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

Pwn入門 BoFからHouse of Orange まで

megumish
September 23, 2017

Pwn入門 BoFからHouse of Orange まで

megumish

September 23, 2017
Tweet

More Decks by megumish

Other Decks in Technology

Transcript

  1. 自己紹介 • CTF ではとくに Pwn ( Exploit )が好き • 去年の

    SECCON2016 (12月)から本格的に始めた – それまでは中長期型の競プロをよくやっていた
  2. 自己紹介 • 当初から Pwn カテゴリを頑張ろうと思っていた • しかし、なかなか手をつけられずに 7 月に至る –

    この時点では BoF や FSA と言ったものも、よく分かっていな かった • 7 月下旬からやる気 MAX ファイアーで頑張ったら、そこ そこできるようになった – pwnable.tw というサイトで 2467 人中 123 位( 9 月 19 日時点)
  3. Pwn (または Exploit )について • サーバーを攻撃して、その制御を奪う部門 • 制御を奪うとは – /bin/sh

    のようなシェルを実行 – Windows では cmd.exe や powershell.exe の実行 – 要は任意の OS コマンドを実行出来る状態にするのが Pwn
  4. Pwn (または Exploit )について • サーバーを攻撃して、その制御を奪う部門 • 制御を奪うとは – 具体的には

    /bin/sh のようなシェルを実行 – Windows では cmd.exe や powershell.exe の実行 – 要は任意の OS コマンドを実行出来る状態にするのが Pwn
  5. Pwn (または Exploit )について • サーバーを攻撃して、その制御を奪う部門 • 制御を奪うとは – 具体的には

    /bin/sh のようなシェルを実行 – Windows では cmd.exe や powershell.exe の実行 – 要は任意の OS コマンドを実行出来る状態にするのが Pwn • この状態にどうやって持っていくかが重要
  6. レジスタとメモリ • 分岐を変えるにはレジスタ・メモリの値を変えればいい • レジスタの値を変えるには? – レジスタ間の値のコピー – メモリからの値のロード •

    read() などによってメモリは書き換え可能 • メモリを書き換えることで意図した命令列を実行すること ができそう。
  7. メモリの書き換え • 書き込み可能な領域は限られている • 書き込み可能な領域すべてが必ずしも利用可能ではない – read() などで書き込むことが可能か • 既知のアドレスであるか

    • それを引数として指定できるか • これらの問題を解決し、特定の領域に何らかの書き込みを行う ➔ そして、任意の命令を実行できるようにする ➔ これが Pwn の主目的となる
  8. 主な Pwn の手法 • Buffer Over Flow • Return Oriented

    Programming • Format String Attack • Heap テク – fastbins attack – unsafe unsorted bins attack – House of 〜系
  9. 攻撃手法ですること • メモリの書き換え • レジスタの書き換え • PIE が有効である場合 – バイナリのアドレスのリーク

    • ASLR が有効である場合 – Heap のアドレスのリーク – libc のアドレスのリーク • SSP が有効である場合 – CANARY の値のリーク
  10. スタック領域 • 関数呼び出し時に、この領域の一部が次のような用途で 確保される – 呼び出し元の命令を指すレジスタ (EIP/RIP) のバックアップ – その他のレジスタのバックアップ

    – ローカル変数の使用領域の確保 呼び出し元関数の領域 呼び出し元命令アドレス RBPのバックアップ いくつかのローカル変数
  11. スタック領域 • RBP との差分で管理 呼び出し元命令アドレス RBPのバックアップ RBP 上位 下位 long

    long hoge char piyo[0x100] piyoの実体 RBP + 0x08 RBP - 0x100 RBP - 0x108 RBP - 0x110
  12. スタック領域 • 例えば、 piyo の実体に文字列 ABCD を代入すると 呼び出し元命令アドレス RBPのバックアップ RBP

    上位 下位 long long hoge char piyo[0x100] piyoの実体 RBP + 0x08 RBP - 0x100 RBP - 0x108 RBP - 0x110
  13. スタック領域 • リトルエンディアンの場合、右から順に入る 呼び出し元命令アドレス RBPのバックアップ RBP 上位 下位 long long

    hoge char piyo[0x100] piyoの実体 RBP + 0x08 RBP - 0x100 RBP - 0x108 RBP - 0x110 0x0000000044434241 AはASCIIコードで0x41 BはASCIIコードで0x42 CはASCIIコードで0x43 DはASCIIコードで0x44
  14. スタック領域 • 次に piyo の実体に A * 0x8 + B

    * 0x8 を入れてみる 呼び出し元命令アドレス RBPのバックアップ RBP 上位 下位 long long hoge char piyo[0x100] piyoの実体 RBP + 0x08 RBP - 0x100 RBP - 0x108 RBP - 0x110
  15. スタック領域 • 図のように 8byte 分入ると今度は下の方に進む(※) 呼び出し元命令アドレス RBPのバックアップ RBP 上位 下位

    long long hoge char piyo[0x100] piyoの実体 RBP + 0x08 RBP - 0x100 RBP - 0x108 RBP - 0x110 0x4141414141414141 0x4242424242424242 AはASCIIコードで0x41 BはASCIIコードで0x42 ※ここでは64bitバイナリを例 にしているため8byteになるが 32bitバイナリでは4byteごとに なることに注意
  16. スタック領域 呼び出し元命令アドレス RBPのバックアップ RBP 上位 下位 long long hoge(0x00000000CDAB) char

    piyo[0x100] piyoの実体 RBP + 0x08 RBP - 0x108 RBP - 0x110 0x4141414141414141 0x4242424242424242 AはASCIIコードで0x41 BはASCIIコードで0x42 ※ここでは64bitバイナリを例 にしているため8byteになるが 32bitバイナリでは4byteごとに なることに注意 • 図のように 8byte 分入ると今度は下の方に進む(※) • このことを理解して BoF 攻撃をする
  17. BoF 攻撃 • バッファ piyo の下には“ RBP のバックアップ”や“呼び出 し元命令アドレス”が存在 •

    バッファ piyo に 0x100byte 以上の書き込みをすると これらの上書きが可能
  18. RBP のバックアップを RBP に戻す処理 • この処理を実行するための命令として leave 命令がある – この命令は以下の2つの命令と等価

    – mov rsp, rbp; pop rbp; • mov rsp, rbp; は RSP に RBP の値をコピーする命令 • pop rbp; は現在の RSP が指す値を RBP にコピーし て、 RSP の値を 8 (※)だけ減算する命令 • 実際のバイナリでは leave 命令を使わないこともある ※64bit バイナリの場合は 8 32bit バイナリの場合は 4
  19. 呼び出し元命令アドレスに戻る処理 • この処理を実行するための命令として ret 命令がある – この命令は以下の命令と等価 – pop rip;

    • RIP に現在 RSP が指す値をコピーし、 RSP を 8 (※)だけ 減算する命令 ※64bit バイナリの場合は 8 32bit バイナリの場合は 4
  20. BoF 攻撃 • RBP のバックアップを RBP に戻す処理への攻撃 – RBP の書き換えが可能

    ➔ read() などによって書き込むアドレスを指定できるかも? • 呼び出し元命令アドレスに戻る処理への攻撃 – RIP の書き換えが可能 ➔ 特定の命令列を実行できるかも?
  21. BoF 攻撃 • RBP のバックアップを RBP に戻す処理への攻撃 – RBP の書き換えが可能

    ➔ read() などによって書き込むアドレスを指定できるかも? • 呼び出し元命令アドレスに戻る処理への攻撃 – RIP の書き換えが可能 ➔ 特定の命令列を実行できるかも?
  22. BoF 攻撃 • RBP のバックアップを RBP に戻す処理への攻撃 – RBP の書き換えが可能

    ➔ read() などによって書き込むアドレスを指定できるかも? • 呼び出し元命令アドレスに戻る処理への攻撃 – RIP の書き換えが可能 ➔ 特定の命令列を実行できるかも? • これらを組み合わせることで意図する命令を実行する
  23. 実例 • このプログラムを以下のようなコマンドでコンパイルする • gcc -o bof -fno-stack-protector -zexecstack bof.c

    • またプログラムの実行環境では ASLR(Address Space Layout Randomization) が有効であるとす る。
  24. Let's Pwn • この場合次のような Exploit が考えられる。 a)BoF によって RBP が

    .bss 領域を指すようにし、 RIP は read() の直前を指すようにする。
  25. Let's Pwn • この場合次のような Exploit が考えられる。 a)BoF によって RBP が

    .bss 領域を指すようにし、 RIP は read() の直前を指すようにする。 b)read() で .bss 領域にシェルコードを書き込む
  26. Let's Pwn • この場合次のような Exploit が考えられる。 a)BoF によって RBP が

    .bss 領域を指すようにし、 RIP は read() の直前を指すようにする。 b)read() で .bss 領域にシェルコードを書き込む • シェルコードとは、 execve(“/bin/sh”, NULL, NULL) を実行する命令列のこと • ここで .bss 領域に書き込むようにするのは ASLR に よってスタック領域を特定できないため
  27. Let's Pwn • この場合次のような Exploit が考えられる。 a)BoF によって RBP が

    .bss 領域を指すようにし、 RIP は read() の直前を指すようにする。 b)read() で .bss 領域にシェルコードを書き込む c)BoF で RIP がシェルコードの先頭を指すようにす る d)execve(“/bin/sh”, NULL, NULL) が発動!
  28. Let's Pwn • この Exploit に次の注意点がある – スタック領域の場所の特定をしない ➔ASLR が効いているためその特定が面倒

    ➔RIP は既知のアドレスにしか書き換えることが出来ない ➔そのため .bss 領域にシェルコードを書き込むようにする ➔この Exploit は以下の条件でしか使えない 1.PIE が無効である ➔バイナリのアドレスが randomize されない 2.NXbit ( DEP )が無効である ➔.bss 領域の命令が実行できる
  29. BoF 攻撃のまとめ • BoF 攻撃によって RBP 、 RIP を書き換えることが出来る •

    またその組み合わせによって、書き込む場所を変えること も出来る • 既知のアドレスにシェルコードを書き込めば、任意の OS コマンドが実行可能な状態に持っていける • ここでは話さないが ROP ( Return Oriented Programming )という攻撃につなげることも可能 ➔これにより攻撃の幅が広がる
  30. 攻撃の成立条件 • 任意のサイズの malloc() が可能 • Heap Over Flow ができる

    – これは次のチャンクサイズが変更可能であれば十分
  31. 攻撃の成立条件 • 任意のサイズの malloc() が可能 • Heap Over Flow ができる

    – これは次のチャンクサイズが変更可能であれば十分 • この攻撃には通常の Heap テクで必要な free() はいら ない ➔ 通常は free() することで fastbins や unsortbins などを作り 出してそれを利用する ➔ この方法では free() を使わずに bins を作り出す。
  32. 攻撃の成立条件 • 任意のサイズの malloc() が可能 • Heap Over Flow ができる

    – これは次のチャンクサイズが変更可能であれば十分 • この攻撃には通常の Heap テクで必要な free() はいら ない ➔ 通常は free() することで fastbins や unsortbins などを作り 出してそれを利用する ➔ この方法では free() を使わずに bins を作り出す。 • 具体例 – HITCONCTF2016 house of orange
  33. 前提知識 • malloc に関するある程度の知識 • abort() するときに _IO_flush_all_lockp() が呼び 出されるという知識

    – これによって File Stream Oriented Programming が可 能である • 実際にはこれらの知識がなくても頑張って調べればいける
  34. 前提知識 • malloc に関するある程度の知識 • abort() するときに _IO_flush_all_lockp() が呼び 出されるという知識

    – これによって File Stream Oriented Programming が可 能である • 実際にはこれらの知識がなくても頑張って調べればいける …かもしれない。
  35. 前提知識 • malloc に関するある程度の知識 • abort() するときに _IO_flush_all_lockp() が呼び 出されるという知識

    – これによって File Stream Oriented Programming が可 能である • 実際にはこれらの知識がなくても頑張って調べればいける …かもしれない
  36. House of Orange のおおまかな流れ a)適当なサイズの chunk をとる。( malloc() ) b)Heap

    Overflow を用いて、 top chunk size を書き 換える c)書き換えた top chunk size より 0x30 程度小さいサ イズの chunk をとる。
  37. House of Orange のおおまかな流れ a)適当なサイズの chunk をとる。( malloc() ) b)Heap

    Overflow を用いて、 top chunk size を書き 換える c)書き換えた top chunk size より 0x30 程度小さいサ イズの chunk をとる。 ➔このとき、 top chunk size は特定の条件を満たさない といけない…
  38. House of Orange のおおまかな流れ a)適当なサイズの chunk をとる。( malloc() ) b)Heap

    Overflow を用いて、 top chunk size を書き 換える c)書き換えた top chunk size より 0x30 程度小さいサ イズの chunk をとる。 ➔このとき、 top chunk size は特定の条件を満たさない といけない… ➔が、正直調べるのは面倒。
  39. House of Orange のおおまかな流れ a)適当なサイズの chunk をとる。( malloc() ) b)Heap

    Overflow を用いて、 top chunk size を書き 換える c)書き換えた top chunk size より 0x30 程度小さいサ イズの chunk をとる。 ➔例えばもともとの top chunk size 0x20f91 だった ら下位 3 桁をとって、 0xf91 にすると条件を満たしたり する。 ➔自分はこの条件を手探りで求めた。
  40. House of Orange のおおまかな流れ a)適当なサイズの chunk をとる。( malloc() ) b)Heap

    Overflow を用いて、 top chunk size を書き 換える c)書き換えた top chunk size より 0x30 程度小さいサ イズの chunk をとる。 d)c により、新たに Heap 領域が確保され、もともとの余っ た領域が大きな unsorted bin になる。 e)さらに chunk をとることで large bin になる。
  41. House of Orange のおおまかな流れ a)適当なサイズの chunk をとる。( malloc() ) b)Heap

    Overflow を用いて、 top chunk size を書き 換える c)書き換えた top chunk size より 0x30 程度小さいサ イズの chunk をとる。 d)c により、新たに Heap 領域が確保され、もともとの余っ た領域が大きな unsorted bin になる。 e)さらに chunk をとることで large bin になる。 ➔これにより libc と Heap のアドレスがリークできる。
  42. House of Orange のおおまかな流れ f) 次のような偽の unsorted bin chunk を作る

    • main_arena が unsorted bin を指す位置に置く • fd は適当な値、 bk は _IO_list_all を指すようにする • サイズは 0x60 で prev_in_use のフラグを立てておく(つま り、 0x61 にする。) • このチャンク自体の prev_size は設定しなくてもよい ➔わざと abort() させ、 _IO_flush_all_lockp() を利用するた め。
  43. House of Orange のおおまかな流れ g)また、 e の unsorted bin が

    FILE_plus 構造体にな るようにしておく • vtables 変数の値がその後に置く system() のアドレスを含む 、 vtables 構造体を指すようにしておく • 他の値は Heap+0x80 などにしておくと問題がない h)unsorted bin (かつ FILE_plus 構造体であるもの)の後に vtables 構造体を置く • vtables 構造体の 4 番目に system() のアドレスを置く。 i) malloc() をする と、 abort() 、 _IO_flush_all_lockp() 、 system() の順にうま く行くと実行される。
  44. House of Orange の原理 • f 以降の手法についての原理 • まず f

    で unsorted bins attack の準備をしている – _IO_list_all は通常は stderr を指している – この攻撃で main_arena の unsorted bins のアドレスを指 すように上書きされる – また、 main_arena の small_bins[4] が偽のチャンクを指す ようになる • これは次に説明する FILE Stream Oriented Programming に関係する
  45. FILE Stream Oriented Programming • abort() 中に _IO_flush_all_lockp() という関数が呼び出さ れる

    – 本来は stdin や stdout 、 stderr といった入出力をすべて flush するためのもの – これの先頭として _IO_list_all が指しているものがとられる – そのため _IO_list_all を任意の FILE 構造体(偽でも良い)を 指すようにするとこの関数の一部を適用できる
  46. FILE Stream Oriented Programming – FILE 構造体には chain と呼ばれる変数がある –

    これによって繋がれているため、すべての FILE 構造体を flush することができる – さきほどの main_arena の small_bins[4] がちょうど chain にくる – つまり偽の unsorted bin に _IO_flush_all_lockp の一部 を適用することが出来る。
  47. FILE Stream Oriented Programming – この関数中では FILE_plus 構造体の _IO_OVERFLOW(fp,EOF) が実行される

    – IO_OVERFLOW(fp,EOF) は vtables 構造体に設定されてい るものが呼び出される ➔ つまり偽の FILE_plus 構造体、 vtables 構造体を作ってお けば任意の関数を実行できる ➔ FILE Stream を使った攻撃なので、 FILE Stream Oritend Programming
  48. House of Orange のまとめ • House of Orange は FILE

    Stream と Heap をうまく使った 面白い手法 • とくに FILE Stream の _IO_OVERFLOW() と類似の _IO_UFLOW() などは他の関数でも使われることがある – 別のバイナリで似たような手法で攻撃が出来るかもしれない
  49. Kernel Exploit について • Kernel Exploit は通常の Pwn とは異なる •

    目標はカーネルランドで root 権限昇格後 に“ /bin/sh” の実行 • 下記の記事が面白いです • 説明は以上になります。
  50. 個人的なテクニック(?) • とにかく時間を掛けること • 分からない命令があったらすぐに調べること – Google で調べる – その命令の直前にブレイクポイントを仕込み、どのような挙動

    をするのか確かめると良い • 諦めること – ある程度時間をかけても(最低でも 3 時間はかけると良さそ う)脆弱性がひとつも見つけられなかった場合は諦めて writeup を見るのが良い • writeup (過去問の解説)を手を動かしながら読むこと
  51. おすすめのサイト • pwnable.tw – 自分はここで育ったのでおすすめです – 単純な脆弱性が多い気がします • batalist –

    これで hard の問題を writeup を見ながら解くと新しい知識 が得られてよいです。 – 何を解けばいいか迷った時はこのリストの中から選ぼう! • bataさんのスライド – 主に batalist に載っている問題の丁寧な解説があります
  52. おすすめのサイト • ももいろテクノロジー – 通称ももテク – 個々に書かれているテクはないというぐらい様々なテクニック がまとめられています。 • Kernel

    exploit集 – Kernel Exploit に関する記事・動画などがまとめられていま す • Twitter – プロによる writeup 情報や PoC などが流れてきます。