PWN Cheatsheet (Userland)
Complete binary exploitation reference for CTF - from dangerous functions to advanced exploitation techniques
December 15, 2025
•
December 13, 2025
•
Info
Dangerous Sinks
Input functions
| Hàm | Chức năng | Hành vi dừng & kết thúc | Nguy hiểm vì | Mức độ |
|---|---|---|---|---|
gets() | Đọc input từ stdin | Dừng khi gặp \n hoặc EOF, thay \n bằng \0 | Không kiểm tra buffer size, buffer overflow 100% | Critical |
scanf("%s") | Đọc chuỗi từ stdin | Dừng khi gặp whitespace (\n, space, \t), thêm \0 vào cuối | Không giới hạn độ dài, buffer overflow | Critical |
scanf("%[^\n]") | Đọc đến newline | Dừng khi gặp \n, thêm \0, không consume \n | Không giới hạn độ dài, buffer overflow | Critical |
read() | Đọc n bytes từ fd | Dừng khi đủ n bytes hoặc EOF, không thêm \0 | Không thêm null terminator, off-by-one nếu dùng như string | High |
fgets() | Đọc tối đa n-1 bytes | Dừng khi đủ n-1 bytes, gặp \n, hoặc EOF, thêm \0, giữ \n nếu có | An toàn hơn nhưng có thể off-by-one nếu tính sai size | Medium |
getchar()/fgetc() | Đọc 1 ký tự | Trả về 1 ký tự hoặc EOF | Cần kiểm tra EOF, có thể tràn nếu loop không đúng | Medium |
String copy/manipulation functions
| Hàm | Chức năng | Hành vi dừng & kết thúc | Nguy hiểm vì | Mức độ |
|---|---|---|---|---|
strcpy() | Copy chuỗi | Dừng khi gặp \0 trong src, thêm \0 vào dest | Không kiểm tra dest size, buffer overflow | Critical |
strcat() | Nối chuỗi | Tìm \0 trong dest, copy src đến đó, dừng khi gặp \0 trong src | Không kiểm tra dest size, buffer overflow | Critical |
sprintf() | Format vào buffer | Dừng khi format xong, thêm \0 | Không kiểm tra buffer size, buffer overflow + format string | Critical |
vsprintf() | sprintf với va_list | Dừng khi format xong, thêm \0 | Không kiểm tra buffer size, buffer overflow + format string | Critical |
strncpy() | Copy tối đa n bytes | Dừng khi đủ n bytes hoặc gặp \0, chỉ thêm \0 nếu src ngắn hơn n | Không đảm bảo null-terminate nếu src >= n bytes | High |
strncat() | Nối tối đa n bytes | Tìm \0 dest, copy n bytes từ src, luôn thêm \0 | Off-by-one: thêm \0 ngoài n bytes | High |
memcpy() | Copy n bytes | Copy đúng n bytes, không thêm \0, không dừng ở \0 | Không kiểm tra overlap, không null-terminate | Medium |
memmove() | Copy n bytes (safe overlap) | Copy đúng n bytes, không thêm \0, xử lý overlap | Không null-terminate | Medium |
snprintf() | Format vào buffer với limit | Dừng khi đủ n-1 bytes hoặc format xong, thêm \0 | Format string bugs, trả về số bytes “cần” (không phải đã ghi) | Medium |
String length/search functions
| Hàm | Chức năng | Hành vi dừng | Nguy hiểm vì | Mức độ |
|---|---|---|---|---|
strlen() | Đếm độ dài | Dừng khi gặp \0 | Không kiểm tra buffer boundary, crash nếu không có \0 | High |
strtok() | Tokenize string | Dừng khi gặp delimiter, thay delimiter bằng \0 | Modify input string, static internal state (not thread-safe) | Medium |
strstr() | Tìm substring | Dừng khi gặp \0 | Crash nếu strings không null-terminated | Medium |
Output functions
| Hàm | Chức năng | Hành vi dừng | Nguy hiểm vì | Mức độ |
|---|---|---|---|---|
printf(user_input) | Format output | Format theo format string | Format string attack: leak/write arbitrary memory | Critical |
fprintf(fp, user_input) | Format output to file | Format theo format string | Format string attack | Critical |
puts() | In chuỗi + newline | In đến \0, tự động thêm \n | An toàn cho output nhưng có thể leak data nếu không có \0 | Low |
write() | Ghi n bytes | Ghi đúng n bytes, không dừng ở \0 | An toàn cho output, nhưng có thể leak nếu n > actual data | Low |
Format string functions
| Hàm | Format specifiers nguy hiểm | Nguy hiểm vì | Mức độ |
|---|---|---|---|
printf/fprintf/sprintf | %n, %hn, %hhn | Ghi giá trị vào địa chỉ trên stack | Critical |
%x, %p, %s | Leak stack/heap/memory contents | Critical | |
%<number>$x | Direct parameter access, bypass stack | Critical |
Memory allocation/management
| Hàm | Chức năng | Nguy hiểm vì | Mức độ |
|---|---|---|---|
alloca() | Allocate trên stack | Không kiểm tra stack space, stack overflow | Critical |
malloc(user_size) | Allocate heap | Integer overflow trong size, heap overflow sau đó | High |
realloc() | Resize allocation | Use-after-free nếu fail, pointer invalidation | High |
free() | Giải phóng memory | Double-free, use-after-free bugs | Critical |
System/execution functions
| Hàm | Chức năng | Nguy hiểm vì | Mức độ |
|---|---|---|---|
system(user_input) | Execute shell command | Command injection, RCE | Critical |
exec*() family | Execute program | Command injection nếu dùng shell | Critical |
popen() | Execute command + pipe | Command injection | Critical |
dlopen()/dlsym() | Load shared library | Load arbitrary .so, code execution | Critical |
File operations
| Hàm | Chức năng | Nguy hiểm vì | Mức độ |
|---|---|---|---|
open() với O_CREAT | Tạo file | Race condition (TOCTOU), arbitrary file write | High |
fopen(user_path) | Mở file | Path traversal, arbitrary file read/write | High |
chmod()/chown() | Đổi permissions | Race condition, privilege escalation | High |
Integer vulnerabilities
| Loại lỗi | Pattern code | Input/Điều kiện | Kết quả | Exploit | Mức độ |
|---|---|---|---|---|---|
| Integer Overflow | Unsigned: size_t len = a + b;malloc(len);Signed: int total = count * size;malloc(total); | Unsigned: a = 0xFFFFFFFF, b = 1Signed: count = 0x40000000, size = 4 | Unsigned: len = 0Signed: total = 0 (wrap) | Allocate 0 bytes → heap overflow | Critical |
| Integer Underflow | Unsigned: size_t remaining = len - offset;memcpy(buf, src, remaining);Signed: int space = bufsize - used;if(space > 0) read(fd, buf, space); | Unsigned: len = 10, offset = 20Signed: used = -10, bufsize = 100 | Unsigned: remaining = 0xFFFFFFF6 (huge)Signed: space = 110 | Copy massive amount hoặc bypass check → overflow | Critical |
| Sign Confusion | Direct cast: void process(int size)malloc(size);Bypass check: if(size < MAX) malloc(size); với size là int | size = -1 | Direct: malloc(0xFFFFFFFF) → fail/hugeBypass: -1 < MAX → pass, cast thành unsigned huge | Allocate fail → NULL deref hoặc bypass check | Critical |
| Type Truncation | Downcast: size_t len = strlen(s);int n = len;Width mismatch: unsigned long len;read(0, &len, 8);char buf[len]; | Downcast: len = 0x100000001Width: len = 0x1FFFFFFFF | Downcast: n = 1Width (32-bit): buf[0xFFFFFFFF] | Dùng truncated value → undersize buffer/stack overflow | Critical |
| Width Confusion | uint32_t a; uint64_t b;b = a * 1000; | a = 5000000 | Overflow trong multiply trước cast | Silent overflow | High |
| Off-by-one via Underflow | for(i = len-1; i >= 0; i--) với size_t i | len = 0 | i = 0xFFFFFFFF (never stop) | Infinite loop, OOB access | High |
Exploitation Techniques
Initial checklist
Checklist:
- Libc version → offsets, heap mechanics; Libc GOT overwrite (glibc < 2.39)
- Seccomp → xác định syscalls bị chặn
- NX disabled → có thể dùng shellcode
- PIE disabled + Partial RELRO → GOT overwrite
- PIE enabled → cần leak binary base
- Full RELRO → GOT read-only, không có GOT overwrite
- Static binary → khó phân tích (binary lớn), không có GOT/PLT, không cần leak libc
Information leaking
Chung: Overread qua output functions (puts, printf, write) để leak data từ stack/heap
Libc leak
- Unsorted bin/Smallbin: UAF hoặc uninitialized allocate → fd/bk pointer trỏ về main_arena
- Heap overflow: overflow để leak unsorted bin pointers
- GOT entry: leak địa chỉ hàm đã được resolve (puts, printf, read,…)
- Format string:
%sđể đọc GOT entry hoặc libc addresses từ stack - Overread: vùng có libc addresses (stack, GOT, heap)
Xác định libc version: Leak nhiều hàm từ GOT, tra libc database (https://libc.rip/)
Heap leak
- Tcache/Fastbin UAF: fd pointer trỏ đến chunk tiếp theo (glibc ≥ 2.26)
- Largebin: fd_nextsize/bk_nextsize chứa heap addresses
- Uninitialized allocate: malloc không zero memory
- Heap overflow: đọc metadata chunk khác
- Format string: leak heap pointer từ stack
- Overread: vùng có heap pointers
Stack leak
- Format string:
%phoặc%xđể leak stack values - __environ: pointer → environ trên stack → tính stack address
- Stack overflow: overread để leak data
- Overread: vùng có stack addresses, canary, return address
PIE leak
- Format string: leak return address hoặc function pointer từ stack
- __environ → AAR: đọc return address trên stack
- Function pointer: leak địa chỉ hàm từ GOT/BSS
- Heap overflow: leak function pointer nếu có trên heap
- Overread: vùng có PIE-relative addresses
Canary leak
- Format string: canary thường ở stack offset cố định
- Stack overflow: overread để leak canary
- __environ → AAR: đọc canary từ stack
- TLS manipulation: ghi vào TLS section để overwrite canary
Arbitrary read/write
AAW (Arbitrary Address Write)
- Format string:
%nđể ghi - Tcache poisoning: overwrite tcache->next → malloc trả về địa chỉ bất kỳ
- Fastbin attack: overwrite fd, cần fake size hoặc fill tcache
- Unsorted bin attack: ghi main_arena address qua bk pointer
- Heap overflow: overwrite metadata để control allocation
- OOB: array index không check bound
- FSOP: manipulate FILE structure
AAR (Arbitrary Address Read)
- Format string:
%svới địa chỉ trên stack - Tcache/Fastbin control: allocate tại địa chỉ muốn đọc
- Heap overflow: đọc metadata chunk khác
- OOB: đọc ngoài bound
- FSOP: manipulate FILE structure
Code execution
Shellcode (NX disabled)
- Ghi shellcode lên stack/heap/bss (vùng có quyền X)
- Nhảy đến shellcode qua return address/GOT overwrite
- Shellcode staging: shellcode nhỏ đọc shellcode lớn
- Lưu ý: kiểm tra seccomp (có thể cần ORW thay execve), shellcode có thể chứa null
Return-oriented Programming (ROP)
- Stack alignment: RSP align 16 bytes trước call
- RBP: cần hợp lệ (không null/invalid)
- Register control: control đủ registers cho function call
- Stack pivoting: pivot RSP đến BSS/heap/GOT
- SROP: rt_sigreturn để set toàn bộ registers
One-gadget / Magic gadget
- Kiểm tra constraints trước dùng (có thể cần ROP setup)
- Stack alignment vẫn critical
- Tiện nhưng ROP vẫn ổn định hơn, trên remote chưa chắc đã chạy được.
System() call
- Overwrite GOT: hàm control được (puts, printf, setvbuf) → system
- Setup RDI: “/bin/sh” (có trong libc)
- Stack alignment 16 bytes: critical, có thể cần RBP hợp lệ
Hooks (glibc ≤ 2.34)
- Function pointers:
__malloc_hook,__free_hook,__realloc_hook - Leak libc → overwrite hook → trigger malloc/free/realloc
FSOP (File Stream Oriented Programming)
- Manipulate
_IO_FILEstructure - Trigger qua exit(), fclose(), overflow
- _IO_vtable_check bypass (modern glibc)
- House of Apple/Kiwi: modern FSOP techniques
Libc GOT Overwrite
https://github.com/n132/Libc-GOT-Hijacking
Heap exploitation
Tcache (glibc ≥ 2.26)
- Tcache poisoning: overwrite fd → malloc return arbitrary address
- Tcache dup: double free (glibc < 2.29 không check)
- Tcache key bypass: overwrite key field để bypass double-free check (glibc ≥ 2.29)
- Struct location: heap_base + 0x10
Fastbin
- Fill tcache: để chunk free vào fastbin
- Fastbin attack: overwrite fd, cần fake size
- Fastbin dup: double free → allocate cùng chunk 2 lần
- House of Spirit: fake chunk (stack) → free() → allocate
Unsorted bin / Smallbin / Largebin
- Fake chunk: fake size để free vào bin (lưu ý prev_inuse chunk sau)
- Unsorted bin attack: ghi main_arena+offset qua bk pointer (dùng để leak/AAW)
- Largebin attack: overwrite fd_nextsize → arbitrary write
- House of Einherjar: consolidate qua fake prev_size
House of techniques
https://github.com/shellphish/how2heap
Lưu ý
- Alignment 16 bytes (64-bit): Tất cả bins (tcache, small, large, unsorted, fast) - địa chỉ trả về chia hết cho 16, kích thước chunk là bội số 16
- Tạo padding chunk (rào chắn top chunk) tránh merge khi free
- Unsorted bin attack corrupt list → chỉ dùng 1 lần
- Safe-linking (glibc ≥ 2.32): fd được mangle
(chunk_addr >> 12) ^ real_fd→ cần heap leak để decode/encode
Advanced techniques
Race condition
- TOCTOU (Time-of-Check-Time-of-Use): Check lúc A nhưng sử dụng lúc B → race thay đổi giữa 2 lúc
- Shared variable: Nhiều thread dùng chung biến toàn cục → data race → corruption
- Exploit: Tạo nhiều threads để race condition
Seccomp bypass (alternative syscalls)
| Mục đích | Syscall chính | Syscall thay thế | Ghi chú |
|---|---|---|---|
| Mở file | open | openat, creat, open_by_handle_at | openat linh hoạt hơn với dirfd |
| Đọc file | read | readv, pread64, preadv, preadv2 | preadv đọc từ offset cụ thể |
| Ghi file | write | writev, pwrite64, pwritev, pwritev2 | writev ghi nhiều buffer cùng lúc |
| Đóng file | close | close_range | close_range đóng nhiều fd cùng lúc |
| Spawn shell | execve | execveat | execveat cho phép exec từ fd |
| Tạo process | fork | clone, clone3, vfork | clone linh hoạt hơn fork |
| Copy data | read + write | sendfile, splice, copy_file_range | Transfer trực tiếp giữa fd |
| Quản lý memory | mmap | mmap2, mremap, remap_file_pages | mprotect để thay đổi permission |
| Lấy thông tin file | stat | fstat, lstat, newfstatat, statx | statx là version mới nhất |
| Thay đổi directory | chdir | fchdir | fchdir dùng fd thay vì path |
| Đổi tên/di chuyển | rename | renameat, renameat2 | renameat2 có thêm flags |
| Xóa file | unlink | unlinkat | unlinkat có thể xóa cả directory |
| Tạo directory | mkdir | mkdirat | mkdirat relative to dirfd |
| Socket operations | socket, connect | socketpair, accept, accept4 | Để network communication |
| Đọc directory | getdents | getdents64 | List files trong directory |
Partial overwrite
- Overwrite 1-2 byte cuối để nhảy đến địa chỉ gần
- Dùng khi không đủ overflow
- Có thể cần brute-force ASLR
Stack pivoting
Dùng leave; ret gadget để pivot RSP đến GOT/BSS/heap
Sau khi pivot:
- Tiếp tục ROP chain: dùng gadgets từ vùng mới để gọi functions, setup registers
- Thực thi shellcode: nếu pivot đến heap/BSS có shellcode sẵn sàng
RWX segment creation
mprotect(addr, len, PROT_READ|PROT_WRITE|PROT_EXEC)qua ROPmmap(NULL, size, PROT_READ|PROT_WRITE|PROT_EXEC, ...)- Compile với
-z execstack(rare)
TLS/Thread manipulation
- Malloc large size (>0x21000): mmap ngay trước TLS → heap overflow, hay OOB để:
- Leak/Overwrite TLS: main canary, master canary, tcache perthread struct, stack guard
Random number prediction
- Predict random() output
- Overwrite seed trong memory
- Predict dùng
ctypefunctions - Time-based seed: brute-force time()