-
Notifications
You must be signed in to change notification settings - Fork 14.1k
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
Mssql session type #18747
Mssql session type #18747
Conversation
subject(:command_dispatcher) { described_class.new(session.console) } | ||
|
||
it_behaves_like 'session command dispatcher' | ||
end |
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.
Looks like you'll want to set up your text editor to add a new line on save, and I imagine you're missing the option to strip superfluous whitespace too 👀
b3eb6f2
to
554e1d4
Compare
print_line 'Usage: query' | ||
print_line | ||
print_line 'Run a raw SQL query on the target.' | ||
print_line 'Examples:' | ||
print_line | ||
print_line ' query SHOW DATABASES;' | ||
print_line ' query USE information_schema;' | ||
print_line ' query SELECT * FROM SQL_FUNCTIONS;' | ||
print_line ' query SELECT version();' | ||
print_line |
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 is Postgres stuff, should replace with MSSQL commands that do +- same things from this list
554e1d4
to
fd1ed5b
Compare
finished = false | ||
until finished | ||
begin | ||
raw_query = ::Reline.readmultiline('SQL >> ', use_history = true) do |multiline_input| | ||
finished = stop_words.include?(multiline_input.split.last) | ||
!multiline_input.split.last.end_with?('\\') | ||
end | ||
rescue ::Interrupt | ||
finished = true | ||
ensure | ||
::Reline.prompt_proc = prompt_proc_before | ||
end | ||
|
||
if finished | ||
print_status 'Exiting Shell mode.' | ||
return | ||
end |
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.
The way finished
is handled here is a little redundant.
finished = false | ||
until finished | ||
begin | ||
raw_query = ::Reline.readmultiline('SQL >> ', use_history = true) do |multiline_input| |
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.
We may want to look into using the existing history manager to store the SQL session commands.
0c65b9e
to
dc6dbfc
Compare
@@ -35,14 +36,30 @@ def initialize | |||
OptBool.new('TDSENCRYPTION', [ true, 'Use TLS/SSL for TDS data "Force Encryption"', true]), | |||
]) | |||
|
|||
deregister_options('PASSWORD_SPRAY') | |||
options_to_deregister = %w[PASSWORD_SPRAY] | |||
unless framework.features.enabled?(Msf::FeatureManager::MSSQL_SESSION_TYPE) |
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.
We're adding in notification messages here now to let users know that the functionality exists, i.e. here's the postgres module code
options_to_deregister = %w[SQL PASSWORD_SPRAY]
if framework.features.enabled?(Msf::FeatureManager::POSTGRESQL_SESSION_TYPE)
add_info('New in Metasploit 6.4 - The %grnCreateSession%clr option within this module can open an interactive session')
else
options_to_deregister << 'CreateSession'
end
deregister_options(*options_to_deregister)
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.
Looks like this is still needing to be applied 👀
Login ScannerWrong Portmsf6 auxiliary(scanner/mssql/mssql_login) > run rport=9001
[*] 192.168.112.3:9001 - 192.168.112.3:9001 - MSSQL - Starting authentication scanner.
[-] 192.168.112.3:9001 - 192.168.112.3:9001 - LOGIN FAILED: WORKSTATION\mssql-user:mssql-password1 (Unable to Connect: The connection with (192.168.112.3:9001) timed out.)
[-] 192.168.112.3:9001 - 192.168.112.3:9001 - LOGIN FAILED: WORKSTATION\mssql-user: (Unable to Connect: The connection with (192.168.112.3:9001) timed out.)
[*] 192.168.112.3:9001 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed TDS Encryption On[*] 192.168.112.3:1433 - 192.168.112.3:1433 - MSSQL - Starting authentication scanner.
[-] 192.168.112.3:1433 - Auxiliary failed: RuntimeError Cannot create sessions when encryption is enabled. See https://github.com/rapid7/metasploit-framework/issues/18745 to vote for this feature
[-] 192.168.112.3:1433 - Call stack:
[-] 192.168.112.3:1433 - /Users/sjanusz/Programming/metasploit-framework/modules/auxiliary/scanner/mssql/mssql_login.rb:59:in `run_host'
[-] 192.168.112.3:1433 - /Users/sjanusz/Programming/metasploit-framework/lib/msf/core/auxiliary/scanner.rb:128:in `block (2 levels) in run'
[-] 192.168.112.3:1433 - /Users/sjanusz/Programming/metasploit-framework/lib/msf/core/thread_manager.rb:105:in `block in spawn'
[*] Auxiliary module execution completed TDS Encryption Off & Wrong UsernameThis seems to be missing an error message? msf6 auxiliary(scanner/mssql/mssql_login) > run rhost=192.168.112.3 rport=1433 stop_on_success=true username=mssql-user1 password=mssql-password1 tdsencryption=false
[*] 192.168.112.3:1433 - 192.168.112.3:1433 - MSSQL - Starting authentication scanner.
[-] 192.168.112.3:1433 - 192.168.112.3:1433 - LOGIN FAILED: WORKSTATION\mssql-user1:mssql-password1 (Incorrect: )
[-] 192.168.112.3:1433 - 192.168.112.3:1433 - LOGIN FAILED: WORKSTATION\mssql-user1: (Incorrect: )
[*] 192.168.112.3:1433 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed TDS Encryption Off & Wrong PasswordThis seems to be missing an error message? msf6 auxiliary(scanner/mssql/mssql_login) > run rhost=192.168.112.3 rport=1433 stop_on_success=true username=mssql-user password=wrong-password tdsencryption=false
[*] 192.168.112.3:1433 - 192.168.112.3:1433 - MSSQL - Starting authentication scanner.
[-] 192.168.112.3:1433 - 192.168.112.3:1433 - LOGIN FAILED: WORKSTATION\mssql-user:wrong-password (Incorrect: )
[-] 192.168.112.3:1433 - 192.168.112.3:1433 - LOGIN FAILED: WORKSTATION\mssql-user: (Incorrect: )
[*] 192.168.112.3:1433 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed TDS Encryption Off & Correct Detailsmsf6 auxiliary(scanner/mssql/mssql_login) > run rhost=192.168.112.3 rport=1433 stop_on_success=true username=mssql-user password=mssql-password1 tdsencryption=false
[*] 192.168.112.3:1433 - 192.168.112.3:1433 - MSSQL - Starting authentication scanner.
[+] 192.168.112.3:1433 - 192.168.112.3:1433 - Login Successful: WORKSTATION\mssql-user:mssql-password1
[*] MSSQL session 2 opened (192.168.112.1:58465 -> 192.168.112.3:1433) at 2024-02-07 10:13:13 +0000
[*] 192.168.112.3:1433 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed Domain name rather than IP:This gets a session twice (this is an issue with msf6 auxiliary(scanner/mssql/mssql_login) > run rhost=dc1.sj.local rport=1433 stop_on_success=true username=mssql-user password=mssql-password1 tdsencryption=false
[*] 192.168.112.3:1433 - 192.168.112.3:1433 - MSSQL - Starting authentication scanner.
[+] 192.168.112.3:1433 - 192.168.112.3:1433 - Login Successful: WORKSTATION\mssql-user:mssql-password1
[*] MSSQL session 7 opened (192.168.112.1:58802 -> 192.168.112.3:1433) at 2024-02-07 10:45:11 +0000
[*] dc1.sj.local:1433 - Scanned 1 of 2 hosts (50% complete)
[*] 192.168.112.3:1433 - 192.168.112.3:1433 - MSSQL - Starting authentication scanner.
[+] 192.168.112.3:1433 - 192.168.112.3:1433 - Login Successful: WORKSTATION\mssql-user:mssql-password1
[*] MSSQL session 8 opened (192.168.112.1:58803 -> 192.168.112.3:1433) at 2024-02-07 10:45:12 +0000
[*] dc1.sj.local:1433 - Scanned 2 of 2 hosts (100% complete)
[*] Auxiliary module execution completed URI:msf6 auxiliary(scanner/mssql/mssql_login) > run mysql://mssql-user:mssql-password1@192.168.112.3:1433
[*] 192.168.112.3:1433 - 192.168.112.3:1433 - MSSQL - Starting authentication scanner.
[+] 192.168.112.3:1433 - 192.168.112.3:1433 - Login Successful: WORKSTATION\mssql-user:mssql-password1
[*] MSSQL session 6 opened (192.168.112.1:61069 -> 192.168.112.3:1433) at 2024-02-07 15:14:09 +0000
[*] mysql://mssql-user:mssql-password1@192.168.112.3:1433:1433 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed QueriesWhen executing queries, there seems to be a few extra lines of blank space:
|
dc6dbfc
to
a56a0a7
Compare
@@ -47,6 +47,8 @@ class MSSQL | |||
# @return [Boolean] Whether to use Windows Authentication instead of SQL Server Auth. | |||
attr_accessor :windows_authentication | |||
|
|||
attr_accessor :use_client_as_proof |
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.
Can we make sure we've added all of the yard doc types here - and other places:
# @returns [Boolean] If a login is successful and this attribute is true - a PostgreSQL::Client instance is used as proof, | |
# and the socket is not immediately closed | |
attr_accessor :use_client_as_proof |
c37a7ca
to
fce9420
Compare
The commit history is a bit strange - it looks like the first commit has merge conflicts present. Might be good to squash into the one commit and ensure you're rebased against the latest master code - let me know if I've misunderstood anything though 👍 |
7181765
to
865220c
Compare
def session_setup(result, client) | ||
return unless (result && client) | ||
rstream = client.sock | ||
my_session = Msf::Sessions::MSSQL.new(rstream, { client: client }) # is cwd right? |
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.
Simon will align the other clients not to use cwd
as a convention, but database_name
or something else 😄
lib/msf/base/sessions/mssql.rb
Outdated
def rhost | ||
self.address | ||
end | ||
|
||
def rport | ||
self.port | ||
end |
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 did we need to redefine this here? 👀
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 was per a conversation with @dwelch-r7 where we talked about ripping the rhost/rport accessors from lib/msf/core/post/common.rb
and putting them directly in the session.
Tagging to correct me if I misunderstood the context
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.
yea I think something got lost in translation somewhere along the line, it seems like these aren't being referenced anywhere either?
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.
Looks like it's good to remove this then 🙌
@@ -114,7 +114,7 @@ def report_hashes(mssql_hashes, version_year) | |||
|
|||
service_data = { | |||
address: ::Rex::Socket.getaddress(rhost,true), | |||
port: rport, | |||
port: datastore['RPORT'], |
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 has snuck in here accidentally, it looks like a rebase issue maybe?
Reminds me of this thread: #18696 (comment)
lib/msf/core/optional_session.rb
Outdated
[ | ||
Msf::OptInt.new('SESSION', [ false, 'The session to run this module on' ]), | ||
Msf::OptString.new('DATABASE', [ false, 'The database to authenticate against', 'MSSQL']), | ||
Msf::OptString.new('USERNAME', [ false, 'The username to authenticate as', 'MSSQL']), | ||
Msf::Opt::RHOST(nil, false), | ||
Msf::Opt::RPORT(nil, 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.
Msf::Opt::RPORT(nil, false) | |
Msf::Opt::RPORT(1433, false) |
# The mssql client context | ||
self.session = session | ||
self.client = session.client | ||
self.cwd = session.client.mssql_query('SELECT DB_NAME();')[:rows][0][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.
Not a blocker; Looks like this information is already given to us during the login negotiation process via wireshark:
And reading the spec:
The type of environment change:
1: Database
https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/2b3eb7e5-d43d-4d1b-bf4d-76b9e3afc791
So to do this without an extra query, all we'd need to do is something similar to using the info that we parse here:
From: /Users/user/Documents/code/metasploit-framework/lib/rex/proto/mssql/client.rb:414 Rex::Proto::MSSQL::Client#mssql_login:
409:
410: info = {:errors => []}
411: info = mssql_parse_reply(resp, info)
412:
413: require 'pry-byebug'; binding.pry
=> 414: return false if not info
415: info[:login_ack] ? true : false
416: end
417:
418: #
419: #this method send a prelogin packet and check if encryption is off
[1] pry(#<Rex::Proto::MSSQL::Client>)> info
=> {:errors=>[],
:envs=>
[{:type=>1, :old=>"master", :new=>"master"},
{:type=>7, :old=>"", :new=>"\t\x04\xD04"},
{:type=>2, :old=>"", :new=>"us_english"},
{:type=>4, :old=>"4096", :new=>"4096"}],
:infos=>
["SQL Server Info #5701 (State:2 Severity:0): Changed database context to 'master'.",
"SQL Server Info #5703 (State:1 Severity:0): Changed language setting to us_english."],
:login_ack=>true,
:done=>{:status=>0, :cmd=>0, :rows=>0}}
[2] pry(#<Rex::Proto::MSSQL::Client>)>
And pull out the database type using the type=>1
reference from the docs:
[{:type=>1, :old=>"master", :new=>"master"},
And expose it on the mssql client instance for future users
print_line 'Usage: shell' | ||
print_line | ||
print_line 'Go into a raw SQL shell where SQL queries can be executed.' | ||
print_line 'To exit, type `exit`, `quit`, `end` or `stop`.' |
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.
Not a blocker since it's from the other pull requests; but we generally don't use back ticks in prompt outputs
|
||
alias cmd_sql cmd_query | ||
alias cmd_sql_help cmd_query_help |
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.
alias cmd_sql cmd_query | |
alias cmd_sql_help cmd_query_help |
lib/rex/proto/mssql/client.rb
Outdated
@@ -27,6 +27,7 @@ class Client | |||
attr_accessor :ssl_cipher | |||
attr_accessor :proxies | |||
attr_accessor :connection_timeout | |||
attr_accessor :realm |
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.
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.
Forgot to rip it out, was using this (incorrectly) for cwd
lib/rex/proto/mssql/client_mixin.rb
Outdated
@@ -58,7 +58,7 @@ def mssql_print_reply(info) | |||
tbl << row | |||
end | |||
|
|||
print_line(tbl.to_s) | |||
print_line(tbl.to_s.gsub("\n\n\n","\n")) |
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 looks like a hack; It looks like the extra whitespace is caused by the Header being blank
tbl = Rex::Text::Table.new(
'Indent' => 1,
- 'Header' => "",
+ 'Header' => "Response",
'Columns' => info[:colnames],
'SortIndex' => -1
)
Which would give a cleaner output without the whitespace that I think you were trying to remove
[*] 192.168.123.136:1433 - SQL Query: select @@version;
[*] 192.168.123.136:1433 - Row Count: 1 (Status: 16 Command: 193)
Response
========
NULL
----
Microsoft SQL Server 2022 (RTM) - 16.0.1000.6 (X64)
Oct 8 2022 05:58:25
Copyright (C) 2022 Microsoft Corporation
Express Edition (64-bit) on Windows Server 2022 Standard Evaluation 10.0 <X64> (Build 20348: ) (Hypervisor)
@@ -24,6 +24,7 @@ def initialize(info = {}) | |||
def run | |||
# Check connection and issue initial query | |||
print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...") | |||
|
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'm guessing this left over from a rebase; we should be good to revert this change 👍
@@ -24,6 +24,7 @@ def initialize(info = {}) | |||
def run | |||
# Check connection and issue initial query | |||
print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...") | |||
|
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'm guessing this left over from a rebase; we should be good to revert this change 👍
if create_session? | ||
raise "Cannot create sessions when encryption is enabled. See https://github.com/rapid7/metasploit-framework/issues/18745 to vote for this feature" | ||
else | ||
print_status("Manually enabled TLS/SSL to encrypt TDS payloads.") |
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.
print_status("Manually enabled TLS/SSL to encrypt TDS payloads.") | |
print_status("TDS Encryption enabled") |
end | ||
|
||
def run_host(ip) | ||
print_status("#{rhost}:#{rport} - MSSQL - Starting authentication scanner.") | ||
|
||
if datastore['TDSENCRYPTION'] | ||
print_status("Manually enabled TLS/SSL to encrypt TDS payloads.") | ||
if create_session? | ||
raise "Cannot create sessions when encryption is enabled. See https://github.com/rapid7/metasploit-framework/issues/18745 to vote for this feature" |
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.
raise "Cannot create sessions when encryption is enabled. See https://github.com/rapid7/metasploit-framework/issues/18745 to vote for this feature" | |
raise Msf::OptionValidateError.new( | |
{ | |
'TDSENCRYPTION' => "Cannot create sessions when encryption is enabled. See https://github.com/rapid7/metasploit-framework/issues/18745 to vote for this feature" | |
} | |
) |
Before
Cryptic stacktrace:
msf6 auxiliary(scanner/mssql/mssql_login) > run 192.168.123.136 username=admin password=p4$$w0rd tdsencryption=true createsession=true
[*] 192.168.123.136:1433 - 192.168.123.136:1433 - MSSQL - Starting authentication scanner.
[-] 192.168.123.136:1433 - Auxiliary failed: RuntimeError Cannot create sessions when encryption is enabled. See https://github.com/rapid7/metasploit-framework/issues/18745 to vote for this feature
[-] 192.168.123.136:1433 - Call stack:
[-] 192.168.123.136:1433 - /Users/user/Documents/code/metasploit-framework/modules/auxiliary/scanner/mssql/mssql_login.rb:61:in `run_host'
[-] 192.168.123.136:1433 - /Users/user/Documents/code/metasploit-framework/lib/msf/core/auxiliary/scanner.rb:128:in `block (2 levels) in run'
[-] 192.168.123.136:1433 - /Users/user/Documents/code/metasploit-framework/lib/msf/core/thread_manager.rb:105:in `block in spawn'
[*] Auxiliary module execution completed
After
Cleaner UI that aligns with other module validation
msf6 auxiliary(scanner/mssql/mssql_login) > reload
[*] Reloading module...
[*] New in Metasploit 6.4 - The CreateSession option within this module can open an interactive session
msf6 auxiliary(scanner/mssql/mssql_login) > run 192.168.123.136 username=admin password=p4$$w0rd tdsencryption=true createsession=true
[*] 192.168.123.136:1433 - 192.168.123.136:1433 - MSSQL - Starting authentication scanner.
[-] 192.168.123.136:1433 - Msf::OptionValidateError The following options failed to validate:
[-] 192.168.123.136:1433 - Invalid option TDSENCRYPTION: Cannot create sessions when encryption is enabled. See https://github.com/rapid7/metasploit-framework/issues/18745 to vote for this feature
[*] Auxiliary module execution completed
msf6 auxiliary(scanner/mssql/mssql_login) >
if use_client_as_proof | ||
result_options[:proof] = client | ||
else | ||
client.disconnect # replacing the ensure so the client doesn't disconnect on login - is this right? |
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.
client.disconnect # replacing the ensure so the client doesn't disconnect on login - is this right? | |
client.disconnect |
Looks good 👍
f808d04
to
4756e65
Compare
4756e65
to
2c60780
Compare
Release NotesUpdates the |
This PR takes the existing MSSQL Client work and adds the session type on top of it.
Verification
List the steps needed to make sure this thing works
./msfconsole -q
features set mssql_session_type true
save
exit
./msfconsole -q
use mssql_login
set CreateSession true
run
sessions -i -1
query 'YOUR_QUERY_HERE'
and verify resultsExample interaction: