@@ -71,6 +71,7 @@ def initialize
71
71
register_advanced_options (
72
72
[
73
73
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 ] ) ,
74
75
OptBool . new ( 'SSL' , [ true , "Negotiate SSL for outgoing connections" , true ] )
75
76
] , self . class )
76
77
@@ -84,44 +85,6 @@ def cleanup
84
85
end
85
86
86
87
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
-
125
88
# Store the original setting
126
89
@blank_passwords_setting = datastore [ 'BLANK_PASSWORDS' ]
127
90
@@ -152,27 +115,38 @@ def run
152
115
auth_path = action . opts [ 'AuthPath' ]
153
116
inbox_path = action . opts [ 'InboxPath' ]
154
117
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
155
128
156
129
begin
157
130
each_user_pass do |user , pass |
158
131
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 } )
160
133
end
161
134
rescue ::Rex ::ConnectionError , Errno ::ECONNREFUSED
162
135
print_error ( "#{ msg } HTTP Connection Error, Aborting" )
163
136
end
164
137
end
165
138
166
139
def try_user_pass ( opts )
167
- domain = opts [ "domain" ]
168
140
user = opts [ "user" ]
169
141
pass = opts [ "pass" ]
170
142
auth_path = opts [ "auth_path" ]
171
143
inbox_path = opts [ "inbox_path" ]
172
144
login_check = opts [ "login_check" ]
173
145
vhost = opts [ "vhost" ]
146
+ domain = opts [ "domain" ]
147
+
174
148
user = domain + '\\' + user if domain
175
- user = datastore [ 'AD_DOMAIN' ] + '\\' + user if datastore [ 'AD_DOMAIN' ] != ''
149
+
176
150
headers = {
177
151
'Cookie' => 'PBack=0'
178
152
}
@@ -254,6 +228,47 @@ def try_user_pass(opts)
254
228
end
255
229
end
256
230
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
+
257
272
def msg
258
273
"#{ vhost } :#{ rport } OWA -"
259
274
end
0 commit comments