Sitemap

ROP Chains

5 min readDec 27, 2024

--

Since my main focus is malware analysis, I’m very interested in reverse engineering. I was reading about how to use this topic in binary exploitation and saw the concept of ROP chain.

ROP is an acronym for Return Oriented Programming, which means the writing of exploits focused in the return of the functions. The term “chain” in the ROP chain brings the idea of chaining together small snippets of assembly code to control the stack and, consequently, the flow of the binary execution.

But what is the stack? When you run a binary, there’s a stack, which stores and removes information during the execution. To know the top of the stack, to know where the next action in the stack will be made, the address of the top is stored in the register ESP (stack pointer).

When the binary is executed, in the top are the variables and the functions, followed by the register EBP (base pointer), and the address where it goes when there’s a return in the function, which will be stored in EIP (instruction pointer), the register that points the next address of the execution.

When we talk about a buffer overflow vulnerability, we are saying that, if exploited, it can write more than on variable can store, so the reminiscent value will go on the stack until rewrite the EIP.

To demonstrate this in practice, I will show the two first ROPEmporium challenges, which are the most basic ones.

In the first challenge, we need to call the ret2win function, which calls a system function with the argument “/bin/cat flag.txt”. Since there’s no way to enter the function during the normal execution of the binary, there’s a buffer overflow vulnerability inside of it, which we can exploit in the “call read” on the pwnme function.

The “call read” instruction is on the address 0x400744, so we would have to overwrite EIP to point to 0x400756, the beginning of ret2win, but the first instruction is a “push” instruction. The “push” will put news values on the stack, which will break the execution, so we will point to 0x400757.

The system is little-endian, so we have to write the address backwards. In addition with the fact that the architecture is x86_64, which uses 8 bytes, we have to fill the other 5 bytes with 0. Mixing with the 0x41’s to cause the buffer overflow, we need to write a input like that.

Debbuging the execution passing this input as argument, we can see that top of the stack was overwritten with the address that we put on the input, that is 0x400757.

This demonstrate that if we pass the input in the execution, we can get the flag.

The first challenge is a trivial one, just to know how to overwrite the RIP address. In the second challenge we will have to use the concept of ROP chain. The challenge here is because, in the previous one, the “system” function call /bin/cat, but this time it calls “/bin/ls flag.txt”. We need to find a way to call “/bin/cat flag.txt”.

If we get only the strings of the data sections of the binary, using the flag -d on strings command, together with the flag -t=x, to also get the position in hexadecimal of each string, we can find the /bin/cat in the position 0x1060. But these positions doesn’t have the offset, so we can’t known exactly in what section they are.

Viewing the position of each data section (.data, .rodata and .bss), using the command objdump — section=<section_name> -h <file>, we can see that .data section starts in 0x601050, so, problably, this string is on that section. To be sure, during the execution, we can print the value of the address 0x601060 to confirm that “/bin/cat flag.txt“ is on that address.

Looking into the code, we need to use the “call read” on 0x400730 to overwrite the stack and enter to “usefulFunction”. Not only that, we also need to replace the “system” function argument to “/bin/cat flag.txt”

To pass this value on the argument, we need to look at the x86_64 documentation, where it describes that if we can pass the first argument of a funcion in the RDI register.

Now the ROP chain technique come to action. We can use the tool ROPgadget to find gadgets that can be use in a ROP chain, which are the ones followed by a “ret” instruction. Running that tool, we can find that there’s a “pop rdi ; ret” on the address 0x4007c3.

With these informations that we get, we will write the exploit in the following way:

  1. 0x41’s to cause the buffer overflow
  2. “pop rdi” on the address 0x40074b
  3. “/bin/cat flag.txt” on the address 0x601060
  4. “system” function on the address 0x40074b

Considering the little-endian, our exploit will be:

Debugging the binary can show that these addresses is being written in the stack successfully.

And when we execute the exploit, we can get the flag.

That’s it. I hope that this post can clarify the concept off ROP chain. This is a topic that I’m starting to study and writing about it help me to solidify the concepts as well as can help other people who are starting studying this topic too.

--

--

No responses yet