Slide 1

Slide 1 text

SECCON Beginners Live 2022 Reversing基礎編 2022/09/11 @hi120ki

Slide 2

Slide 2 text

自己紹介 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

Slide 3

Slide 3 text

本演習の目的 バイナリ解析の基本ツールのインストールから使い方までを紹介し,バイナリ 解析の第一歩を踏み出してもらい,Beginners CTFのEasy問題を解けるよう になる Reversing基礎編 - SECCON Beginners Live 2022 3

Slide 4

Slide 4 text

流れ 1. Reversingとは 2. ELFファイル解析の基本 3. ツールのインストール 4. ツールの使い方 Reversing基礎編 - SECCON Beginners Live 2022 4

Slide 5

Slide 5 text

1. Reversingとは Reverse Engineeringとも言われ,機械や製品・プログラムの内部の構造や 動作を解析すること CTFではプログラムや特定の形式のファイルを解析します (例) 実行可能ファイル(Executable file) Linux ELF Windows PE モバイルアプリ APK(Android Application Package) スクリプトファイル pcapファイル ファームウェア Reversing基礎編 - SECCON Beginners Live 2022 5

Slide 6

Slide 6 text

出題傾向 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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

なぜLinux ELFファイルの出題が多いのか C言語で作成されたLinux ELFファイルは ファイルサイズが小さい 配布しやすい 解析ツールが軽快に動作する アセンブリが簡潔 どんなプログラムであるか想像しやすい 問題の本質にすぐ気付くことができる 問題を作りやすい C言語を多少扱えればある程度の難易度の問題が作れる Reversing基礎編 - SECCON Beginners Live 2022 8

Slide 9

Slide 9 text

2. ELFファイル解析の基本 CPUは機械語しか実行できないが機械語は人間にとって扱いづらいので,機械 語と1対1で対応するアセンブリ言語や,コンパイラでアセンブリコードを出力 できるソースコードで処理を記述する ソースコードに記述された処理は機械語に変換されるとどんな処理が行われて いるか分かりづらくなる・マルウェアでは処理を秘匿するために更に処理が分 かりづらくなるような工夫がされる → 機械語から処理を正確に把握する能力を養う Reversing基礎編 - SECCON Beginners Live 2022 9

Slide 10

Slide 10 text

ELFファイル解析の流れ 1. 表層解析 ファイルの種類を調べる ファイルに含まれる文字列からファイルの種類や動作の手がかりを取得する 2. 静的解析 バイナリに含まれる機械語の命令からプログラムの動作を把握する 3. 動的解析 ファイルを実行しながら処理を追うことでプログラムの動作を把握する Reversing基礎編 - SECCON Beginners Live 2022 10

Slide 11

Slide 11 text

ELFファイル解析でよく使うツール 1. 表層解析 fileコマンド : ファイル形式を推測 stringsコマンド : ファイルに含まれる可読文字列を表示 2. 静的解析 Ghidra : NSAによって開発されているOSSの解析ツール IDA : Hex Rays社によって開発されている有償(機能が制限された無償版もあ り)の解析ツール 3. 動的解析 GDB : GNU Project debugger 特にLinuxではデファクトスタンダードなデ バッグ&動的解析ツール Reversing基礎編 - SECCON Beginners Live 2022 11

Slide 12

Slide 12 text

4. ツールのインストール インストールにあたっての準備 fileとstringsはLinuxのコマンドで,GDBはLinux上で動作 → Linux環境が必要 CTFでは色々なツールをインストールしていくことになり,ライブラリのバー ジョンの衝突で動かなくなったり,動作が不安定になることがよくある → CTF環境は「リセットしやすいもの」を選び構築するのがおすすめ 1つのアプローチ VirtualBoxとVagrantでいつでもCTF環境となるLinux仮想マシンを立ち上げ る・リセットできるようにする よく使うツールを自動インストールするAnsible Playbookやシェルスクリプ トを用意し自分のCTF環境を再現できるようにする ホストとの共有ディレクトリの中で作業しCTF環境が突然動かなくなってもフ ァイルは復元できるようにする Reversing基礎編 - SECCON Beginners Live 2022 12

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

1. 起動後File→New Projectを選択 Reversing基礎編 - SECCON Beginners Live 2022 21

Slide 22

Slide 22 text

2. Non-shared projectを選択 Reversing基礎編 - SECCON Beginners Live 2022 22

Slide 23

Slide 23 text

3. 適当なProject DirectoryとProject Nameを入力 Reversing基礎編 - SECCON Beginners Live 2022 23

Slide 24

Slide 24 text

4. Tool Chestの緑のアイコンをクリック Reversing基礎編 - SECCON Beginners Live 2022 24

Slide 25

Slide 25 text

5. File→Import Fileから配布バイナリを選択 Reversing基礎編 - SECCON Beginners Live 2022 25

Slide 26

Slide 26 text

5. File→Import Fileから配布バイナリを選択 Reversing基礎編 - SECCON Beginners Live 2022 26

Slide 27

Slide 27 text

5. File→Import Fileから配布バイナリを選択 Reversing基礎編 - SECCON Beginners Live 2022 27

Slide 28

Slide 28 text

6. 「analyze now?」にYes Reversing基礎編 - SECCON Beginners Live 2022 28

Slide 29

Slide 29 text

7. Analysis OptionはデフォルトでOK Reversing基礎編 - SECCON Beginners Live 2022 29

Slide 30

Slide 30 text

8. 左の真ん中のSymbol TreeのFunctionsを展開しmainを選択 Reversing基礎編 - SECCON Beginners Live 2022 30

Slide 31

Slide 31 text

8. 左の真ん中のSymbol TreeのFunctionsを展開しmainを選択 Reversing基礎編 - SECCON Beginners Live 2022 31

Slide 32

Slide 32 text

8. 左の真ん中のSymbol TreeのFunctionsを展開しmainを選択 Reversing基礎編 - SECCON Beginners Live 2022 32

Slide 33

Slide 33 text

9. 真ん中に逆アセンブル結果,右に逆コンパイル結果が表示される Reversing基礎編 - SECCON Beginners Live 2022 33

Slide 34

Slide 34 text

(解法1) 逆アセンブル結果を見る Reversing基礎編 - SECCON Beginners Live 2022 34

Slide 35

Slide 35 text

(解法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

Slide 36

Slide 36 text

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 ::read ff ff (LEA命令は第2オペランドのアドレスを第1オペランドにコピーする) このとき 第1引数 EDIには読み込むデータの種類として標準入力を指定 第2引数 RSIには書き込み先メモリ領域のアドレス 第3引数 EDXには読み込む文字数の0x17 とし,関数を呼び出すCALL命令で read を指定することで,標準入力から 0x17(=23)文字読み込みメモリ内に保存する処理が実行される Reversing基礎編 - SECCON Beginners Live 2022 36

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

(解法2) Ghidraの右のDecompile画面を見る Reversing基礎編 - SECCON Beginners Live 2022 38

Slide 39

Slide 39 text

(解法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

Slide 40

Slide 40 text

5-3. 動的解析ツール GDBの使い方を紹介 0. 表層解析・静的解析 1. バイナリの読み込み 2. 解析の始め方 3. Break Pointによる一時停止 4. レジスタの書き換え Reversing基礎編 - SECCON Beginners Live 2022 40

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

3. Break Pointによる一時停止 プログラムのアドレスを設定しておくことで,そのアドレスの命令を実行する 直前でプログラムを一時停止する機能 さらに停止中はレジスタやメモリの値を書き換えることができる → プログラム内のptraceシステムコールが呼ばれた直後にプログラムを一時 停止させ,返り値が格納されているレジスタの値を -1 から 0 に書き換える Reversing基礎編 - SECCON Beginners Live 2022 46

Slide 47

Slide 47 text

まずは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 0x0000555555555217 <+24>: mov eax,DWORD PTR [rbp-0x54] Reversing基礎編 - SECCON Beginners Live 2022 47

Slide 48

Slide 48 text

ここから1回目に呼ばれるptraceシステムコールを探すと 0x00005555555552f3 <+244>: call 0x555555555080 0x00005555555552f8 <+249>: mov QWORD PTR [rbp-0x38],rax アドレス 0x00005555555552f3 で呼びだしており,返り値が格納されるレジスタ RAX をその直後にメモリ内にコピーし処理が行われていくことが分かる → ptraceシステムコールが呼ばれた直後にプログラムを一時停止させたいの でアドレス 0x00005555555552f8 にbreak pointを設定する Reversing基礎編 - SECCON Beginners Live 2022 48

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

フラグがメモリ内で復号されているようなのでさらに flag decrypted. bye. が 表示される箇所(GhidraのDecompile画面とGDBの逆アセンブル結果を見比 べることで 0x0000555555555330 のputs命令だとわかる)にbreak pointを設定 する Reversing基礎編 - SECCON Beginners Live 2022 50

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

最後に 表層解析ではfileコマンド・stringsコマンド,静的解析ではGhidra,動的解 析ではGDBをインストール方法から基本的な使い方までを紹介しました 実はGhidraにはstringsコマンドに該当する機能があり,逆アセンブル結果の どこで使われているかを簡単に見つける方法があったり,GDBでは今回紹介し たbreak point以外にも様々なコマンドがGDB本体やGDBプラグインで提供 されています SECCON Beginners CTFの過去問は https://github.com/seccon から入手 でき,また他にも常設CTFや書籍や他のCTFの過去問から解答付きの問題を入 手することができます ぜひいろんな問題を今回紹介したツールたちで解いてみてください Reversing基礎編 - SECCON Beginners Live 2022 52