バイナリ萌えの彼女がシンボリック実行に恋着してますが、制約に挑む幼気な表情が最高です!(1)

 バイナリ萌えの彼女がシンボリック実行に恋着してますが、制約に挑む幼気な表情が最高です!(1)

【あらすじ】
高校2年生の二木双葉は、CTF(情報セキュリティの競技の一つ)ではバイナリ問題を担当する女の子。ある日チームメイトにangrを紹介されたことで、シンボリック実行に目覚める…

【今回の話】
Day 1 双葉はangrに出会う
Day 2 双葉のシンボリック実行エンジンを自作してみた

【次回】
Girls Meets Symbolic Execution: Assertion 2. Automated Exploit Generation
https://speakerdeck.com/katc/girls-meets-symbolic-execution-assertion-2-automated-exploit-generation

【改訂履歴】
2017/10/31 スライドに著作権表記ないしはタイトルを追加。体裁を微調整。

※上のタイトルから「い」が抜けていた。悲しい

09cdb8323ed1eecee2f93d1f078143ca?s=128

友利奈緒(@K_atc)

October 29, 2017
Tweet

Transcript

  1. 〈ダイジェスト版〉 © 2017 K_atc.

  2. プロフィール 著者 友利奈緒(@K_atc) TomoriNaoのTomoriNao。 趣味はバイナリ、CTF、イラスト、デザインと多岐にわたる。 イラスト K_atc イラスト歴5年。二次創作を中心に活動。著者と同一人物。 TomoriNaoの同人誌のイラストを担当。 https://www.pixiv.net/member.php?id=4440209

    2 バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)
  3. 高校2年生の二木双葉は、CTF(情報セキュリティの競技の一つ)で はバイナリ問題を担当する女の子。ある日チームメイトにangrを紹 介されたことで、シンボリック実行に目覚める… メインヒロイン 二木 双葉(ふたき ふたば) 高校2年生。17歳。 部屋着のレパートリーが多いらしい。 身長:166

    cm 得意な科目:化学 好きな食べ物:シュークリーム 好きな言葉:「バイナリおいしい」 あらすじ&登場人物紹介 3 バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)
  4. Day 1 双葉はangrに出会う Day 2 双葉のシンボリック実行エンジンを自作してみた 双葉ちゃんからの問題(=宿題) 目次 4 バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)

  5. シンボリック実行は入力値をシンボル化して実行する形態をいう。 シンボルとは数学的に表現された値で、一定の値に固定されない。 シンボリック実行ではレジスタ、スタック、メモリ、ファイル等、 あらゆるものがシンボル化される。 命令を評価する度に、シンボル値に制約を追加する。目的の地点に プログラムカウンタが到達したら制約を解き具体的な値を得る →そこに至る入力条件が明らかになる【シンボリック実行の肝】 シンボリック実行エンジンは上記を実行するコアのこと。 主要なシンボリック実行エンジン(年は主要論文を基準とする) •

    angr(2016年;Shellphish/UCSBのSecLab) • KLEE(2008年;スタンフォード大学) シンボリック実行とは 5 バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)
  6. angrはpythonのモジュールとして動作。 pip install angr でインストールできる。 (see https://github.com/angr/angr) Day 1 angrをインストールする双葉

    6 簡単にインストールできるのね。簡単なの解析させてみようかな? バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)
  7. Day 1 双葉のサンプルプログラム #include <stdio.h> #include <string.h> void correct(void) {

    puts("correct"); } int main() { char buf[32]; fgets(buf, sizeof(buf), stdin); if(strcmp(buf, "flag{angr_makes_it_easy}") == 0) { correct(); } return 0; } 7 ※完全なコードは https://github.com/Futaki-Futaba/angr-sample にあります futaba% gcc –o sample sample.c バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)
  8. Day 1 双葉のソルバースクリプト import angr # 解析対象をロード ELF_FILE = "./sample"

    proj = angr.Project(ELF_FILE, load_options={'auto_load_libs': False}) state = proj.factory.entry_state(args=[ELF_FILE]) # 初期ステート生成 simgr = proj.factory.simgr(state) # Simulation Managerを初期化 simgr.explore(find=lambda p: “correct” in p.state.posix.dumps(1)) # 探索 for i, found in enumerate(simgr.found): print “#%d stdin: %r” % (i, found.state.posix.dumps(0)) # 結果をダンプ futaba% ./sample-solve.py #0 stdin: 'flag{angr_makes_it_easy}¥x00 ¥x80¥x10¥x0 ... snipped ... 8 バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)
  9. プロトタイプなので、実行ターゲットの仕様はこんな感じ: • Intel x86_64をベースにする • サポートする命令はごく一部のみ • メモリ参照無し。dst, src オペランドはレジスタと即値のみ

    • pcは現在実行している命令のアドレスを指す(※本家と異なるので注意) • フラグレジスタはZF、SF、OFに限定 シンボリック実行エンジンの仕様: • z3py(制約ソルバーz3*のPython向けバインディング)ベース • 命令はデコードされている Day 2 Intel、双葉ってる 9 *z3 Z3Proverとも。“z3py”か“z3 prover”でググるとよい。(申し訳程度のMicrosoft要素) スポンサー バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)
  10. 全体の基本解析フロー(双葉1号とする): Day 2 双葉はシンボリック実行エンジンを設計する Execution Loop 命令を評価 初期State Active States

    更新済State State push pop push Active Statesが空 または 時間切れ …Stateの集合 State 現在のレジスタ、スタック、 メモリの状態をシンボル値や 具体値で表したものの集合 (スナップショットに近い) Stateが複数になることも 無くなることもある 解析終了 求解 ここで 制約追加OK 解析開始 10 バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)
  11. State Branching: 条件分岐を含んだコードの実行例 xの値を場合分けして子のStateを生成→条件分岐に対処! Day 2 双葉はシンボリック実行エンジンを設計する if (x <

    5) {…} … x = α (α : Int) code α < 5 α ≧ 5 true false SymExec S S'T S'F … Symbolize x (declare α) … if statement 11 バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)
  12. Execution Loop (双葉1号とする) : Day 2 双葉は実装上の問題点に気づいた 問題点1:レジスタのシンボル化をどう実現するか? 問題点2:命令をどう数学的に表現するか? ActiveStates

    ← {S_init}, SuccessStates ← φ while ActiveStates ≠ φ: Dequeue S from ActiveSates according R // Rはヒューリスティック関数 p is program counter of S I ← FetchInstruction(p) S* ← Eval(I, S) for S’ in S*: next_pc is program counter of S’ if next_pc in find: // findに至るStateは成功→あとで求解 SuccessStates ← SuccessStates ∪ {S’} else: ActiveStates ← ActiveStates ∪ {S’} // そのStateで解析を継続 return assertions of SuccessStates // それぞれのStateの制約集合のみ返す 12 1 2 バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)
  13. レジスタのシンボル値をあるシンボル変数に固定化すると、 値の書き換えを表現できない(循環参照のような状態に…) symvar_rax := symvar_rax + 1 ✕NG 解決策: レジスタの名前をキーとして、そのレジスタの現在のシンボル値を

    管理する cur_rax = GetReg(“rax”) new_rax = BitVector(“new_rax”, 64) // generate new symvar new_rax := cur_rax + 1 // assume new_rax == cur_rax + 1 StoreReg(“rax”, new_rax) // GetReg(“rax”) => new_rax Day 2 問題点1:レジスタのシンボル化をどう実現するか? 13 バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)
  14. 制約ソルバーz3はIntelの命令を直接理解できない ➡ and, or, <, >, ==, !=, +, -

    と数値・真偽値で頑張って表現する これが命令にセマンティクス(Semantics)を与える作業にあたる Day 2 問題点2:命令をどう数学的に表現するか? 14 はわゎ、IntelのISAマニュアル読みますぅ バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)
  15. symexec.pyから抜粋 ※簡略化してある Day 2 セマンティクスの例:jz命令 ZF = get_flag_symvar("ZF") solver.push() #

    現在のソルバーの状態を退避 Add_Constraint(ZF == False) # ジャンプしないという制約を追加 S_false = Dump_State(next_pc, pc) solver.pop() # ZF == False を追加する前の状態を復元 solver.add(ZF == True) # ジャンプするという制約を追加 S_true = Dump_State(next_pc + dst, pc) # + dst でジャンプを表現 return [S_false, S_true] # State Branching jz dst (dstは即値) Dump_State(pc, prev_pc) は、現在のソルバーへの制約集合とレジスタのダンプに pcと1つ前のpcの情報を付加する ZF*が立っていればpcをdstだけ進める分岐命令 *ZF = Zero Flag Register 15 バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)
  16. Day 2 「できたー!」 BITS 64 cmp rsi, 1 jl check

    loop: add rdx, rdx dec rsi jnz loop check: cmp rdx, rax je clear ret clear: nop futaba% ./test.py … snipped … [*] adding some initial state assertions: [init_rsi == 3] … snipped … ---------------------------------------- [*] loading assertions which leads success state. let’s check [*] adding constraints to current state [init_rax == 16] [*] sat check: sat [*] solution for (rsi, rdx, rax): rsi = 3 rdx = 2 rax = 16 rsi = 3, rax = 16 のとき clear に至る rdx の初期値は? rdx * (2 ** rsi) == rax ? 16 2 ✕ 23 = 16 OK! バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)
  17. シンボリック実行は、 • シンボル化しながら命令を逐次実行する(方式もある) • 特定条件を満たす入力を半自動的に求めることができる • いろいろ諦めれば自作は難しくないが、ロジック設計が難しい 双葉ちゃんの自作シンボリック実行エンジン: https://github.com/Futaki-Futaba/symexec-engine-modoki 双葉ちゃんからの問題

    (1) 双葉1号はループに嵌まると、findに至らないステートが無限 に生成されて停止しません。どう対処すればよいでしょうか? (2) z3は求解段階で解を1つに固定化してしまいます。複数の解を 得たいときはどうすればよいでしょうか? まとめ&宿題 ぜひブログ等でご回答ください! 17 バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)
  18. • Drew Davidson et al., FIE on Firmware: Finding Vulnerabilities

    in Embedded Systems Using Symbolic Execution, USENIX Security Symposium, 2013. https://www.semanticscholar.org/paper/FIE-on-Firmware-Finding- Vulnerabilities-in-Embedde-Davidson- Moench/b642d797f87d6a5c875acb7c43e2f057daf386a9 • JonathanSalwan/Triton, https://github.com/JonathanSalwan/Triton 参考資料 18 バイナリ萌えの彼女がシンボリック実行に恋着していますが、制約に挑む幼気な表情が最高です!(1)