We covered a scenario of a binary vulnerable to buffer overflow vulnerability. The binary has NX and PIE protections enabled so we opened the binary with Ghidra debugger and built the exploitation methodology based on calculating the offsets of the input variable and another variable that controls an entry to an if statement that prints the flag. The objective was to control the value of that binary and let the execution flow enter the if statement. This was part of HackTheBox Jeeves Intro to Binary Exploitation Track.
Initial Analysis and Code Exploration
I began my analysis of the downloaded executable by checking its file type, confirming it was a 64-bit executable. I then used the command checksec file Jeeps
to inspect its security protections, specifically looking for buffer overflow mitigations. Following this, I opened the binary in Ghidra, a reverse engineering tool, to delve into its code.
In Ghidra, I focused on the main
function. I identified a variable, Local 48
, as the one responsible for accepting user input—the program prompts the user for their name, which gets stored here. Crucially, I noticed an if
statement that depended on another integer variable, local_underscore_C
. If local_underscore_C
held a specific hexadecimal value (0x6161616161616161
), the code inside the if
statement would execute. This code was designed to open a file named flag.txt
, read its content, and presumably print the flag. The challenge was that I could only directly control Local 48
, making it seem impossible to enter the if
statement through normal input since local_underscore_C
appeared to be a separate variable.
- Query successful
Try again without apps
I’ve summarized the video about the “Jeeps” Hack The Box challenge in detail, using a conversational tone and the pronoun “I,” as you requested. I’ve also extracted the technical commands shown on the terminal.
Hack The Box: “Jeeps” Challenge Walkthrough 💻
I started by introducing the “Jeeps” challenge from Hack The Box’s “Intro to Binary Exploitation” track. The core objective of this challenge is to understand and apply buffer overflow techniques. I explained that the first step is to start the challenge instance, which provides an IP address and port for connection. You can also download the challenge files, including an executable that needs to be exploited.
Initial Analysis and Code Exploration 🕵️♂️
I began my analysis of the downloaded executable by checking its file type, confirming it was a 64-bit executable. I then used the command checksec file Jeeps
to inspect its security protections, specifically looking for buffer overflow mitigations. Following this, I opened the binary in Ghidra, a reverse engineering tool, to delve into its code.
In Ghidra, I focused on the main
function. I identified a variable, Local 48
, as the one responsible for accepting user input—the program prompts the user for their name, which gets stored here. Crucially, I noticed an if
statement that depended on another integer variable, local_underscore_C
. If local_underscore_C
held a specific hexadecimal value (0x6161616161616161
), the code inside the if
statement would execute. This code was designed to open a file named flag.txt
, read its content, and presumably print the flag. The challenge was that I could only directly control Local 48
, making it seem impossible to enter the if
statement through normal input since local_underscore_C
appeared to be a separate variable.
Finding the Buffer Overflow Offset
My goal was to overwrite local_underscore_C
by providing an input to Local 48
that was long enough to spill over into local_underscore_C
‘s memory location. In Ghidra, I examined the memory offsets of these variables:
local_underscore_C
was at offset0xc
(hexadecimal).Local 48
(user input) was at offset0x48
(hexadecimal).
I calculated the difference to find the required offset:
0x48
(hex) = 72 (decimal)0xc
(hex) = 12 (decimal)- Distance = 72 – 12 = 60 bytes. This meant I needed 60 bytes of input to reach and begin overwriting
local_underscore_C
.
Confirming the Offset with GDB
To confirm my findings from Ghidra, I used GDB (GNU Debugger). I started GDB with the executable using a command similar to gdb ./Jeeps
. I set a breakpoint right after the gets
function (which handles user input) in the main
function using the command:
breakpoint *main+53
Then, I ran the program with a short input using run
(or r
). By examining the stack in GDB, I was able to reconfirm that the distance between the user input’s location and the target variable (local_underscore_C
) was indeed 60 bytes.
Crafting the Exploit Script with Pwntools
I then wrote a Python script to automate the exploit using the pwntools
library. I started by importing it: from pwn import *
.
The script’s logic was as follows:
- It connected to the remote instance using
netcat
functionality provided bypwntools
, specifying the target IP and port. - I constructed the payload:
- First, I filled the buffer with 60 ‘A’ characters to reach the
local_underscore_C
variable. The code for this waspayload = 'A' * 60
. - Next, I needed to append the target hexadecimal value (
0x6161616161616161
) thatlocal_underscore_C
needed to hold. I used thep64()
function frompwntools
to pack this hex value into bytes:byte_payload = p64(0x6161616161616161)
. - Since the input expected was a string, I decoded this byte payload into a string using
ISO-8859-1
encoding:byte_payload.decode('ISO-8859-1')
. - The final payload was the concatenation of the 60 ‘A’s and the decoded hexadecimal value.
- First, I filled the buffer with 60 ‘A’ characters to reach the
- The script then sent this crafted payload to the server using
target.sendline(final_payload)
. - Finally, it received and printed the output until it found a closing curly brace
}
, which I expected to be the end of the flag:print(target.recvuntil(b'}'))
.
I used the nano exploit.py
command to create and edit the script.
Running the Exploit and Getting the Flag
To execute the exploit, I simply ran the Python script using:
python3 exploit.py
(orpython exploit.py
)
The script successfully connected, sent the crafted input, overwrote local_underscore_C
with the desired value, triggered the if
condition, and the server responded with the flag! I then submitted the flag to Hack The Box.
In essence, this video demonstrated how a simple buffer overflow works. By providing more input than a program expects for a particular variable, the excess data “overflows” into adjacent memory locations. In this specific case, I precisely controlled this overflow to overwrite a different variable with a specific value, which then unlocked a part of the code that printed the flag. Tools like Ghidra (for static analysis) and GDB (for dynamic analysis) were indispensable for understanding the binary’s behavior and calculating the exact offset needed for the overflow. Pwntools then provided the means to automate sending this specially crafted input to the remote server.