Hacking Blind
A classic paper for low-level vulnerabilities and defenses, attackers attack server via stack overflow. I learnt a lot of basic concepts in computer security from this paper.
Introduction
Before this paper, all attacks need the accessibility to binary, and no general techniques to attack 64-bit servers with PIE. However, the authors proposed Blind Return Oriented Programming, BROP, which makes it possible to attack 64-bit PIE servers that do not rerandomize after a crash, without the need of binary.
Before coming to the details of BROP, let’s talk about some background knowledge in low-level computer security.
Brief History of Buffer Overflows
The buffer overflows usually happen when a vulnerable program read data whose size exceeds the pre-defined buffer size. Without appropriate bound check, the input data will overwrite the memory beyond the end of the buffer. Without other defend techniques, attackers can write malicious code into the stack and overwrite the return address to jump to this malicious code and execute them. It is very classic “Code Injection”.
However, code injection is not possible on modern processers now, because operating systems will mark data memory pages as “non-executable” (NX on x86), that any attempts to run code on the stack will cause an exception.
To defeat NX, another technique called Return Oriented Programming, ROP is proposed. Since there must be executable parts in the memory space, attackers can utilize code snippets from this space and combine them to perform arbitrary operation. Such code snippets are called as gadgets. The attackers can overwrite the return address alongside the stack, pointing to desired gadgets and creating a chain of gadgets that gain control of programs without any dependence on code injection. On 32-bit systems it is very efficient because all arguments are passed in stack. On 64-bit systems, whose arguments are passed in registers, additional gadgets are needed to manipulate the value in registers.
Both Code Injection and ROP rely on Stack Overflows, so Address Space Layout Randomization, ASLR is introduced to defend it. ASLR will randomize the location of code and data memory segments in the process address space, which makes the address of code (or even stack) unpredictable. However, on 32-bit systems, ASLR is restricted by the limited address space, making brute-force attacks possible. On 64-bit systems, there are too much randomness for brute-force to be feasible. To enhance ASLR, Position-Independent Executable, PIE is a kind of executable that can be loaded at any memory address, rather than a fixed one. With PIE, the entire executable can be relocated, and its code address space randomized, making attacks like Return-Oriented Programming (ROP) much harder.
Canary is another common technique to defend stack overflows by detecting whether the value in stacks is overwritten. Stack canary is a pre-defined secret value that is placed before saved frame pointer and return address, which will be checked when the function returns. There are still several ways to circumvent canary.
ROP Tutorial
In general, ROP will manipulate the return addresses in stack, presenting a link of gadgets. The processer will go through the gadgets chain along with the addresses in the stack. Fig. 1 and 2 show how a malicious code is divided and linked via ROP.
Unlike what shown in Fig. 2, in practice, each ROP gadgets will be a short sequence of machine instructions terminated by a return. So, dup2(s,0)
is divided into more tiny snippets. The needed gadgets are used to manipulate the value in registers, like rdi
, controlling the first argument of function, rsi
, controlling the second argument of function, and rax
, controlling the system call number.
Registers can be controlled by using pop gadgets and placing the value to load on the stack. By chaining enough gadgets, complete shellcode can eventually be built.
BROP Environment
- A stack vulnerability and knowledge of how to trigger it. (because we need to utilize stack overflows)
- A server application that restarts (but do not rerandomize) after a crash.
The threat model for a BROP attack is an attacker that knows an input string that crashes a server due to a stack overflow bug. The attacker must be able to overwrite a variable length of bytes including a return instruction pointer.
Stack Reading
The authors proposed a method to “read” the value stored in the stack, to
- know the secret value of canary,
- find an address that won’t crash the service, which will become the starting point to find other useful gadgets.
It is done by overwriting the value after buffer bit by bit. If we write a correct/valid bit, the server won’t crash, so we can know the actual value of the first bit of canary. Repeating this, we can finally “read” the whole value of canary. It is much quicker than guessing the whole sequence. For return address, we may not find the exact value originally stored in the stack but must an address that won’t cause crash.
BROP Attack
The optimized BROP attack is as follows:
- Find where the executable is loaded. Either 0x400000 for non-PIE executables (default) or stack read a saved return address.
- Find a stop gadget. This is typically a blocking system call (like sleep or read) in the PLT. The attacker finds the PLT in this step too.
- Find the BROP gadget. The attacker can now control the first two arguments to calls.
- Find strcmp in the PLT. The attacker can now control the first three arguments to calls.
- Find write in the PLT. The attacker can now dump the entire binary to find more gadgets.
- Build a shellcode and exploit the server.