Skip to content

Commit

Permalink
refactor packet parsing code
Browse files Browse the repository at this point in the history
  • Loading branch information
zgoldman-r7 committed Mar 5, 2024
1 parent 93e8f87 commit 8a6f229
Show file tree
Hide file tree
Showing 15 changed files with 64 additions and 103 deletions.
11 changes: 8 additions & 3 deletions lib/msf/core/exploit/remote/mssql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ module Exploit::Remote::MSSQL

attr_accessor :mssql_client

ENCRYPT_OFF = 0x00 #Encryption is available but off.
ENCRYPT_ON = 0x01 #Encryption is available and on.
ENCRYPT_NOT_SUP = 0x02 #Encryption is not available.
ENCRYPT_REQ = 0x03 #Encryption is required.

#
# Creates an instance of a MSSQL exploit module.
#
Expand Down Expand Up @@ -48,15 +53,15 @@ def initialize(info = {})
register_autofilter_services(%W{ ms-sql-s ms-sql2000 sybase })
end

def set_session(client)
def set_mssql_session(client)
print_status("Using existing session #{session.sid}")
@mssql_client = client
end

def mssql_get_version
def create_mssql_client
@mssql_client ||= Rex::Proto::MSSQL::Client.new(self, framework, datastore['RHOST'], datastore['RPORT'])
@mssql_client.mssql_get_version
end

#
# This method sends a UDP query packet to the server and
# parses out the reply packet into a hash
Expand Down
44 changes: 11 additions & 33 deletions lib/rex/proto/mssql/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,6 @@ def initialize(framework_module, framework, rhost, rport = 1433, proxies = nil)
#

def mssql_login(user='sa', pass='', db='', domain_name='')
disconnect if self.sock
connect
mssql_prelogin

if auth == Msf::Exploit::Remote::AuthOption::KERBEROS
Expand Down Expand Up @@ -422,28 +420,20 @@ def mssql_login(user='sa', pass='', db='', domain_name='')
#this method send a prelogin packet and check if encryption is off
#
def mssql_prelogin(enc_error=false)
disconnect if self.sock
connect

pkt = mssql_prelogin_packet

resp = mssql_send_recv(pkt)

idx = 0
data = parse_prelogin_response(resp)

while resp && resp[0, 1] != "\xff" && resp.length > 5
token = resp.slice!(0, 5)
token = token.unpack("Cnn")
idx -= 5
if token[0] == 0x01

idx += token[1]
break
end
end
if idx > 0
encryption_mode = resp[idx, 1].unpack("C")[0]
else
unless data['Encryption']
framework_module.print_error("Unable to parse encryption req " \
"during pre-login, this may not be a MSSQL server")
encryption_mode = ENCRYPT_NOT_SUP
data['Encryption'] = ENCRYPT_NOT_SUP
end

##########################################################
Expand All @@ -461,7 +451,7 @@ def mssql_prelogin(enc_error=false)
#
##########################################################

if encryption_mode == ENCRYPT_REQ
if data['Encryption'] == ENCRYPT_REQ
# restart prelogin process except that we tell SQL Server
# than we are now able to encrypt
disconnect if self.sock
Expand All @@ -474,27 +464,15 @@ def mssql_prelogin(enc_error=false)
"been enabled based on server response.")

resp = mssql_send_recv(pkt)
data = parse_prelogin_response(resp)

idx = 0

while resp && resp[0, 1] != "\xff" && resp.length > 5
token = resp.slice!(0, 5)
token = token.unpack("Cnn")
idx -= 5
if token[0] == 0x01
idx += token[1]
break
end
end
if idx > 0
encryption_mode = resp[idx, 1].unpack("C")[0]
else
unless data['Encryption']
framework_module.print_error("Unable to parse encryption req " \
"during pre-login, this may not be a MSSQL server")
encryption_mode = ENCRYPT_NOT_SUP
data['Encryption'] = ENCRYPT_NOT_SUP
end
end
encryption_mode
data
end

def mssql_ssl_send_recv(req, tdsproxy, timeout=15, check_status=true)
Expand Down
51 changes: 12 additions & 39 deletions lib/rex/proto/mssql/client_mixin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,54 +148,27 @@ def mssql_prelogin_packet
pkt
end

def mssql_get_version
disconnect if self.sock
connect

pkt = mssql_prelogin_packet
def parse_prelogin_response(resp)
data = {}
if resp.length > 5 # minimum size for response specification
version_index = resp.slice(1, 2).unpack('n')[0]

resp = mssql_send_recv(pkt)
return unless resp
major = resp.slice(version_index, 1).unpack('C')[0]
minor = resp.slice(version_index+1, 1).unpack('C')[0]
build = resp.slice(version_index+2, 2).unpack('n')[0]

data = {}
while resp
token = resp.slice!(0, 1)
if token.unpack('C')[0] == 255
major = resp.slice!(0, 1).unpack('C')[0]
minor = resp.slice!(0, 1).unpack('C')[0]
build = resp.slice!(0, 2).unpack('n')[0]
break
end
enc_index = resp.slice(6, 2).unpack('n')[0]
data['Encryption'] = resp.slice(enc_index, 1).unpack('C')[0]
end

if major && minor && build
build = "#{major}.#{minor}.#{build}"
end
if resp
resp.slice!(0,2)
enc = resp.slice!(0,1).unpack('C')[0]
case enc
when ENCRYPT_OFF
enc_value = 'off'
when ENCRYPT_ON
enc_value = 'on'
when ENCRYPT_NOT_SUP
enc_value = 'unsupported'
when ENCRYPT_REQ
enc_value = 'required'
end
data['Version'] = "#{major}.#{minor}.#{build}"
end

if build
data['Version'] = build
end

if enc_value
data['Encryption'] = enc_value
end
data['Status'] = 'open'
return data
data['Status'] = 'open' if data['Version'] || data['Encryption']

return data
end

def mssql_send_recv(req, timeout=15, check_status = true)
Expand Down
2 changes: 1 addition & 1 deletion modules/auxiliary/admin/mssql/mssql_enum.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ module to work, valid administrative user credentials must be
def run
print_status("Running MS SQL Server Enumeration...")
if session
set_session(session.client)
set_mssql_session(session.client)
else
unless mssql_login_datastore
print_error("Login was unsuccessful. Check your credentials.")
Expand Down
2 changes: 1 addition & 1 deletion modules/auxiliary/admin/mssql/mssql_escalate_dbowner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def initialize(info = {})
def run
# Check connection and issue initial query
if session
set_session(session.client)
set_mssql_session(session.client)
else
print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...")
if mssql_login_datastore
Expand Down
2 changes: 1 addition & 1 deletion modules/auxiliary/admin/mssql/mssql_escalate_execute_as.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def initialize(info = {})

def run
if session
set_session(session.client)
set_mssql_session(session.client)
else
print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...")
if mssql_login_datastore
Expand Down
2 changes: 1 addition & 1 deletion modules/auxiliary/admin/mssql/mssql_exec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def initialize(info = {})

def run
if session
set_session(session.client)
set_mssql_session(session.client)
else
return unless mssql_login_datastore
end
Expand Down
2 changes: 1 addition & 1 deletion modules/auxiliary/admin/mssql/mssql_findandsampledata.rb
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ def sql_statement()
# CREATE DATABASE CONNECTION AND SUBMIT QUERY WITH ERROR HANDLING
begin
if session
set_session(session.client)
set_mssql_session(session.client)
else
print_line(" ")
print_status("Attempting to connect to the SQL Server at #{rhost}:#{rport}...")
Expand Down
2 changes: 1 addition & 1 deletion modules/auxiliary/admin/mssql/mssql_idf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def run

begin
if session
set_session(session.client)
set_mssql_session(session.client)
else
unless mssql_login_datastore
print_error('Login failed')
Expand Down
2 changes: 1 addition & 1 deletion modules/auxiliary/admin/mssql/mssql_sql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def cmd_select(*args)

def run
if session
set_session(session.client)
set_mssql_session(session.client)
else
return unless mssql_login_datastore
end
Expand Down
2 changes: 1 addition & 1 deletion modules/auxiliary/admin/mssql/mssql_sql_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def run

begin
if session
set_session(session.client)
set_mssql_session(session.client)
else
unless mssql_login_datastore
print_error("#{datastore['RHOST']}:#{datastore['RPORT']} - Invalid SQL Server credentials")
Expand Down
2 changes: 1 addition & 1 deletion modules/auxiliary/scanner/mssql/mssql_hashdump.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def initialize

def run_host(ip)
if session
set_session(session.client)
set_mssql_session(session.client)
elsif !mssql_login(datastore['USERNAME'], datastore['PASSWORD'])
print_error('Invalid SQL Server credentials')
return
Expand Down
2 changes: 1 addition & 1 deletion modules/auxiliary/scanner/mssql/mssql_schemadump.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def initialize

def run_host(ip)
if session
set_session(session.client)
set_mssql_session(session.client)
else
unless mssql_login_datastore
print_error("#{datastore['RHOST']}:#{datastore['RPORT']} - Invalid SQL Server credentials")
Expand Down
23 changes: 19 additions & 4 deletions modules/auxiliary/scanner/mssql/mssql_version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,37 @@ def initialize

def run
if session
set_session(session.client)
set_mssql_session(session.client)
else
create_mssql_client
end

data = mssql_get_version
data = mssql_prelogin

if data.nil? || data.empty?
print_error("Unable to retrieve version information for #{mssql_client.address}")
return
end

print_status("SQL Server for #{mssql_client.address}:")
if data['Version'] && !data['Version'].empty?
if data['Version']
print_good("Version: #{data['Version']}")
else
print_error('Unknown Version')
end
if data['Encryption'] && !data['Encryption'].empty?
if data['Encryption']
case data['Encryption']
when ENCRYPT_OFF
data['Encryption'] = 'off'
when ENCRYPT_ON
data['Encryption'] = 'on'
when ENCRYPT_NOT_SUP
data['Encryption'] = 'unsupported'
when ENCRYPT_REQ
data['Encryption'] = 'required'
else
data['Encryption'] = 'unknown'
end
print_good("Encryption is #{data['Encryption']}")
else
print_error('Unknown encryption status')
Expand Down
18 changes: 4 additions & 14 deletions modules/exploits/windows/mssql/mssql_payload.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,7 @@ def initialize(info = {})

def check
if session
set_session(session.client)
end

unless session || mssql_login_datastore
vprint_status("Invalid SQL Server credentials")
return Exploit::CheckCode::Detected
end

if session
set_session(session.client)
set_mssql_session(session.client)
else
unless mssql_login_datastore
vprint_status("Invalid SQL Server credentials")
Expand All @@ -106,10 +97,9 @@ def execute_command(cmd, opts)
def exploit

if session
set_session(session.client)
end

unless session || mssql_login_datastore
set_mssql_session(session.client)
else
unless mssql_login_datastore
print_status("Invalid SQL Server credentials")
return
end
Expand Down

0 comments on commit 8a6f229

Please sign in to comment.