8. Bypassing ASLR/NX with Ret2PLT
Bypassing ASLR/NX with Ret2PLT
Before beginning this section, please ensure you have re-enabled ASLR. You can do this by running the following command.
ubuntu@ubuntu-xenial:/vagrant/lessons/7_bypass_nx_ret2libc/scripts$ echo 2 |
sudo tee /proc/sys/kernel/randomize_va_space
2Finally, we have two protections enabled: ASLR and NX. To start off, this will be our first target for the section:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
void show_time() {
system("date");
system("cal");
}
void vuln() {
char buffer[64];
read(0, buffer, 92);
printf("Your name is %s\n", buffer);
}
int main() {
puts("Welcome to the Matrix.");
puts("The sheep are blue, but you see red");
vuln();
puts("Time is very important to us.");
show_time();
}Running the binary:
Now that ASLR has been enabled, we have a problem. We no longer can be sure where the libc will be mapped at. However, that begs the question: how does the binary know where the address of anything is now that they are randomised? The answer lies in something called the Global Offset Table and the Procedure Linkage Table.
Global Offset Table
To handle functions from dynamically loaded objects, the compiler assigns a space to store a list of pointers in the binary. Each slot of the pointers to be filled in is called a 'relocation' entry. This region of memory is marked readable to allow for the values for the entries to change during runtime.
We can take a look at the '.got' segment of the clock binary with readelf.
Let's take the read entry in the GOT as an example. If we hop onto gdb, and open the binary in the debugger without running it, we can examine what is in the GOT initially.
It actually turns out that that value is an address within the Procedure Linkage Table. This actually is part of the mechanic to perform lazy binding. Lazy binding allows the binary to only resolve its dynamic addresses when it needs o.
If we run it and break just before the program ends, we can see that the value in the GOT is completely different and now points somewhere in libc.
Procedure Linkage Table
When you use a libc function in your code, the compiler does not directly call that function but calls a PLT stub instead. Let's take a look at the disassembly of the read function in PLT.
Here's what's going on here when the function is run for the first time:
The
read@pltfunction is called.Execution reaches
jmp DWORD PTR ds:0x804a00cand the memory address 0x804a00c is dereferenced and is jumped to. If that value looks familiar, it is. It was the address of the GOT entry ofread.Since the GOT contained the value 0x08048346 initially, execution jumps to the next instruction of the
read@pltfunction because that's where it points to.The dynamic loader is called which overwrites the GOT with the resolved address.
Execution continues at the resolved address.
The details of this will be important for the next section but for now, the crucial characteristic of the PLT stub is that it is part of the binary and will be mapped at a static address. Thus, we can use the stub as a target when constructing our exploit.
Writing the Exploit
As per usual, here is the skeleton code to obtain EIP control of the binary.
Let's look at the available PLT stubs to choose from.
We are in luck, because system@plt is a powerful function we can definitely use. That's one out of two things we need. The second thing is a command we can execute. Normally, we would use "/bin/sh" but it does not seem we would find that here.
Take a moment to figure out a target before taking a look at the answers.
It turns out that ed is a valid Linux command. It actually spawns a minimalistic editor. It also turns out that there is an "ed" string available in the binary. Can you spot it?
If we take the last two characters of the string "The sheep are blue, but you see red" or "_IO_stdin_used", we can get that "ed" we are looking for.
Putting our parts together, we can come up with this final exploit.
But, now you might ask, if all we are going to spawn is a line based text editor, then how are we going to get our shell? As it so happens, the ed program can actually run commands!
Exercises
Please do these exercises without looking at the solution.
Ex 9.1: Event 0
Let's start doing some difficult exercises. Here is event0. Try to solve this problem using the Ret2PLT technique.
The binary can be found here. And the remote target is at nc localhost 1901.
If you get stuck, you can look at the following solution scripts in order of completeness.
Skeleton
Local POC
Remote POC
Last updated
Was this helpful?