LACTF 2024: pizza
yummy
Last updated
yummy
Last updated
Classic Format String GOT Overwrite - Abuse read primitive of
printf()
to leak canary, LIBC and PIE addresses, followed by GOT overwrite to execute asystem(/bin/sh)
call.
The challenge starts with a given Dockerfile, but without the LIBC.
The LIBC file can be retrieved from the Debian image via Docker volume as a shortcut.
Using o12/pwninit to patch the binary yields an error due to the lack of support for EGLIBC.
I found another fork of pwninit written in Python that supports EGLIBC, so I went with that instead.
Pizza is a menu-style challenge that prompts the user for 3 pizza toppings.
Interestingly enough, it supports custom toppings! These custom user inputs are then echoed back to us, indicating something fishy that leans toward an info leak primitive.
Inspecting the binary protection shows that Partial RELRO is enabled, meaning GOT overwrite is possible. Another thing to take note is PIE is enabled as well, meaning we would need an info leak to retrieve both LIBC and PIE addresses.
An obvious format string vulnerability exists when a custom topping is added. Since our user input is reflected back to us, we essentially have both Read & Write primitives to play with.
Recall that Partial RELRO is enabled on the GOT; This is a classic scenario where we can overwrite the GOT entry with something like system()
to get a shell.
But first, we need to figure out the offset where the first positional argument occurs. To do this, input a bunch of A's followed by the pointer %p
specifier. Since our initial input of A's showed up on the 6th address, this will be our offset.
Before we overwrite the GOT, there are 2 info leaks required to formulate our payload - Remember, GOT entries are affected by PIE, and system()
comes from LIBC which has ASLR enabled on the remote instance.
We can fuzz these offsets to understand where the leaks occur using a similar script from a previous writeup of SiberSiaga 2023: Password Generator. We'll skip forward this step, but PIE and LIBC can be found from offsets 49 and 47 respectively.
Next is to calculate how far these addresses are from their respective base addresses; the value for this will always remain as a constant throughout different runs.
Putting everything together - the read primitive info leaks has to come first before we make use of pwntool's fmtstr_payload()
to construct our payload.
Flag: lactf{golf_balls_taste_great_2tscx63xm3ndvycw}