ACS 2023: register
Register your nickname and email address!
TL;DR
Exploit null-byte overwrite to leak canary, followed by a Partial Overwrite to ret2main. In the second stage, exploit the same null-byte overwrite to leak LIBC, then ret2libc.
Challenge Overview
The program is a user registration platform that asks for a username and email address. The interesting part is both user inputs are echoed back to us.
All protections are fully enabled. This means that we need at least 3 info leaks for canary, PIE, and LIBC respectively.
Null-byte Overwrite (Leak Canary)
2 rounds of obvious buffer overflows occur when trying to read 256 bytes into a limited buffer. After receiving user input, printf()
is called to echo the input back to us. Since the canary is positioned below our buffer, we can overflow the null byte sitting in the middle, causing printf()
to leak the canary.
Ghidra shows that the canary is sitting at a 40-byte offset relative to our input, via the in_FS_OFFSET
value. To double confirm, inspecting the rsi
using GDB before the first read()
also shows a potential canary sitting at an 40-byte offset.
This means that 41 A's should overflow the null byte and leak the canary.
Partial Overwrite (ret2main)
During our 2nd BOF, we must return to main
to restart the program and reintroduce the vulnerability so that we get infinite info leaks, as we still require a PIE and LIBC leak. However, exploiting this is complicated since the binary has PIE enabled, meaning we can't reliably return to anywhere without first leaking the PIE. This brings us to another problem - how can we attempt to leak both canary and PIE values at the same time during the 1st BOF?
In fact, we do not need a PIE base leak at all; we can instead ret2main via a Partial Overwrite during the 2nd BOF. Since PIE does not affect the Least Significant Byte (LSB), we can brute-force this value from \x00
to \xff
to see which one would return to main
.
The 2nd BOF payload should look something like the following:
Null-byte Overwrite Cont'd (Leak LIBC)
Now that we have a way to reintroduce our info leak, we can use it for a LIBC leak. Figuring out the number of bytes required to leak the LIBC address is purely guesswork. Since the 64-bit calling convention requires the stack to be 16-byte aligned, I figured the next offset to try would be 40+16, as there is no way LIBC would live right beside the canary. Inspecting the rsi
using GDB also confirms our hypothesis.
Next, with 56 A's and some GDB vmmap shenanigans, we managed to retrieve the LIBC base address to perform a ret2libc
attack.
ret2libc
To summarise everything, we have a 4 stage payload:
Round 1, BOF 1: Leak canary via null-byte overwrite.
Round 1, BOF 2: ret2main via Partial Overwrite.
Round 2, BOF 1: Leak LIBC via null-byte overwrite.
Round 2, BOF 2: ret2libc.
Flag: ACS{15_y0ur_n1ckname_and_3ma1l_c0rre3tly_r3g15t3rd?}
Last updated