lib/msf/core/exploit/remote/mssql.rb
# -*- 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