Pwn - TK-CTF/CTF GitHub Wiki

どうもこんばんは。SECCON終わりましたね、お疲れさまでした。
今回は、僕の担当分野のPwn(Exploit)を紹介したいと思います。
TODO:体系的にまとめる

Contents

  1. Pwnとは
  2. 必要となる知識
  3. 参考サイト
  4. ELF機構 - 脆弱性とメタとメタのメタ
  5. 攻撃手法&脆弱性
    $ 1. shellcodeの実行
    $ 2. バッファオーバーフロー(BOF)
    $ 3. Heap系脆弱性
    $ 4. ret2系
    $ 5. ROP
    $ 6. Format String Bug (FSB)
  6. 自分用メモ・コマンド集
    $ 1. 知っていれば得する!知識編
    $ 2. ssh - サーバーへの接続
    $ 3. gdb - デバッガ
    $ 4. readelf - elfの表層解析
    $ 5. objdump - ダンプする
    $ 6. rp++
    $ 7. Pwntoolsチートシート

Pwnとは

そもそもPwnって何かってとこからいきますね。
Pwnではだいたい主催者側のサーバーにアクセスして、そこにある実行可能ファイルをクラックし、最後にroot権限を奪取してflagを手に入れるということをやってます。
自分はまだ全然問題を解いていないのであんま言い切れないですけど…

必要となる知識

必要そうな知識を紹介していきます

まず、CTF全般に言えることですがコンピューターがどのように動くか、つまりコンピューターの設計は知っておいた方がいいと思います。 Rev同様、基本はアセンブラ言語と向き合うことになるので、そこら辺の知識があれば理解がしやすくなるかと。

あとはLinuxのコマンドやsystemcallとかアセンブラ・C言語・pythonとかは使える方がいいです。 というかWriteupとか見てるとそこら辺の知識は自明としているので僕が云々言う前に身についてると思います。 gdb(-peda)とかpwntoolsとかのツールも使えるようになっておきたいところです。

最後に、実行可能ファイルの知識ですね。
Pwnでメインとなるのは実行可能ファイルをクラックするところなので、 その詳細な知識は欲しいです。 詳細、といってもリンカ・ローダまでは追わなくていいです。 概念として知っていれば。 大事なのはメモリマップとかセキュリティ機構とかですね。 そこらへんはGoogle先生を活用しつつ、問題を解いていけば何とかなると思います。 あと、secconでは(多分)ELF形式の実行可能ファイルが渡されるので、Windowsの方はあんまりやんなくてもいいです。

参考サイト

え、これ問題解説とか具体的に何やってるかとか書いた方がいいの?
取り敢えず良し悪しは分からないですが僕が今勉強してるサイトを載せときます。

ksnctf  問題があります。 配点が鬼高いのがPwnの問題です。

A painter and a black cat  Pwnの知識を割と体系的に学べると思います。 一部内容が未完成ですが、何を知ればよいのかがかるのは大事かと。

The Linux Kernel  Linuxカーネルの概要がサッと学べます。 暇があれば読んでおいて損はないかも。 ただ、結構専門用語使っているので、何も知らない状態では結構大変かも。

Reversingとかpwnとかを解くときのメモ(かきかけ)  ここに書いてあることが大体書いてあります。

Exploitの流れ

実際にどのようにExploitしていけばいいか解説します。
基本的にroot強奪までは以下の流れだと思います。

攻撃手法&脆弱性

shellcodeの実行

最も基本的な攻撃手法。/bin/shをexecveさせるshellcodeを実行させれば勝ち=rootを奪える(elfにsuid bitがあればだけど)。

参考:Linux x86用のシェルコードを書いてみる
   (*(void (*)()) shellcode)()とは (*(void (*)()) shellcode() が何するか分かる? ヒント:shellcodeはバイト列
   x64でスタックバッファオーバーフローをやってみる

  • x86用shellcode
_start:
        /* push 0 */
        xor edx, edx
        push edx
        push 0x68732f2f
        push 0x6e69622f
        mov ebx, esp
        push edx
        push ebx
        mov ecx, esp
        /* mov eax, 11 */
        lea eax, [edx+11]
        int 0x80

\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80

レジスタを設定して、syscall(execve)を呼び出す、ってことをやってます。

  • x86_64用
_start:
        xor rdx, rdx
        push rdx
        mov rax, 0x68732f2f6e69622f
        push rax
        mov rdi, rsp
        push rdx
        push rdi
        mov rsi, rsp
        lea rax, [rdx+59]
        syscall

\x48\x31\xd2\x52\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x48\x8d\x42\x3b\x0f\x05

バッファオーバーフロー(BOF)

strncpy()とかがやばいって話

  • Stack-based BOF

scanf()等でバッファサイズ以上の文字列を入力し、スタック領域を溢れさせてReturn Addressを書き換えたりする。

  • Heap-based BOF

プログラムの実行時にデータが置かれる場所にはスタックとヒープがあり、スタックと同様ヒープについてもバッファオーバーフローが起こりうる。

上から、*(buf1->buf)の書き込みがオーバーフローすると、buf2->bufに入っているポインタの上書きが可能であることがわかる。 そしてbuf2->bufが書き換えられたとき、2回目のstrcpy関数が呼び出される際に上書きされたポインタが指す領域にデータが書き込まれることになる。 すなわち、任意のメモリアドレスの値が書き換え可能になる。 このような状態は、Write-what-where Conditionと呼ばれる。

参考:ヒープオーバーフローによるGOT overwriteをやってみる 参考:GLIBC MALLOC FOR EXPLOITERS 英語できついけど頑張って

Heap系脆弱性

  • use-after-free

Heapの最適化アルゴリズムとCodeの脆弱性を悪用する。

このコードでは、free_box関数内で解放されたbox->bufが、strncpy関数により再度参照されている。 また、その間にサイズを自由に指定可能なnewbufが新たに確保され、任意のデータを書き込めるようになっている。

この攻撃を行うには、適当なタイミングで任意のサイズのバッファを新たに確保できる必要がある。 このような状況は、Webブラウザなどスクリプトエンジンを介してある程度自由にメモリの確保が行える場合において成立する。

参考:use-after-freeによるGOT overwriteをやってみる

ret2系

  • ret2esp  > スタック中にjmp espや、call espに復帰するようなアセンブラコードを仕込む。
     文字数制限とかは回避できる。
    上のコードの直後にshellcodeを仕込む。
     DEPで終わりでーす。

  • ret2plt
     return addressをpltの任意の関数に書き換える。 printf(*char)とかにやればbufferを出せる。

ROP

  • プログラム中に(偶然)存在する、自分が実行したい短いマシン語を見つけて、制御を移す手法。
    要はコード断片をかき集めて、いい感じにレジスタとか調整してsyscall呼び出そうねってやつ。
    PIEで死ぬ。
  • Stager
    攻撃に使える領域のサイズが制限されている場合,readなどの関数を用いて再度メモリに書き込む方法をstagerと呼ぶ.
  • Stack Pivot
    スタックのサイズ上,リターンアドレスの下にROP chainを構築できないような場合,xchg esp,eaxなどのgadgetを用いてスタックのアドレスを移動させる方法をstack pivotと呼ぶ.
    Reversingとかpwnとかを解くときのメモ(かきかけ) ここのROPのコーナーは分かりやすい
    Return-oriented programming以後 *TODO ROP Techniqueの索引にもなると思います

Format String Bug (FSB)

自分用メモ・コマンド集

知っていれば得する!知識編

  • system系
    x86の場合
    int 0x80 (cd80)で呼ぶ。システムコール番号はeax。引数はebx,ecx,edx,esi ...
    x64の場合
    syscall ()で呼ぶ。システムコール番号はrax。引数はrdi,rsi,rdx,r10 ...

  • 文字入出力
    scanf 水平タブ(0x9),改行(0xa),垂直タブ(0xb),改ページ(0xc),キャリッジリターン(0xd),スペース(0x20)
    gets 0xa
    read なし
    printf 0x0
    puts 0x0
    write なし
    strcpy 0x0

ssh - サーバーへの接続

ログイン $ssh user@host (-p portnumber)

ダウンロード $scp user@host:/host/path /local/path

nc

gdb - デバッガ

大体ももテクからの引用

実行 (gdb) start/run "arg" mainでとまる/とまらない

 breakpointまで処理の継続でc、breakpoint or 関数の終了まで継続のfin、特定のアドレスまで継続のu *func+num/address等がある

一命令実行 (gdb) si/ni 関数に入る/入らない

 (gdb) record しておくと (gdb) rsi/rni で巻き戻せる(reverse-si/ni)

ジャンプ (gdb) jump *func+num/address eipを変える

レジスタ表示 (gdb) i r $esp レジスタ複数指定可能、指定がないと全部

機械語表示 (gdb) disas function 無指定でeipのいるfunctionになる。

ブレークポイント (gdb) (b *func+num/address)/(i b)/(d num) set/display/delete tbでsetすると一回で消える

 ウォッチポイントやsyscallポイントもある

メモリ表示 (gdb) x/nwx $esp esp以降nword(4bite)を16進数(x)で defaultは$eip x→iで命令を表示する。defaultは$pc(直後の命令)

メモリ書き換え (gdb) set {int/char}address = num/'char' ワード単位/バイト単位

メモリマップ (gdb) i proc map

シェル実行 (gdb) shell cat /proc/pid/map ちなみにこのコードはpidのメモリマップを表示する(i proc mapと異なりNXbit)

gdb-peda - 拡張版gdb

チートシート

readelf - elfの表層解析

ELFヘッダ -h

セグメント(プログラム?)ヘッダ -l ローダがつかうらしい

セクションヘッダ -S

n番目のセクションをダンプ -xn ちなみに後述のように名前でも可能

.rel何とかセクション -r 動的リンク、共有ライブラリとかでつかう

ローダ・リンカ?を表示 -p .interp

共有ライブラリ・シンボルを表示 -p .dynstr

pltの参照先 -x .plt.got アドレステーブル

objdump - ダンプする

基本 objdump -M intel -d a.out | sed -n '/<main>:/,/^$/p

解説:intel記法でa.outをdisassenbleする。パイプにつないでるのはsedコマンド。-n '~p'はセットで、"マッチする行のみを出力"という意味

   "

:"から始まり"^$"で終わる範囲までがマッチする(ここで、"^$"は正規表現で、空行との完全一致という意味)

plt表示 -d -j .plt 動的リンクされた関数のラッパー 機械語表示 -d -j .text -dはdisasの略


以降TODO

radare2 - gdbっぽいなにか

よくわからん

参考? radare2 覚書

rp++

github - 0vercl0k/rp

USAGE:

 ./rp++ [-hv] [-f <binary path>] [-i <1,2,3>] [-r <positive int>] [--raw=<archi>]
 [--atsyntax] [--unique] [--search-hexa=<\x90A\x90>] [--search-int=<int in hex>]

OPTIONS:

  -f, --file=<binary path>  give binary path
  -i, --info=<1,2,3>        display information about the binary header
  -r, --rop=<positive int>  find useful gadget for your future exploits, arg is the gadget maximum size in instructions
  --raw=<archi>             find gadgets in a raw file, 'archi' must be in the following list: x86, x64
  --atsyntax                enable the at&t syntax
  --unique                  display only unique gadget
  --search-hexa=<\x90A\x90> try to find hex values
  --search-int=<int in hex> try to find a pointer on a specific integer value
  -h, --help                print this help and exit
  -v, --version             print version information and exit

EXAMPLES:
$ ./rp-lin-x86 --file=a.out --rop=3 --unique > gadgets.txt

checksec.sh

gdb-pedaに入ってるっぽいので略

strace/ltrace - syscall/libトレーサ

ググって

socat

要:socat+gdb(+peda)でexploitのデバッグを行う方法
pwntoolsも使ってる

pwntools - なんか便利そう

Writeup見ながら覚える

nasm

metasploit - ペネトレーションツール

使えるようになると強そう

Tutorとしてよさげ



因みに許可されていないサーバーでやると最悪法に触れるので厳禁

TODO

リンクを張っていく

System Call

Writeup

Techniques

大体黒猫参照

  • Heap系
    Use After Free
    Double Free
    off-by-one error
    House of XXX

  • Race Condition

Python

struct pack

pwntools

ROP Gadgets

⚠️ **GitHub.com Fallback** ⚠️