The one thing that will separates a script kiddy through a legitimate hacker or security professional is usually the ability to program. Script kiddies use different people’s tools, while hackers along with security pros write their own tools. To that will end, we’re going to see how a stack overflow vulnerability allows us to flood a variable with enough input to overwrite the instruction pointer with our own commands.
Understanding the Structure of a Program
Before we can understand how to exploit a program, we should have a general understanding of the program itself. When you first run a program, all of the information that will the program needs to execute is usually loaded into the RAM of the computer. Once a program is usually loaded into This specific memory to run, the item has 5 parts:
- Text: This specific is usually where the code for the program is usually.
- Initialized data: This specific is usually where global variables that will have been declared along with given a value are stored
- Uninitialized data/BSS: This specific is usually where global variables that will have been declared nevertheless not given a value are stored.
- Stack: The stack keeps track of the program execution along with stores local variables. We’ll talk about the stack more soon.
- Heap: The heap is usually where dynamic memory allocation takes place. A programmer can utilize the heap to store variables which are only needed for a short period of time along with so can be removed through memory later to optimize the program.
Understanding the Stack
Since we’ll be taking a look at a stack overflow vulnerability, the item makes sense to take some time to understand the stack. As mentioned above, the stack keeps track of the program execution. Specifically, the stack keeps track of what function is usually being executed along with the local variables that will are defined within that will function.
When a function is usually called, a data structure called a stack frame is usually created. Each function has its own stack frame which contains the local variables for that will function, the parameters passed to the function when the item was called, along with most importantly, a return address which specifies what instruction the program should execute next once the function is usually done.
Each time a completely new function is usually called, a completely new stack frame is usually added on the top of the stack. Likewise, each time a function finishes execution, the item is usually removed through the stack. This specific organization results in what is usually referred to as a LIFO data structure. LIFO stands for “last in first out” meaning that will the last stack frame added to the stack is usually the first one which will be removed.
With our stack overflow exploit, we’re more concerned about working within the scope of an individual stack frame. Our goal is usually to overflow a local variable into the return address of a stack frame in order that will we can redirect code execution.
nevertheless enough of the hypothetical already, let’s dig into a real program!
Exploiting Stack5 on the Protostar VM
For our example today, we’ll be looking at the stack5 level through the Protostar virtual machine we created in our last exploit development article. If you haven’t yet set up a virtual machine for Protostar, read the previous article first to do so.
Once you have your Protostar virtual machine fired up, let’s take a look at the source code for the stack5 program.
As we can see This specific is usually an extremely basic program. We see one local variable created on line 8, a string of characters called “buffer” which is usually allocated 64 bytes of memory. The only different exciting thing happens on line 10 when the program passes unsanitized user input into that will variable. This specific means that will while 64 bytes of memory is usually allocated within the stack frame for the variable “buffer,” there is usually nothing stopping us through passing more than 64 bytes into the variable. Let’s see what might happen if we were to do This specific.
Step 1: Creating a Skeleton for Our Exploit
Just like within the last tutorial, Protostar will not let us write any information within the same directory as the stack5 program, so we need to move to a directory where we can write a completely new file. To do This specific, simply type the following command.
This specific will change your directory to the home directory of the user. Once that will is usually done, let’s create a completely new Python program by typing the following command.
Let’s go line by line along with see how we’re going to setup This specific exploit below.
The first line tells the bash shell that will we are writing a program that will is usually to be run with the Python interpreter. Lines 2 along with 3 import packages that will we will need while we create our exploit. The struct package will give us an easy way to pack our return address into our payload, while the os package will let us run a few shell commands to launch the exploit. Line 4 contains the buffer overflow itself, while lines 5 along with 6 write that will payload to a file along with run the stack5 program with that will payload as the user input.
right now that will we have our framework, let’s go ahead along with save the program. We can give the program execute permissions by typing:
chmod +x exploit.py
This specific will allow us to execute the program, so let’s do so by typing:
You won’t see anything too exciting at This specific point. The program we just wrote will have created a completely new file called payload.txt containing 64 As. We’re going to use This specific file to take a look at what’s truly going on behind the scenes of the program.
Step 2: Investigating the Program
The next thing we should do is usually fire up GDB, the GNU debugger, in order that will we can step through the execution of the program. We can fire up GDB by typing the following in a terminal window.
The first thing we want to do in GDB is usually set a breakpoint. Looking at the original code for the program, we should probably set a breakpoint at line 11. We don’t want to break before the program accepts the user input, because then we cannot see the input within the program. Since the program accepts the input on line 10, the item makes sense to break right after This specific input has been accepted. To set a breakpoint, we type the following command.
right now we’re all set to run the program. We want to make sure that will the contents of the payload.txt file we made earlier are being correctly passed as the user input though. To do This specific, we are going to type the following.
run < payload.txt
This specific tells GDB that will we want to run the program along with use the contents of payload.txt as the input. Once This specific is usually done, we should hit the breakpoint at line 11 like such:
right now we can start poking around memory. The stack pointer will be pointing to the start of the stack frame for the main function, so in order to examine the stack frame, all we have to do is usually type the command below.
Let’s revisit what This specific command is usually actually saying first. The first x is usually short for “examine.” This specific command allows us to examine memory, so the name is usually fitting. The /32 specifies that will we want to examine the next 32 four-byte segments. The final x at the very end tells GDB that will we want to view This specific section of memory in hexadecimal format.
We could have also specified an s or i to view the memory as a string or integer, nevertheless that will wouldn’t make much sense. Hexadecimal format is usually by far the most helpful format to view large chunks of memory in.
Finally, $esp refers to the address of the stack pointer, which points to the beginning of the current stack frame.
Let’s take a look at the output we get through This specific command.
The most noticeable pattern in This specific chunk of memory is usually the big slew of 41s that will are sitting within the stack frame. These are the 64 As we wrote into the payload.
through This specific, we can see where we are starting through in memory, nevertheless where exactly are we trying to get to? The answer is usually the instruction pointer, or EIP.
The EIP specifies what memory address the next instruction is usually at. If we can overwrite This specific address with the address of instructions that will we write, we can hijack execution of the program completely. So how do we find the location of EIP? the item’s simple. To find the location of EIP we are going to type the following.
This specific will give us all the information that will is usually pertinent to the current stack frame. The output will look something like the image below.
We can see that will the output through the command includes a line which says “eip at 0xbffff7cc.” This specific is usually the address of the EIP, along with the item falls within the window of memory we were looking at earlier. By using the x command to examine that will piece of memory, we can identify the contents at that will address along with locate the same piece of memory within the window of memory we were looking at earlier. The address of the EIP has been highlighted in red, along with the EIP itself has been highlighted in green.
So right now we know where we’re starting, along with where we are trying to get to, so let’s expand our payload into the EIP along with see what happens! To do This specific, we’re going to have to exit GDB along with modify our exploit code. Open your payload again in nano using the same command as earlier to modify the item.
Because the last of our 64 As was 12 bytes away through the start of the EIP address, we’re going to add an extra 16 bytes in order to overflow the entire address. When we run the program again, the EIP should right now be overwritten with “0x41414141.” Let’s see if the item works. Running the exploit code again gives us the following output:
We see that will we get a “Segmentation fault” error, along with nothing could be more glorious. In This specific case, the item means that will we successfully overwrote EIP. Let’s run the program again in GDB along with take a look at the memory once more:
Just as we suspected, our longer payload overwrote the entire EIP address. right now when the program tried to execute the instruction at the address held in EIP, the item couldn’t. The program tried to find an instruction at memory address 0x41414141 which doesn’t exist. This specific created the segmentation fault we saw.
right now that will we can redirect code execution, we have to decide where we want to redirect code execution to. The program is usually pretty basic along with doesn’t offer any functionality we might truly want to manipulate, so the item makes sense for us to add our own instructions along with have those executed.
In This specific example, we’ll inject code that will will give us back a command shell. In theory, our exploit should look something like below.
The padding of As takes us right up to the EIP, which we will overwrite with the address of the shellcode that will we will place directly after the completely new address in our payload.
There is usually one problem though: We don’t actually know the memory address of the shellcode. While we may know the memory addresses that will the stack frame occupies in GDB, these address change slightly when the program is usually run by itself. We have to find a way to give ourselves some wiggle room.
Thankfully, there is usually a way to do that will. Enter the NOP.
NOP stands for “no operation.” Essentially, the item is usually an instruction which tells the program not to do anything along with move on to the next instruction. By using a large number of NOP instructions, we can redirect the instruction pointer to an address somewhere within the middle of our NOP instructions. right now even if the memory addresses are slightly higher or lower than those we saw in GDB, the instruction pointer will still land on a NOP along with continue down the “sled” of NOP instructions until the item reaches the shellcode. The real exploit will look something like the example below.
Let’s translate This specific concept into some actual code. Once more, we’ll go line by line in our exploit file.
On line 4, we’ve reduced the payload of As by four to make room for the completely new return address. On line 5, we use the struct.pack function in order to generate the completely new return address. 0xbffff7cc+100 will pack the address that will is usually 100 bytes higher than the address 0xbffff7cc, which is usually the location of EIP. This specific location will put the instruction pointer within the middle of the NOP sled, which we create on line 6. “x90” tells Python to put the hexadecimal value of 90 into the string, which is usually the representation of a NOP instruction. We take This specific along with multiply the item by 200 in order to give us a large sled of NOPs.
Once the padding, return address, along with NOP sled are all built, the item is usually time to add the shellcode. Before we add the actual shellcode, we are going to substitute a series of four bytes each containing the value cc. This specific value is usually uniquely recognized by the program as a breakpoint. By using these four bytes, we can test to see if the program hits the shellcode correctly. Let’s save the program along with run the item. We should get the following output:
Sure enough, we get a message letting us know that will we hit a breakpoint. The program has been exploited!
right now the item’s time to do something fun with the item. Going back to the exploit code, we can substitute our placeholder shellcode with the real thing below.
Once we copy along with paste the item into our program, we can save our exploit along with watch the shells rain through the skies!
Let’s see what happens when we run our program right now.
Well, that will was… disappointing. What went wrong? We know that will the exploit hits the shellcode, so why didn’t the item execute?
The funny thing is usually, the shellcode actually did execute. The problem was with the way that will the shell is usually being called. By the time the shellcode was executed, the standard input into the program was already closed, along with the shell just quit. We need a way to keep that will open.
Thankfully, the cat command can help us out. To use the item, let’s type the following.
(cat payload.txt; cat) | /opt/protostar/bin/stack5
Success! We finally have a working exploit. Before we start celebrating, let’s take a look at why This specific works. The first chunk of our command is usually what we see below.
(cat payload.txt ; cat)
The first part should make sense. Typing “cat payload.txt” might simply print the contents of payload.txt to the screen. The magic of This specific command comes with the second call to the cat command. When you call the cat command without any parameters, the program will by default open a prompt in which the item will print out any input that will you type. This specific means the standard input is usually redirected to the standard output. By calling This specific after we print the contents of payload.txt, we keep that will standard input open. Let’s examine the second part of the command below.
The | represents the pipe command. This specific allows us to pipe the output stream of the first chunk of our command into the stack 5 program. This specific way, we pass the exploit as input along with keep the standard input along with output open with the cat command so we can keep the shell alive.
Step 5: Finishing Touches
The whole point of writing an exploit is usually to make an individual program that will we can run to get a shell. We shouldn’t have to type in extra commands if we can avoid the item. This specific can be done by replacing the last line of our exploit code.
Instead of using the os.system command to run stack5 along with pass the payload as input, we use the completely new command that will we just looked at to keep the standard I/O stream open. right now when we run the program, we’ll get a root shell every time.
As a sort of homework assignment, I might recommend going back to stack level 4 along with trying to write your own exploit. that will level is usually slightly simpler than the one we looked at today nevertheless uses a lot of the same concepts. through there, being able to conquer the last two stack levels will cement your knowledge of stack overflow exploitation.
Thank you so much for reading! Comment below with any questions or contact me via Twitter @xAllegiance.