saotake’s blog

-竿竹-

angr on PythonをCTFに使う

Defcon2016のbaby-re、write-upを見ていると、私のように真面目に連立方程式を解いているパターンの他に、angrというフレームワークを使って自動解析して解いているパターンが多く見受けられました。そこで、angrの勉強をしてみました。

 

angr公式:

angr, a binary analysis framework

 

angrインストール方法:

https://github.com/angr/angr-doc/blob/master/INSTALL.md

 

□angrとは?

angr is a framework for analyzing binaries. It focuses on both static and dynamic symbolic ("concolic") analysis, making it applicable to a variety of tasks.(公式より)

 angrはバイナリ解析のフレームワークです。静的解析と動的解析の両方に対応しており、いろいろな用途に適用できます。

 

□CTFへのangrの適用

プログラムを実行したときに、特定の条件を満たす(FLAGが表示される)ような入力を探すとき、ブルートフォースとは違い、アセンブリの構造を解析してあるアドレスに到達するメモリ状態を調査してくれるため、ブルートフォースとは比較にならないくらいなようです。

 

□angrのインストール( on Ubuntu)

インストール方法に書いてることをまとめると、以下の通りとなります。私の環境ではこれでうまくいきましたが、CTF用のPCはあまりメンテされていないことが多いので、事前に、apt-get install --upgradeをしておくとよいと思います。

 

$ sudo apt-get install python-dev libffi-dev build-essential virtualenvwrapper

$ mkvirtualenv angr

(angr)$ pip install angr 

 

□angrの実行方法

 

まずはコマンドラインで使ってみて、動くことを確認しましょう。

$ mkvirtualenv angr

(angr)$ python

 >>> import angr
>>> p = angr.Project('./baby-re')
>>> a = p.surveyors.Explorer(find=0x40294b,avoid=0x402941).run()
>>> a.found[0].state.posix.dumps(1)
'Var[0]: Var[1]: Var[2]: Var[3]: Var[4]: Var[5]: Var[6]: Var[7]: Var[8]: Var[9]: Var[10]: Var[11]: Var[12]: The flag is: Math is hard!\n'
>>>

 解けました。解けてしまいました。

私は6時間かけて解いたのですが、angrなら4行3分で解けました。これはすごい。

 

□angrの簡単な解説

上記の例でいうと、angrに解析の条件として渡しているのは、以下の二つだけです。

find=0x40294b

↑プログラムが0x40294b(flagを表示しているあたりのアドレス)に到達するような条件を検索するよう指定。

 

avoid=0x402941

 ↑プログラムが0x402941(Wrongと表示されるあたりのアドレス)は通らないよう指定。

 

これにより、「Wrongと表示しないようにしながら、Flagを表示するような条件を探せ」という解析になります。

 

なお、Writeupによってはメモリ表示でflagを表示しているところもありますが、findの検索条件をきちんとflag表示部分に指定すれば、dump(画面出力)でOKです。(逆に、findの条件をflagを表示するよりも前にしてしまうと、dumpにflagが表示されず、メモリを表示させるしかありません)

 

□angrだとどれくらい早いか?

実行するPCにもよりますが、私のUbuntuOnVMware(ksスペック)でもかなり早いです。

  • angrを使わない、単純なブルートフォースの場合
    そもそも入力が何桁の数字なのか、符号付なのか、最大何ビットなのか、という条件がわからないので、あたりを付けるところから始めなければなりません。仮に、asciiコード(32~126の間)だと目星がついていたとしても、およそ、100の13乗/2の回数の計算が必要になります。仮に1回0.01秒だとして、
    ( (100^13) /2)回 * 0.01 秒/回 = 1京年以上
    くらいの時間がかかります。(間違ってたらすみません)

  • angrだと?(findとavoidを指定)
    上で紹介したプログラムだと、私のPCでも3分程度で解けました。

  • angrをうまく使う(find,avoid以外にもいろいろ指定)
    angrは、find,avoid以外にもいろいろ指定できます。こちらのwriteupでは、解析開始アドレス、BasePointerアドレス、スタックアドレス、入力アドレスなどを事前に調査して指定してやることで、解析をより高速にしています。
    このコードの場合、10秒程度で解けてしまいます。