How to exploit a buffer overflow vulnerability in Linux
In this simple howto we will see how the execution flow of a program can be redirected, by exploiting a BOF (Buffer Overflow) vulnerability. If you are not familiar with this term or its use, please refer to the wiki page.
In this howto I will assume that all of you have (at least) a basic knowledge of:
- Function calling procedure
If you don't meet one or more of the above ponts, I suggest you to gather more information
Few further notes before to begin:
- The machine I use, has installed Ubuntu 12.04 64 bit with a kernel v.3.5.0-40. Since my machine has a 64 bit core, the addresses shown in this howto will be 8 bytes long. Anyway this fact changes almost nothing!
- BOF exploits become harder since the Linux Kernel 2.4 has been relased, due to the introduction of several protections (on stack, execution flags, ALSR, etc.). Thus, in order to let the example programs in this howto work, we will compile them with the -fno-stack-protector flag on. This flag merely says to the compiler to do not activate the stack protection.
Take a look at the following main:
As you can see, the purpose of the above code, merely is to take characters from
the keyboard, as long as an 'x' is entered, then counting the number of characters insterted, and finally
saying if such a number is even or odd.
The buffer buf is thought to contain only 10 characters, but actually there is not any
control to enforce that. Here it is the BOF vulnerability!
In fact if we write more than 10 characters, the program will try to place all of them in the buffer buf, one by one. Not only 10. If the buffer is not enough large, the overflowing characters will be written in the near memory locations.
Hence, let's try to pass to the program 50 chars.
the expression: perl -e 'print "A"x50 . "x"' literally says "print A 50 times and append an x", try in a shell to believe.
Furthermore we can regularly place the characters to write in a separate file, then passing them to the program with: $./progr < file
This is going to work thanks to the operator of standard input redirection (i.e. <).
So the steps to perform are:
- $gcc -g -fno-stack-protector bof.c -o bof
- $echo "`perl -e 'print "A"x50 . "x"'`" > expl
- $./bof < expl
Numer of insterted character is even
 17375 segmentation fault (core dumped) ./bof < expl
What we get is a message error saying to us that a segmentation fault happened. This is happened because we have written so many A letters that we have overwritten the memory portions beyond the memory reserved for the buf variable. Particularly the memory location reserved to contain the memory address to jump when the return statement is executed, has been soiled. And this fact has caused a fault. In fact the fault happened when the return statement is executed
Let's take a closer look by using the gdb debugger (GNU debugger):
Let's see the program body, and let's fix a breakpoint just before the return statement.
Ok, now let's run the program giving to it the 50 'A's as showed before.
The program has stopped at the breakpoint.
Up to now the program it is not crashed yet. In fact,
as said before, it will crash during the execution of the
return statement. Not before.
So, let's see the assembly code:
As we can see the return statement is performed by the three
latest instructions. Particularly the purpose of the very last
one (retq) is to pop
up an 8 byte value from the the top of the stack and jumping into it.
Usually, at this point of a program execution, the top of the stack would contain a valid address. So, let's skip two machine instructions and see what actually the top of stack contains:
As we can see, the top of the stack contains a list of
apparently strange characters. If we are familiar with
the ASCII table, we will note immediately that what the
stack contains actually is a list of A!
So, what happened?
It merely happened, that we wrote a numer of A long enough to overwrite the stack starting from the location of the variable buf, up to the place where the returning address should had been placed.
Therefore when the retq statement is executed, the popped address will be not valid and thus a fault will be thrown.
But, What would happen if we would write a valid address,
instead of a list of A?
Did you already guess, didn't you? The execution flow will be redirect where the address says!!
So, let's do it!
First of all: we just need to write a number of chars
long enough to write the first location of stack, when
the retq will be executed. Therefore, as the above stack snippet
shows, 50 chars are too many.
If we look at the above snippet, we will see that we have written 18 byte more. Hence the right length of our string will be: 50 - 18 = 32 bytes.
Now, let's take the address of the function bof(): What we have to do now is to write 24 'A's and a 8 byte long address.
In fact, even though the above address is showed using only 3 bytes, we have to represent it completely, hence on 8 bytes; hence: 0x0000000000400634. Furthermore, my machine uses a little endian representation (and probably also yours), hence the bytes of the address have to be written using this correct representation. Hence the address in the little endian representation, and written in bytes, became: \x34\x06\x40\x00\x00\x00\x00\x00.
From another terminal, let's modify the expl file writing in it the new string and let's launch again the program:
- $echo "`perl -e 'print "A"x24 . "\x34\x06\x40\x00\x00\x00\x00\x00" . "x"'`" > expl
- $./bof < expl
$./bof < expl
Numer of insterted character is even
 18534 segmentation fault (core dumped) ./bof < expl
Thus, in a nuthsell, what happened is:
So, this was the way to redirect an execution flow by exploiting a buffer overflow.
Obviously this was a really useless example, I left you to think what we could do with this kind
The use of this material at the expense of others is absolutely not approved by badnack, which is not considered in any way responsible for any damage caused by improper use of the material. Copies of the above links are for illustrative purposes only and are posted only for for educational purposes