Skip to content

Commit 7e098e4

Browse files
committed
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.
1 parent 7e0b26e commit 7e098e4

File tree

1 file changed

+56
-41
lines changed

1 file changed

+56
-41
lines changed

modules/auxiliary/scanner/http/owa_login.rb

Lines changed: 56 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ def initialize
7171
register_advanced_options(
7272
[
7373
OptString.new('AD_DOMAIN', [ false, "Optional AD domain to prepend to usernames", '']),
74+
OptBool.new('ENUM_DOMAIN', [ true, "Automatically enumerate AD domain using NTLM authentication", true]),
7475
OptBool.new('SSL', [ true, "Negotiate SSL for outgoing connections", true])
7576
], self.class)
7677

@@ -84,44 +85,6 @@ def cleanup
8485
end
8586

8687
def run
87-
urls = ["aspnet_client",
88-
"Autodiscover",
89-
"ecp",
90-
"EWS",
91-
"Microsoft-Server-ActiveSync",
92-
"OAB",
93-
"PowerShell",
94-
"Rpc"]
95-
96-
domain = nil
97-
98-
begin
99-
urls.each do |url|
100-
res = send_request_cgi({
101-
'encode' => true,
102-
'uri' => "/#{url}",
103-
'method' => 'GET',
104-
'headers' => {"Authorization" => "NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw=="}
105-
}, 25)
106-
107-
if not res
108-
print_error("#{msg} HTTP Connection Error, Aborting")
109-
return :abort
110-
end
111-
112-
if res and res.code == 401 and res['WWW-Authenticate'].match(/^NTLM/i)
113-
hash = res['WWW-Authenticate'].split('NTLM ')[1]
114-
domain = Rex::Proto::NTLM::Message.parse(Rex::Text.decode_base64(hash))[:target_name].value().gsub(/\0/,'')
115-
print_good("Found target domain: " + domain)
116-
break
117-
end
118-
end
119-
120-
rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT
121-
print_error("#{msg} HTTP Connection Failed, Aborting")
122-
return :abort
123-
end
124-
12588
# Store the original setting
12689
@blank_passwords_setting = datastore['BLANK_PASSWORDS']
12790

@@ -152,27 +115,38 @@ def run
152115
auth_path = action.opts['AuthPath']
153116
inbox_path = action.opts['InboxPath']
154117
login_check = action.opts['InboxCheck']
118+
119+
domain = nil
120+
121+
if datastore['AD_DOMAIN'].nil? or datastore['AD_DOMAIN'] == ''
122+
if datastore['ENUM_DOMAIN']
123+
domain = get_ad_domain
124+
end
125+
else
126+
domain = datastore['AD_DOMAIN']
127+
end
155128

156129
begin
157130
each_user_pass do |user, pass|
158131
vprint_status("#{msg} Trying #{user} : #{pass}")
159-
try_user_pass({"user" => user, "pass"=>pass, "domain" => domain, "auth_path"=>auth_path, "inbox_path"=>inbox_path, "login_check"=>login_check, "vhost"=>vhost})
132+
try_user_pass({"user" => user, "domain"=>domain, "pass"=>pass, "auth_path"=>auth_path, "inbox_path"=>inbox_path, "login_check"=>login_check, "vhost"=>vhost})
160133
end
161134
rescue ::Rex::ConnectionError, Errno::ECONNREFUSED
162135
print_error("#{msg} HTTP Connection Error, Aborting")
163136
end
164137
end
165138

166139
def try_user_pass(opts)
167-
domain = opts["domain"]
168140
user = opts["user"]
169141
pass = opts["pass"]
170142
auth_path = opts["auth_path"]
171143
inbox_path = opts["inbox_path"]
172144
login_check = opts["login_check"]
173145
vhost = opts["vhost"]
146+
domain = opts["domain"]
147+
174148
user = domain + '\\' + user if domain
175-
user = datastore['AD_DOMAIN'] + '\\' + user if datastore['AD_DOMAIN'] != ''
149+
176150
headers = {
177151
'Cookie' => 'PBack=0'
178152
}
@@ -254,6 +228,47 @@ def try_user_pass(opts)
254228
end
255229
end
256230

231+
def get_ad_domain
232+
urls = ["aspnet_client",
233+
"Autodiscover",
234+
"ecp",
235+
"EWS",
236+
"Microsoft-Server-ActiveSync",
237+
"OAB",
238+
"PowerShell",
239+
"Rpc"]
240+
241+
domain = nil
242+
243+
begin
244+
urls.each do |url|
245+
res = send_request_cgi({
246+
'encode' => true,
247+
'uri' => "/#{url}",
248+
'method' => 'GET',
249+
'headers' => {"Authorization" => "NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw=="}
250+
}, 25)
251+
252+
if not res
253+
print_error("#{msg} HTTP Connection Error, Aborting")
254+
return :abort
255+
end
256+
257+
if res and res.code == 401 and res['WWW-Authenticate'].match(/^NTLM/i)
258+
hash = res['WWW-Authenticate'].split('NTLM ')[1]
259+
domain = Rex::Proto::NTLM::Message.parse(Rex::Text.decode_base64(hash))[:target_name].value().gsub(/\0/,'')
260+
print_good("Found target domain: " + domain)
261+
break
262+
end
263+
end
264+
265+
rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT
266+
print_error("#{msg} HTTP Connection Failed, Aborting")
267+
return :abort
268+
end
269+
return domain
270+
end
271+
257272
def msg
258273
"#{vhost}:#{rport} OWA -"
259274
end

0 commit comments

Comments
 (0)