231 lines
6.1 KiB
Ruby
231 lines
6.1 KiB
Ruby
# -*- coding: binary -*-
|
|
|
|
require 'rex/proto/mssql/client'
|
|
require 'metasploit/framework/tcp/client'
|
|
|
|
module Msf
|
|
###
|
|
#
|
|
# This module exposes methods for querying a remote MSSQL service
|
|
#
|
|
###
|
|
module Exploit::Remote::MSSQL
|
|
include Exploit::Remote::MSSQL_COMMANDS
|
|
include Exploit::Remote::Udp
|
|
include Exploit::Remote::Tcp
|
|
include Exploit::Remote::NTLM::Client
|
|
include Msf::Exploit::Remote::Kerberos::Ticket::Storage
|
|
include Msf::Exploit::Remote::Kerberos::ServiceAuthenticator::Options
|
|
|
|
attr_accessor :mssql_client
|
|
|
|
#
|
|
# Creates an instance of a MSSQL exploit module.
|
|
#
|
|
def initialize(info = {})
|
|
super
|
|
|
|
# Register the options that all MSSQL exploits may make use of.
|
|
register_options(
|
|
[
|
|
Opt::RHOST,
|
|
Opt::RPORT(1433),
|
|
OptString.new('USERNAME', [ false, 'The username to authenticate as', 'sa']),
|
|
OptString.new('PASSWORD', [ false, 'The password for the specified username', '']),
|
|
OptBool.new('USE_WINDOWS_AUTHENT', [ true, 'Use windows authentication (requires DOMAIN option set)', false]),
|
|
# OptBool.new('TDSENCRYPTION', [ true, 'Use TLS/SSL for TDS data "Force Encryption"', false]), - TODO: support TDS Encryption
|
|
], Msf::Exploit::Remote::MSSQL)
|
|
register_advanced_options(
|
|
[
|
|
OptPath.new('HEX2BINARY', [ false, "The path to the hex2binary script on the disk",
|
|
File.join(Msf::Config.data_directory, "exploits", "mssql", "h2b")
|
|
]),
|
|
OptString.new('DOMAIN', [ true, 'The domain to use for windows authentication', 'WORKSTATION'], aliases: ['MssqlDomain']),
|
|
*kerberos_storage_options(protocol: 'Mssql'),
|
|
*kerberos_auth_options(protocol: 'Mssql', auth_methods: Msf::Exploit::Remote::AuthOption::MSSQL_OPTIONS),
|
|
], Msf::Exploit::Remote::MSSQL)
|
|
register_autofilter_ports([ 1433, 1434, 1435, 14330, 2533, 9152, 2638 ])
|
|
register_autofilter_services(%W{ ms-sql-s ms-sql2000 sybase })
|
|
end
|
|
|
|
def set_session(client)
|
|
print_status("Using existing session #{session.sid}")
|
|
@mssql_client = client
|
|
end
|
|
|
|
#
|
|
# This method sends a UDP query packet to the server and
|
|
# parses out the reply packet into a hash
|
|
#
|
|
def mssql_ping(timeout=5)
|
|
data = { }
|
|
|
|
ping_sock = Rex::Socket::Udp.create(
|
|
'PeerHost' => rhost,
|
|
'PeerPort' => 1434,
|
|
'Context' =>
|
|
{
|
|
'Msf' => framework,
|
|
'MsfExploit' => self,
|
|
})
|
|
|
|
ping_sock.put("\x02")
|
|
resp, _saddr, _sport = ping_sock.recvfrom(65535, timeout)
|
|
ping_sock.close
|
|
|
|
return data if not resp
|
|
return data if resp.length == 0
|
|
|
|
return mssql_ping_parse(resp)
|
|
end
|
|
|
|
#
|
|
# Parse a 'ping' response and format as a hash
|
|
#
|
|
def mssql_ping_parse(data)
|
|
res = []
|
|
var = nil
|
|
idx = data.index('ServerName')
|
|
return res if not idx
|
|
sdata = data[idx, (data.length - 1)]
|
|
|
|
instances = sdata.split(';;')
|
|
instances.each do |instance|
|
|
rinst = {}
|
|
instance.split(';').each do |d|
|
|
if (not var)
|
|
var = d
|
|
else
|
|
if (var.length > 0)
|
|
rinst[var] = d
|
|
var = nil
|
|
end
|
|
end
|
|
end
|
|
res << rinst
|
|
end
|
|
|
|
return res
|
|
end
|
|
|
|
#
|
|
# Execute a system command via xp_cmdshell
|
|
#
|
|
def mssql_parse_tds_reply(data, info)
|
|
@mssql_client.mssql_parse_tds_reply(data, info)
|
|
end
|
|
|
|
def mssql_parse_reply(data, info)
|
|
@mssql_client.mssql_parse_reply(data, info)
|
|
end
|
|
|
|
#
|
|
# Parse a single row of a TDS reply
|
|
#
|
|
def mssql_parse_tds_row(data, info)
|
|
@mssql_client.mssql_parse_tds_row(data, info)
|
|
end
|
|
|
|
#
|
|
# Parse a "ret" TDS token
|
|
#
|
|
def mssql_parse_ret(data, info)
|
|
@mssql_client.mssql_parse_ret(data, info)
|
|
end
|
|
|
|
#
|
|
# Parse a "done" TDS token
|
|
#
|
|
def mssql_parse_done(data, info)
|
|
@mssql_client.mssql_parse_done(data, info)
|
|
end
|
|
|
|
#
|
|
# Parse an "error" TDS token
|
|
#
|
|
def mssql_parse_error(data, info)
|
|
@mssql_client.mssql_parse_error(data, info)
|
|
end
|
|
|
|
#
|
|
# Parse an "environment change" TDS token
|
|
#
|
|
def mssql_parse_env(data, info)
|
|
@mssql_client.mssql_parse_env(data, info)
|
|
end
|
|
|
|
#
|
|
# Parse an "information" TDS token
|
|
#
|
|
def mssql_parse_info(data, info)
|
|
@mssql_client.mssql_parse_info(data, info)
|
|
end
|
|
|
|
def mssql_xpcmdshell(cmd, doprint=false, opts={})
|
|
@mssql_client.mssql_xpcmdshell(cmd, doprint, opts)
|
|
end
|
|
|
|
#
|
|
# Upload and execute a Windows binary through MSSQL queries
|
|
#
|
|
def mssql_upload_exec(exe, debug=false)
|
|
@mssql_client.mssql_upload_exec(exe, debug)
|
|
end
|
|
|
|
#
|
|
# Upload and execute a Windows binary through MSSQL queries and Powershell
|
|
#
|
|
def powershell_upload_exec(exe, debug=false)
|
|
@mssql_client.powershell_upload_exec(exe, debug)
|
|
end
|
|
|
|
#
|
|
#this method send a prelogin packet and check if encryption is off
|
|
#
|
|
def mssql_prelogin(enc_error=false)
|
|
@mssql_client.mssql_prelogin(enc_error)
|
|
end
|
|
|
|
#
|
|
# This method connects to the server over TCP and attempts
|
|
# to authenticate with the supplied username and password
|
|
# The global socket is used and left connected after auth
|
|
#
|
|
def mssql_login(user='sa', pass='', db='', domain_name='')
|
|
@mssql_client ||= Rex::Proto::MSSQL::Client.new(self, framework, datastore['RHOST'], datastore['RPORT'])
|
|
result = @mssql_client.mssql_login(user, pass, db, domain_name)
|
|
add_socket(@mssql_client.sock) if @mssql_client.sock && !sockets.include?(@mssql_client.sock)
|
|
result
|
|
end
|
|
|
|
def mssql_login_datastore(db=nil)
|
|
mssql_login(datastore['USERNAME'], datastore['PASSWORD'], db || datastore['DATABASE'] || '', datastore['MssqlDomain'] || '')
|
|
end
|
|
#
|
|
# Issue a SQL query using the TDS protocol
|
|
#
|
|
def mssql_query(sqla, doprint=false, opts={})
|
|
@mssql_client.query(sqla, doprint, opts)
|
|
end
|
|
|
|
#
|
|
# Nicely print the results of a SQL query
|
|
#
|
|
def mssql_print_reply(info)
|
|
@mssql_client.mssql_print_reply(info)
|
|
end
|
|
|
|
def mssql_send_recv(req, timeout=15, check_status = true)
|
|
@mssql_client.mssql_send_recv(req, timeout, check_status)
|
|
end
|
|
|
|
#
|
|
# Encrypt a password according to the TDS protocol (encode)
|
|
#
|
|
def mssql_tds_encrypt(pass)
|
|
# Convert to unicode, swap 4 bits both ways, xor with 0xa5
|
|
Rex::Text.to_unicode(pass).unpack('C*').map {|c| (((c & 0x0f) << 4) + ((c & 0xf0) >> 4)) ^ 0xa5 }.pack("C*")
|
|
end
|
|
end
|
|
end
|