Domain enumeration put in own function

The code to enumerate the AD domain is now in its own function

Additionally, a new advanced option has been added which controls
whether or not the domain enumeration will occur so that if it is
not wanted the user can disabled it. By default this is set to
enumerate the AD domain.

If AD_DOMAIN is already specified then this will be used and no
auto enumeration will occur.
bug/bundler_fix
kaospunk 2013-08-22 14:16:00 -04:00
parent 7e0b26e932
commit 7e098e4d6b
1 changed files with 56 additions and 41 deletions

View File

@ -71,6 +71,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", true]),
OptBool.new('SSL', [ true, "Negotiate SSL for outgoing connections", true]) OptBool.new('SSL', [ true, "Negotiate SSL for outgoing connections", true])
], self.class) ], self.class)
@ -84,44 +85,6 @@ class Metasploit3 < Msf::Auxiliary
end end
def run def run
urls = ["aspnet_client",
"Autodiscover",
"ecp",
"EWS",
"Microsoft-Server-ActiveSync",
"OAB",
"PowerShell",
"Rpc"]
domain = nil
begin
urls.each do |url|
res = send_request_cgi({
'encode' => true,
'uri' => "/#{url}",
'method' => 'GET',
'headers' => {"Authorization" => "NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw=="}
}, 25)
if not res
print_error("#{msg} HTTP Connection Error, Aborting")
return :abort
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)
break
end
end
rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT
print_error("#{msg} HTTP Connection Failed, Aborting")
return :abort
end
# Store the original setting # Store the original setting
@blank_passwords_setting = datastore['BLANK_PASSWORDS'] @blank_passwords_setting = datastore['BLANK_PASSWORDS']
@ -153,10 +116,20 @@ 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'].nil? or datastore['AD_DOMAIN'] == ''
if datastore['ENUM_DOMAIN']
domain = get_ad_domain
end
else
domain = datastore['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" => user, "pass"=>pass, "domain" => domain, "auth_path"=>auth_path, "inbox_path"=>inbox_path, "login_check"=>login_check, "vhost"=>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")
@ -164,15 +137,16 @@ class Metasploit3 < Msf::Auxiliary
end end
def try_user_pass(opts) def try_user_pass(opts)
domain = opts["domain"]
user = opts["user"] user = opts["user"]
pass = opts["pass"] pass = opts["pass"]
auth_path = opts["auth_path"] auth_path = opts["auth_path"]
inbox_path = opts["inbox_path"] inbox_path = opts["inbox_path"]
login_check = opts["login_check"] login_check = opts["login_check"]
vhost = opts["vhost"] vhost = opts["vhost"]
domain = opts["domain"]
user = domain + '\\' + user if domain user = domain + '\\' + user if domain
user = datastore['AD_DOMAIN'] + '\\' + user if datastore['AD_DOMAIN'] != ''
headers = { headers = {
'Cookie' => 'PBack=0' 'Cookie' => 'PBack=0'
} }
@ -254,6 +228,47 @@ 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
begin
urls.each do |url|
res = send_request_cgi({
'encode' => true,
'uri' => "/#{url}",
'method' => 'GET',
'headers' => {"Authorization" => "NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw=="}
}, 25)
if not res
print_error("#{msg} HTTP Connection Error, Aborting")
return :abort
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)
break
end
end
rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT
print_error("#{msg} HTTP Connection Failed, Aborting")
return :abort
end
return domain
end
def msg def msg
"#{vhost}:#{rport} OWA -" "#{vhost}:#{rport} OWA -"
end end