Skip to content

Commit b2eeaef

Browse files
committed
Add admin check to smb_login
The attached updates changes smb_login to detect if the newly discovered user is an administrator. It is based on code from Brandon McCann "zeknox" submitted in PR rapid7#1373, the associated changes, and the newer PR rapid7#2656. The changes should correct a few issues with PR rapid7#1373 and rapid7#2656 and address Redmine bug rapid7#8773. Specifically it: - Fixes the admin detection code by using simple.disconnect(<share>) instead of disconnect() - Adds support for detecting if the remote host will allow connects using any domain name when one of the new status codes is returned - Dealt with the issue in PR rapid7#2656 where the username was prefixed with a '\' Verification Be connected to a database Run this against a machine with a known user and admin user See that the admin user is reported correctly See that the non-admin user is reported correctly Check the output of creds Select a target that requires a domain in order to authenticate In the stored credentials, with CHECK_ADMIN enabled, see that the domain name is, in fact, preserved in the reporting To validate that the remote domain ignores domain value use the following command from a windows system: net use \\<hostip>\admin$ /user:<random_value>\<username> <password>
1 parent d4c0d01 commit b2eeaef

File tree

1 file changed

+37
-4
lines changed

1 file changed

+37
-4
lines changed

modules/auxiliary/scanner/smb/smb_login.rb

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ def initialize
3232
'Author' =>
3333
[
3434
'tebo <tebo [at] attackresearch [dot] com>', # Original
35-
'Ben Campbell' # Refactoring
35+
'Ben Campbell', # Refactoring
36+
'Brandon McCann "zeknox" <bmccann [at] accuvant.com>', # admin check
37+
'Tom Sellers <tom <at> fadedcode.net>' # admin check/bug fix
3638
],
3739
'References' =>
3840
[
@@ -69,6 +71,7 @@ def initialize
6971
OptString.new('SMBPass', [ false, "SMB Password" ]),
7072
OptString.new('SMBUser', [ false, "SMB Username" ]),
7173
OptString.new('SMBDomain', [ false, "SMB Domain", '']),
74+
OptBool.new('CHECK_ADMIN', [ false, "Check for Admin rights", false]),
7275
OptBool.new('PRESERVE_DOMAINS', [ false, "Respect a username that contains a domain name.", true]),
7376
OptBool.new('RECORD_GUEST', [ false, "Record guest-privileged random logins to the database", false])
7477
], self.class)
@@ -124,6 +127,27 @@ def check_login_status(domain, user, pass)
124127
# Windows SMB will return an error code during Session Setup, but nix Samba requires a Tree Connect:
125128
simple.connect("\\\\#{datastore['RHOST']}\\IPC$")
126129
status_code = 'STATUS_SUCCESS'
130+
131+
if datastore['CHECK_ADMIN']
132+
status_code = :not_admin
133+
# Drop the existing connection to IPC$ in order to connect to admin$
134+
simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$")
135+
begin
136+
simple.connect("\\\\#{datastore['RHOST']}\\admin$")
137+
status_code = :admin_access
138+
# Restore the orginal connection
139+
simple.disconnect("\\\\#{datastore['RHOST']}\\admin$")
140+
simple.connect("\\\\#{datastore['RHOST']}\\IPC$")
141+
rescue
142+
status_code = :not_admin
143+
ensure
144+
begin
145+
simple.connect("\\\\#{datastore['RHOST']}\\IPC$")
146+
rescue ::Rex::Proto::SMB::Exceptions::NoReply
147+
end
148+
end
149+
end
150+
127151
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
128152
status_code = e.get_error(e.error_code)
129153
rescue ::Rex::Proto::SMB::Exceptions::LoginError => e
@@ -187,7 +211,16 @@ def accepts_bogus_domains?(user, pass, rhost)
187211
end
188212

189213
def valid_credentials?(status)
190-
return (status == "STATUS_SUCCESS" || @correct_credentials_status_codes.include?(status))
214+
215+
case status
216+
when 'STATUS_SUCCESS', :admin_access, :not_admin
217+
return true
218+
when *@correct_credentials_status_codes
219+
return true
220+
else
221+
return false
222+
end
223+
191224
end
192225

193226
def try_user_pass(domain, user, pass)
@@ -214,7 +247,7 @@ def try_user_pass(domain, user, pass)
214247
output_message << " (#{smb_peer_os}) #{user} : #{pass} [#{status}]".gsub('%', '%%')
215248

216249
case status
217-
when 'STATUS_SUCCESS'
250+
when 'STATUS_SUCCESS', :admin_access, :not_admin
218251
# Auth user indicates if the login was as a guest or not
219252
if(simple.client.auth_user)
220253
print_good(output_message % "SUCCESSFUL LOGIN")
@@ -275,7 +308,7 @@ def note_creds(domain,user,pass,reason)
275308
def report_creds(domain,user,pass,active)
276309
login_name = ""
277310

278-
if accepts_bogus_domains?(user,pass,rhost)
311+
if accepts_bogus_domains?(user,pass,rhost) || domain.blank?
279312
login_name = user
280313
else
281314
login_name = "#{domain}\\#{user}"

0 commit comments

Comments
 (0)