BOF
🔍 Details
| Attribute | Details |
|---|---|
| Challenge Name | BOF |
| Category | Binary Exploitation |
| Difficulty | 🔴 Hard |
| Flag | F4H{b3n1ItFaWP**********} |
📝 Description
After running the docker image, run the exetable ./bof
Try to type something-yes, it requires a password.
But here’s a secret: the code isn’t written the best way.
Can you exploit a buffer overflow to bypass authentication without knowing the correct password?
In the terminal, pull the challenge image:
docker pull public.ecr.aws/h7j1s9m0/fl4ghunt-ecr:buffer_overflow_ctfRun the container:
docker run --rm -it public.ecr.aws/h7j1s9m0/fl4ghunt-ecr:buffer_overflow_ctfInside an interactive shell, execute:
./bof🧩 Hints
- Try experimenting with longer inputs and observe what happens.
- When the program crashes, it leaves behind clues. Check the system logs to see where it broke.
- The program was compiled with disabled PIE, making memory locations predictable. Can you find a function inside the binary that should only be accessible under specific conditions?
💡 Solution
- After running the binary
./bofand providing random input likeqwertyuiopasdfghjklzxcvbnmabcdefghijklmnopqrstuvwxyz, Segmentation fault occurs. - You can confirm the use of vulnerable method
gets()by disassembling the binary using:
objdump -d bof- Look for a suspiciously named function like
unclockAccess(The name is purposely written as it is) — it will print the flag if called. - By analyzing the disassembly, you can find the address of
unclockAccessand the offset to overwrite the return address. - Now you need to determine offset and overwrite the return address.
- Try different lengths of input until the program crashes. Once found (e.g., ~30 characters), craft a payload that:
- Fills the buffer
- Overwrites the return address with
0x0804930d(little endian →\x0d\x93\x04\x08)
- Here is the final payload:
(echo -e "qwertyuiopasdfghjklzxcvbnmab\x0d\x93\x04\x08"; cat) | ./bofExplanation:
- The string is long enough to reach the return address
\x0d\x93\x04\x08is the address ofunclockAccess()in little endian format- The
catensures the program doesn't hang waiting for more input
- After running the above command, the program skips the password check and prints ther flag.
📚 Insights
Binary compilation
The binary was compiled using:
gcc -std=c11 -o bof bof.c -m32 -z execstack -Wno-deprecated-declarations -no-pie -fno-stack-protectorHere’s what each flag means and why it matters:
- m32: Compiles the binary for a 32-bit architecture, which uses a smaller address space and simplifies exploitation.
- z execstack: Marks the stack as executable. Though not strictly needed here, it would allow shellcode execution in other contexts.
- no-pie: Disables Position Independent Executable support. This makes function addresses static and predictable, simplifying return address overwrites.
- fno-stack-protector: Disables stack canaries, meaning there’s no built-in protection against stack overflows.
- Wno-deprecated-declarations: Suppresses warnings about deprecated functions like gets(). Together, these flags intentionally weaken binary security, creating a perfect learning environment for classic buffer overflow exploitation.
Vulnerable method
The vulnerability stems from the use of the gets() function. Unlike fgets(), it:
- Does not check input length
- Continues reading until a newline is received
- Overflows the buffer if input is too long
- This makes
gets()a notorious example of insecure programming and is why it has been removed from modern C standards.
In this binary, user input is read into a small buffer with gets(), and no bounds checking is performed — allowing you to overwrite the return address on the stack.
Why This Matters
- This type of stack-based buffer overflow is a textbook example of low-level memory exploitation.
- Though simple, it reflects real-world vulnerabilities in legacy or embedded systems.
- It teaches the importance of secure coding practices (e.g., avoiding unsafe functions, enabling compiler protections)