New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Convert MSSQL mixin to class #18696
Convert MSSQL mixin to class #18696
Conversation
b548572
to
e443438
Compare
11a20f6
to
6d4edb4
Compare
6d4edb4
to
9fa145e
Compare
modules/exploits/windows/mssql/ms09_004_sp_replwritetovarbin.rb
Outdated
Show resolved
Hide resolved
164a28e
to
448725f
Compare
@@ -93,7 +93,7 @@ def connect(global = true, opts={}) | |||
'SSLCipher' => opts['SSLCipher'] || ssl_cipher, | |||
'Proxies' => proxies, | |||
'Timeout' => (opts['ConnectTimeout'] || connection_timeout || 10).to_i, | |||
'Context' => { 'Msf' => framework, 'MsfExploit' => framework_module } | |||
'Context' => { 'Msf' => framework, 'MsfExploit' => self } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there any context on this change? 👀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me revert and re-test and get back to you, this might be fine to revert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume it was fine to revert? 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You got it!
@@ -70,7 +70,7 @@ def run_host(ip) | |||
create_credential_login(login_data) | |||
|
|||
# Grabs the Instance Name and Version of MSSQL(2k,2k5,2k8) | |||
instancename= mssql_query(mssql_enumerate_servername())[:rows][0][0].split('\\')[1] | |||
instancename= mssql_query(mssql_enumerate_servername())[:rows][0][0].split('\\')[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, it looks like this [1]
was intentionally added previously:
I wonder if whatever your current string returns needed to be handled, as well as whatever value was previously expected?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting - IIRC the [1]
was returning NULL at times even in master with [0]
having the data we were looking for, I'll verify whether this is the right change or something I need to adjust elsewhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
running this on both my branch and master, mssql_query(mssql_enumerate_servername())[:rows][0][0].split('\\')
returns ["WIN-F0OBFMVGB07"]
- so the result of running this with [1]
gives us [*] 192.168.2.212:1433 - Instance Name: nil
on the output. Maybe I've got something configured wrong, but either way it seems like this should be tweaked to either [0] or there's some sort of logic we need to wrap this in
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if the behaviour should be preferencing second part, and if it's not there - fallback to the using the first part? 🤔 Worth a check 👍
)) | ||
)) | ||
register_options([ | ||
OptBool.new('DISPLAY_RESULTS', [true, "Display the Results to the Screen", true]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was this change needed? 👀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this (and the above) snuck in during a merge, I'll see if I can nuke
33918be
to
6d47fb8
Compare
Looks like this breaks kerberos auth:
Stack trace:
|
It looks like this is leaking file descriptors/not closing sockets. You can verify this with Run the mssql query module multiple times:
See that the sockets are not closed and are leaking:
But if we compare to master, there's no leaks |
Test RC file I was running with
|
attr_accessor :use_ntlmv2 | ||
attr_accessor :windows_authentication | ||
attr_reader :framework_module | ||
attr_reader :framework |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what uses this framework
attribute? strikes me as a little odd for a client of any kind to require a framework object
potentially the same question for framework_module
I know it's being used to pull stuff out of the datastore, but is the object itself needed and/or can we just pass an opts hash instead?
asking out of curiosity more than anything else, not a blocker
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Primarily, both of these get used in mssql_login
- open to alternative implementations though!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where in mssql_login? I can't see it being accessed through the client, the mssql_login module provides the scanner with the framework and framework_module though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry - the mssql_login
method in lib/rex/proto/mssql/client.rb
. The two main cases are:
framework_module.fail_with(Msf::Exploit::Failure::BadConfig, 'The Mssql::Rhostname option is required when using kerberos authentication.') if @hostname.blank?
kerberos_authenticator = Msf::Exploit::Remote::Kerberos::ServiceAuthenticator::MSSQL.new(
host: domain_controller_rhost,
hostname: @hostname,
mssql_port: rport,
proxies: proxies,
realm: domain_name,
username: user,
password: pass,
framework: framework,
framework_module: framework_module,
ticket_storage: Msf::Exploit::Remote::Kerberos::Ticket::Storage::WriteOnly.new(framework: framework, framework_module: framework_module)
)
and in using print_status
/print_error
Should I investigate a way around it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah I see it now, I didn't realise it was in code you didn't change
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('TDSENCRYPTION', [ true, 'Use TLS/SSL for TDS data "Force Encryption"', false]), | ||
OptBool.new('USE_WINDOWS_AUTHENT', [ true, 'Use windows authentication (requires DOMAIN option set)', false]), | ||
]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change doesn't seem right, shouldn't there be a mixin pulling these in (or at least the common ones like RHOST and RPORT) for the mssql modules?
Similar to the smb_login module here still includes a mixin registering these options but makes use of an SMB client too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this module runs differently since it's coming from the login_scanner rather than the client directly, but I'll investigate pulling this out, that's definitely the cleaner approach
instancename = mssql_query(mssql_enumerate_servername())[:rows][0][0].split('\\')[1] | ||
instancename = mssql_query(mssql_enumerate_servername())[:rows][0][0].split('\\')[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this a bug you found/fixed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe so - see #18696 (comment)
24ebf3e
to
559d48b
Compare
validates :tdsencryption, | ||
inclusion: { in: [true, false] } | ||
# validates :tdsencryption, - TODO: support TDS Encryption | ||
# inclusion: { in: [true, false] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It smells like this is fixing a side effect rather than the underlying issue
i.e. Does the caller need fixed, rather than this validation being removed?
lib/msf/core/exploit/remote/mssql.rb
Outdated
@@ -104,622 +99,140 @@ def mssql_ping_parse(data) | |||
return res | |||
end | |||
|
|||
def disconnect |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will break any other disconnect
implementations inherited from a super class. To avoid doing that bug, we should be calling super
here when using mixins like this.
To take a step back though, I believe the real issue is you're not registering the sock
with the framework module for it to be automatically cleaned up here:
Main branch:
msf6 auxiliary(admin/mssql/mssql_sql) > run 192.168.123.132 domaincontrollerrhost=192.168.123.132 username=vagrant password=vagrant mssql::auth=kerberos mssql::rhostname=dc01.demo.local mssqldomain=demo.local sql='select auth_scheme from sys.dm_exec_connections where session_id=@@spid'
[*] Running module against 192.168.123.132
From: /Users/adfoster/Documents/code/metasploit-framework/lib/msf/core/auxiliary.rb:135 Msf::Auxiliary#add_socket:
133: def add_socket(sock)
134: require 'pry-byebug'; binding.pry
=> 135: self.sockets << sock
136: end
[1] pry(#<Msf::Modules::Auxiliary__Admin__Mssql__Mssql_sql::MetasploitModule>)> sock
=> #<Socket:fd 15>
[2] pry(#<Msf::Modules::Auxiliary__Admin__Mssql__Mssql_sql::MetasploitModule>)>
If we followed the existing pattern of registering the socket, we wouldn't need this custom disconnect method here - or I believe you could register the socket still, ensure you call super here, and ensure you've got a nil check with @client.disconnect if @client
Looks like Kerberos is still broken even after the kerberos fixes commit 👀
And the crash in other modules:
|
62766f8
to
0011b4a
Compare
convert first module from remote to client move client to rex remove metasploit mixin
0011b4a
to
35778e9
Compare
Release NotesIntroduces a standalone MSSQL client class that can be used in new contexts not tied to a specific module |
This continues the work started in #18615
Before adding an MSSQL session type, we need a standalone client class, in addition to a mixin. This PR consolidates the two instances of MSSQL client classes, consolidates them, and converts the consolidated mixin into a class that all existing MSSQL modules have been tweaked to work with.
To test:
rhost
to the target's ip,rport
to the port MSSQL is running on (usually 1433),username
,password
, and any other required options.