From 7e098e4d6b6fc387ec4d88eee21f682f635a8b5f Mon Sep 17 00:00:00 2001 From: kaospunk Date: Thu, 22 Aug 2013 14:16:00 -0400 Subject: [PATCH] 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. --- modules/auxiliary/scanner/http/owa_login.rb | 97 ++++++++++++--------- 1 file changed, 56 insertions(+), 41 deletions(-) diff --git a/modules/auxiliary/scanner/http/owa_login.rb b/modules/auxiliary/scanner/http/owa_login.rb index 7dbafeb132..4e2f06f770 100644 --- a/modules/auxiliary/scanner/http/owa_login.rb +++ b/modules/auxiliary/scanner/http/owa_login.rb @@ -71,6 +71,7 @@ class Metasploit3 < Msf::Auxiliary register_advanced_options( [ 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]) ], self.class) @@ -84,44 +85,6 @@ class Metasploit3 < Msf::Auxiliary end 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 @blank_passwords_setting = datastore['BLANK_PASSWORDS'] @@ -152,11 +115,21 @@ class Metasploit3 < Msf::Auxiliary auth_path = action.opts['AuthPath'] inbox_path = action.opts['InboxPath'] 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 each_user_pass do |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 rescue ::Rex::ConnectionError, Errno::ECONNREFUSED print_error("#{msg} HTTP Connection Error, Aborting") @@ -164,15 +137,16 @@ class Metasploit3 < Msf::Auxiliary end def try_user_pass(opts) - domain = opts["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 - user = datastore['AD_DOMAIN'] + '\\' + user if datastore['AD_DOMAIN'] != '' + headers = { 'Cookie' => 'PBack=0' } @@ -254,6 +228,47 @@ class Metasploit3 < Msf::Auxiliary 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 "#{vhost}:#{rport} OWA -" end