Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Reversing基礎編 / Basics of Reversing - SECCON Beg...

Hi120ki
September 11, 2022
1.9k

Reversing基礎編 / Basics of Reversing - SECCON Beginners Live 2022

SECCON Beginners Live 2022 発表スライド
https://connpass.com/event/258217/

Hi120ki

September 11, 2022
Tweet

Transcript

  1. 自己紹介 Hi120ki - Hiroki Akamatsu 大阪大学大学院 情報科学研究科 修士1年 大阪大学CTFサークル Wani

    Hackase 所属 Web・Reversing担当 【Web】Util, Ironhand 【Rev】Quiz, Recursive, Ransom WaniCTFのインフラ担当 CTF大会開催はいいぞ - 魔女のお茶会 2021冬 Reversing基礎編 - SECCON Beginners Live 2022 2
  2. 1. Reversingとは Reverse Engineeringとも言われ,機械や製品・プログラムの内部の構造や 動作を解析すること CTFではプログラムや特定の形式のファイルを解析します (例) 実行可能ファイル(Executable file) Linux

    ELF Windows PE モバイルアプリ APK(Android Application Package) スクリプトファイル pcapファイル ファームウェア Reversing基礎編 - SECCON Beginners Live 2022 5
  3. 出題傾向 Linux ELF 2020 : mask yakisoba sneaky 2021 :

    only_read children please_not_trace_me be_angry firmware 2022 : Quiz Recursive Ransom Windows PE 2022 : WinTLS APK 2020 : siblangs スクリプトファイル 2020 : ghost pcapファイル 2022 : Ransom ファームウェア 2021 : firmware 特にBeginner~Easy難易度はLinux ELFファイルの出題がほとんど Reversing基礎編 - SECCON Beginners Live 2022 6
  4. ELFファイルとは Executable and Linkable Formatの略 多くのLinux系やBSD系のOSで実行ファイル形式として採用されている C言語でソースコードを記述し,コンパイラのgccで作成できる gcc main.c -o

    a.out 実行権限を与えた上で実行すると,ソースコード main.c に記述された処理が実 行される chmod +x ./a.out # 実行権限を与える ./a.out # 実行する Reversing基礎編 - SECCON Beginners Live 2022 7
  5. ELFファイル解析でよく使うツール 1. 表層解析 fileコマンド : ファイル形式を推測 stringsコマンド : ファイルに含まれる可読文字列を表示 2.

    静的解析 Ghidra : NSAによって開発されているOSSの解析ツール IDA : Hex Rays社によって開発されている有償(機能が制限された無償版もあ り)の解析ツール 3. 動的解析 GDB : GNU Project debugger 特にLinuxではデファクトスタンダードなデ バッグ&動的解析ツール Reversing基礎編 - SECCON Beginners Live 2022 11
  6. 4. ツールのインストール インストールにあたっての準備 fileとstringsはLinuxのコマンドで,GDBはLinux上で動作 → Linux環境が必要 CTFでは色々なツールをインストールしていくことになり,ライブラリのバー ジョンの衝突で動かなくなったり,動作が不安定になることがよくある → CTF環境は「リセットしやすいもの」を選び構築するのがおすすめ

    1つのアプローチ VirtualBoxとVagrantでいつでもCTF環境となるLinux仮想マシンを立ち上げ る・リセットできるようにする よく使うツールを自動インストールするAnsible Playbookやシェルスクリプ トを用意し自分のCTF環境を再現できるようにする ホストとの共有ディレクトリの中で作業しCTF環境が突然動かなくなってもフ ァイルは復元できるようにする Reversing基礎編 - SECCON Beginners Live 2022 12
  7. 4-1. 表層解析ツール fileコマンド, stringsコマンド POSIXコマンドなのでLinuxでは標準インストールされている (今回の資料はUbuntu 20.04.4 LTSで作成) $ file

    --help Usage: file [OPTION...] [FILE...] Determine type of FILEs. $ strings --help Usage: strings [option(s)] [file(s)] Display printable strings in [file(s)] (stdin by default) Reversing基礎編 - SECCON Beginners Live 2022 13
  8. 4-2. 静的解析ツール Ghidra https://ghidra-sre.org/ 1. https://jdk.java.net/やhttps://adoptium.net/からJDKをダウン ロードしインストールする 2. GithubのReleaseページから最新のバージョンのzipファイル ghidra_<

    バージョン >_PUBLIC_< 日付 >.zip をダウンロードし展開する 3. Windowsなら ghidraRun.bat をクリックし,MacOSとLinuxは Terminalから ./ghidraRun で実行する (Armプロセッサを搭載したMacについては公式のInstallation Guideを参照 してください) Reversing基礎編 - SECCON Beginners Live 2022 14
  9. 4-3. 動的解析ツール GDB aptからインストール $ sudo apt update $ sudo

    apt install gdb $ gdb --version GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2 (最新版はhttp://ftp.gnu.org/gnu/gdb/からソースコードを入手できます) Reversing基礎編 - SECCON Beginners Live 2022 15
  10. GDBプラグイン Peda GEF PwndbgといったGDBを拡張するプラグインが公開されている これらをまとめてインストールできるスクリプト https://github.com/apogiatzis/gdb-peda-pwndbg-gef が便利 $ gdb-peda $

    gdb-pwndbg $ gdb-gef これらのコマンドから各プラグインが適用された状態のGDBが起動する Reversing基礎編 - SECCON Beginners Live 2022 16
  11. 5. ツールの使い方 表層解析ツールでは2022年出題 Quiz https://github.com/SECCON/Beginners_CTF_2022/raw/main/reversi ng/quiz/files/quiz 静的解析ツールでは2021年出題 only_read (by n01e0)

    https://github.com/SECCON/Beginners_CTF_2021/raw/main/reversi ng/only_read/files/chall 動的解析ツールでは2021年出題 please_not_trace_me (by n01e0) https://github.com/SECCON/Beginners_CTF_2021/raw/main/reversi ng/please_not_trace_me/files/chall を実際に解きながら紹介します Reversing基礎編 - SECCON Beginners Live 2022 17
  12. 5-1. 表層解析ツール fileコマンド $ file quiz quiz: ELF 64-bit LSB

    shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=3c3ecb93f6ca813352964076835ff6712fe9554e, for GNU/Linux 3.2.0, not stripped x86-64環境で動作するELFファイル Reversing基礎編 - SECCON Beginners Live 2022 18
  13. stringsコマンド $ strings quiz /lib64/ld-linux-x86-64.so.2 ... ctf4b{w0w_d1d_y0u_ca7ch_7h3_fl4g_1n_0n3_sh07?} Welcome, it's time

    for the binary quiz! Q1. What is the executable file's format used in Linux called? Linux 1) ELM 2) ELF 3) ELR Answer : %2s%*[^ answer length must be 1. ... 本来クイズに答えないと表示されないフラグ文字列がそのままバイナリ内にあ るため,stringsコマンドで取得できる (難しい問題はそのままバイナリ内にフラグが埋め込まない工夫がされている) Reversing基礎編 - SECCON Beginners Live 2022 19
  14. 5-2. 静的解析ツール Ghidraの使い方を紹介 1. 起動後File→New Projectを選択 2. Non-shared projectを選択 3.

    適当なProject DirectoryとProject Nameを入力 4. Tool Chestの緑のアイコンをクリック 5. File→Import Fileから配布バイナリを選択 6. 「analyze now?」にYes 7. Analysis OptionはデフォルトでOK 8. 左の真ん中のSymbol TreeのFunctionsを展開しmainを選択 9. 真ん中に逆アセンブル結果,右に逆コンパイル結果が表示される Reversing基礎編 - SECCON Beginners Live 2022 20
  15. (解法1) 逆アセンブル結果を見る アドレス バイナリ 命令 オペランド 001011c9 ba 17 00

    MOV EDX,0x17 00 00 001011ce 48 89 c6 MOV RSI,RAX アドレス : メモリの中で命令が格納される番地.メモリの中に格納された命令 は基本的に順番に実行されていくがJNZ命令などで任意のアドレスの命令を実 行していくようにすることもできる バイナリ : ELFファイルの中身で命令とオペランドに対応するものが表示され ている 命令 : メモリのアドレスや中身・レジスタ・固定の値を引数(オペランドと呼 ぶ)として行われる処理の名称.MOV命令は第2オペランドの値を第1オペラン ドにコピーする レジスタ : CPUと⾼速にデータのやり取りができる記憶素子.EDX, RSI, RAX はレジスタの1種 Reversing基礎編 - SECCON Beginners Live 2022 35
  16. 001011c5 48 8d 45 e0 LEA RAX=>local_28,[RBP + -0x20] 001011c9

    ba 17 00 MOV EDX,0x17 00 00 001011ce 48 89 c6 MOV RSI,RAX 001011d1 bf 00 00 MOV EDI,0x0 00 00 001011d6 e8 b5 fe CALL <EXTERNAL>::read ff ff (LEA命令は第2オペランドのアドレスを第1オペランドにコピーする) このとき 第1引数 EDIには読み込むデータの種類として標準入力を指定 第2引数 RSIには書き込み先メモリ領域のアドレス 第3引数 EDXには読み込む文字数の0x17 とし,関数を呼び出すCALL命令で read を指定することで,標準入力から 0x17(=23)文字読み込みメモリ内に保存する処理が実行される Reversing基礎編 - SECCON Beginners Live 2022 36
  17. 001011e0 0f b6 45 e0 MOVZX EAX,byte ptr [RBP +

    local_28] 001011e4 3c 63 CMP AL,0x63 001011e6 0f 85 da JNZ LAB_001012c6 00 00 00 001011ec 0f b6 45 e1 MOVZX EAX,byte ptr [RBP + local_28+0x1] 001011f0 3c 74 CMP AL,0x74 001011f2 0f 85 ce JNZ LAB_001012c6 00 00 00 ... そしてメモリ内に保存された入力文字列を1byteずつEAXにコピーして 0x63 や 0x74 と比較している 0x63 0x74 0x66 0x34 は文字コードの標準的な規格であるアスキー文字として c t f 4 と対応する → CMP命令で比較している数値を順番にアスキー文字として変換するとフラ グ文字列 ctf4b{c0n5t4nt_f0ld1ng} が得られる Reversing基礎編 - SECCON Beginners Live 2022 37
  18. (解法2) Ghidraの右のDecompile画面を見る if (((((((char)local_28 == 'c') && (local_28._1_1_ == 't'))

    && (local_28._2_1_ == 'f')) && (((local_28._3_1_ == '4' && (local_28._4_1_ == 'b')) && ((local_28._5_1_ == '{' && ((local_28._6_1_ == 'c' && (local_28._7_1_ == '0')))))))) && (((char)local_20 == 'n' && ((((((local_20._1_1_ == '5' && (local_20._2_1_ == 't')) && (local_20._3_1_ == '4')) && ((local_20._4_1_ == 'n' && (local_20._5_1_ == 't')))) && ((local_20._6_1_ == '_' && ((local_20._7_1_ == 'f' && ((char)local_18 == '0')))))) && (local_18._1_1_ == 'l')))))) && ((((local_18._2_1_ == 'd' && (local_18._3_1_ == '1')) && ((char)local_14 == 'n')) && ((local_14._1_1_ == 'g' && (local_12 == '}')))))) { puts("Correct"); } Ghidraに付属する逆コンパイラにより,処理がC言語のような擬似的なコード で表示される → 一文字ずつ c t f 4 ...と比較してすべて一致すれば Correct と出力するコ ードなので文字をつなげることでフラグ文字列 ctf4b{c0n5t4nt_f0ld1ng} が得ら れる Reversing基礎編 - SECCON Beginners Live 2022 39
  19. 5-3. 動的解析ツール GDBの使い方を紹介 0. 表層解析・静的解析 1. バイナリの読み込み 2. 解析の始め方 3.

    Break Pointによる一時停止 4. レジスタの書き換え Reversing基礎編 - SECCON Beginners Live 2022 40
  20. 0. 表層解析・静的解析 $ file please_not_trace_me please_not_trace_me: ELF 64-bit LSB shared

    object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=23181ea7316f70cf887016337e4024aa643a9d7b, for GNU/Linux 3.2.0, not stripped $ strings please_not_trace_me /lib64/ld-linux-x86-64.so.2 ... flag decrypted. bye. prease not trace me... ... Reversing基礎編 - SECCON Beginners Live 2022 41
  21. 0. 表層解析・静的解析 Ghidraで動作を確認する local_30 = 9; do { switch(local_30) {

    case 8: fwrite("prease not trace me...\n",1,0x17,stderr); exit(1); ... case 0xb: local_38 = ptrace(PTRACE_TRACEME,0,1,0); ... case 0x16: local_40 = ptrace(PTRACE_TRACEME,0,1,0); } Reversing基礎編 - SECCON Beginners Live 2022 42
  22. ptraceシステムコールとは https://man7.org/linux/man-pages/man2/ptrace.2.html あるプロセス(実行されているプログラム)のデバッグを提供する機能 ptraceシステムコールはあるプロセスの中で2回呼び出すことができないとい う特徴があり,1回目の呼び出しでは返り値が 0 (実行に成功した)となるが2回 目の呼び出しでは返り値が -1 (実行に失敗した)となる

    GDBはptraceシステムコールによってデバッグを実現しているため,GDB上 でデバッグを行うプロセスはすでに1回ptraceシステムコールが呼ばれた状態 となる つまり,ptraceシステムコールをあらかじめプログラム内に記載しておくと プログラム内のptraceシステムコールの呼び出しの返り値が 0 とな るときはGDB(やptraceシステムコールによるデバッグ)で呼び出さ れていない プログラム内のptraceシステムコールの呼び出しの返り値が -1 とな る場合はデバッガー上で動作している と判定することができる Reversing基礎編 - SECCON Beginners Live 2022 43
  23. 2. 解析の始め方 please_not_trace_meをGDB上で動かす $ gdb-peda please_not_trace_me ... gdb-peda$ start #

    main 関数手前で一時停止 ... gdb-peda$ c # 実行を続ける Continuing. prease not trace me... [Inferior 1 (process 162338) exited with code 01] Reversing基礎編 - SECCON Beginners Live 2022 44
  24. please_not_trace_meをそのまま動かす $ ./please_not_trace_me flag decrypted. bye. GDB上で動かしたときと処理が変わっている → please_not_trace_meはptraceシステムコールでGDB上で動作している か検知し,GDB上で動作していないときのみフラグ文字列を復号する実装

    → フラグ文字列を取得するにはプログラム内のptraceシステムコールが呼ば れた直後でプログラムを一時停止させ,返り値が格納されている場所の値を書 き換える必要がある Reversing基礎編 - SECCON Beginners Live 2022 45
  25. まずはGDB上でプログラム内のptraceシステムコールがどのアドレスで呼び 出されているか調査する $ gdb-peda please_not_trace_me ... gdb-peda$ start # main

    関数手前で一時停止 ... gdb-peda$ disas main # main 関数を逆アセンブルする Dump of assembler code for function main: 0x00005555555551ff <+0>: push rbp 0x0000555555555200 <+1>: mov rbp,rsp => 0x0000555555555203 <+4>: sub rsp,0x70 0x0000555555555207 <+8>: mov DWORD PTR [rbp-0x54],edi 0x000055555555520a <+11>: mov QWORD PTR [rbp-0x60],rsi 0x000055555555520e <+15>: mov QWORD PTR [rbp-0x68],rdx 0x0000555555555212 <+19>: call 0x55555555585e <megaInit> 0x0000555555555217 <+24>: mov eax,DWORD PTR [rbp-0x54] Reversing基礎編 - SECCON Beginners Live 2022 47
  26. ここから1回目に呼ばれるptraceシステムコールを探すと 0x00005555555552f3 <+244>: call 0x555555555080 <ptrace@plt> 0x00005555555552f8 <+249>: mov QWORD

    PTR [rbp-0x38],rax アドレス 0x00005555555552f3 で呼びだしており,返り値が格納されるレジスタ RAX をその直後にメモリ内にコピーし処理が行われていくことが分かる → ptraceシステムコールが呼ばれた直後にプログラムを一時停止させたいの でアドレス 0x00005555555552f8 にbreak pointを設定する Reversing基礎編 - SECCON Beginners Live 2022 48
  27. 4. レジスタの書き換え gdb-peda$ b *0x00005555555552f8 # break point を設定 Breakpoint

    2 at 0x5555555552f8 gdb-peda$ c # 実行を再開する Continuing. ... Breakpoint 2, 0x00005555555552f8 in main () gdb-peda$ set $rax=0 # RAX レジスタの値を0 にする gdb-peda$ c # 実行を再開する Continuing. flag decrypted. bye. → プログラム内で呼ばれたptraceシステムコールの返り値をsetコマンドで -1 から 0 に書き換えることで,please_not_trace_meをそのまま動かすと きと同じ処理をするようになった Reversing基礎編 - SECCON Beginners Live 2022 49
  28. gdb-peda$ b *0x0000555555555330 Breakpoint 3 at 0x555555555330 gdb-peda$ start #

    最初から実行し直す gdb-peda$ c # main 関数前で停止するので実行を再開する Breakpoint 2, 0x00005555555552f8 in main () # ptarace システムコールが呼ばれた直後に停止 gdb-peda$ set $rax=0 # RAX レジスタの値を0 にする gdb-peda$ c # 実行を再開する [----------------------------------registers-----------------------------------] R8 : 0x5555555592c0 ("ctf4b{d1d_y0u_d3crypt_rc4?}") R8 レジスタにフラグ文字列 ctf4b{d1d_y0u_d3crypt_rc4?} が格納されていた (特にGDBでのアドレスの値は実行環境ごとに異なるので,適宜 disas コマン ドでGDBでの逆アセンブル結果を見ながらbreak pointを設定してください) Reversing基礎編 - SECCON Beginners Live 2022 51