Pwn - TK-CTF/CTF GitHub Wiki
どうもこんばんは。SECCON終わりましたね、お疲れさまでした。
今回は、僕の担当分野のPwn(Exploit)を紹介したいと思います。
TODO:体系的にまとめる
- Pwnとは
- 必要となる知識
- 参考サイト
- ELF機構 - 脆弱性とメタとメタのメタ
-
攻撃手法&脆弱性
$ 1. shellcodeの実行
$ 2. バッファオーバーフロー(BOF)
$ 3. Heap系脆弱性
$ 4. ret2系
$ 5. ROP
$ 6. Format String Bug (FSB) -
自分用メモ・コマンド集
$ 1. 知っていれば得する!知識編
$ 2. ssh - サーバーへの接続
$ 3. gdb - デバッガ
$ 4. readelf - elfの表層解析
$ 5. objdump - ダンプする
$ 6. rp++
$ 7. Pwntoolsチートシート
そもそも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していけばいいか解説します。
基本的にroot強奪までは以下の流れだと思います。
最も基本的な攻撃手法。/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
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 英語できついけど頑張って
- use-after-free
Heapの最適化アルゴリズムとCodeの脆弱性を悪用する。
このコードでは、free_box関数内で解放されたbox->bufが、strncpy関数により再度参照されている。 また、その間にサイズを自由に指定可能なnewbufが新たに確保され、任意のデータを書き込めるようになっている。
この攻撃を行うには、適当なタイミングで任意のサイズのバッファを新たに確保できる必要がある。 このような状況は、Webブラウザなどスクリプトエンジンを介してある程度自由にメモリの確保が行える場合において成立する。
参考:use-after-freeによるGOT overwriteをやってみる
-
ret2esp > スタック中にjmp espや、call espに復帰するようなアセンブラコードを仕込む。
文字数制限とかは回避できる。
上のコードの直後にshellcodeを仕込む。
DEPで終わりでーす。 -
ret2plt
return addressをpltの任意の関数に書き換える。 printf(*char)とかにやればbufferを出せる。
- プログラム中に(偶然)存在する、自分が実行したい短いマシン語を見つけて、制御を移す手法。
要はコード断片をかき集めて、いい感じにレジスタとか調整してsyscall呼び出そうねってやつ。
PIEで死ぬ。 - Stager
攻撃に使える領域のサイズが制限されている場合,readなどの関数を用いて再度メモリに書き込む方法をstagerと呼ぶ. - Stack Pivot
スタックのサイズ上,リターンアドレスの下にROP chainを構築できないような場合,xchg esp,eaxなどのgadgetを用いてスタックのアドレスを移動させる方法をstack pivotと呼ぶ.
Reversingとかpwnとかを解くときのメモ(かきかけ) ここのROPのコーナーは分かりやすい
Return-oriented programming以後 *TODO ROP Techniqueの索引にもなると思います
- printf(buf)とかがやばいって話
%3c%2$n
の意味が分かれば - 参考:Format String Exploitを試してみる
-
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 user@host (-p portnumber)
ダウンロード $scp user@host:/host/path /local/path
nc
大体ももテクからの引用
実行 (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)
ELFヘッダ -h
セグメント(プログラム?)ヘッダ -l
ローダがつかうらしい
セクションヘッダ -S
n番目のセクションをダンプ -xn
ちなみに後述のように名前でも可能
.rel何とかセクション -r
動的リンク、共有ライブラリとかでつかう
ローダ・リンカ?を表示 -p .interp
共有ライブラリ・シンボルを表示 -p .dynstr
pltの参照先 -x .plt.got
アドレステーブル
基本 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 覚書
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
gdb-pedaに入ってるっぽいので略
ググって
要:socat+gdb(+peda)でexploitのデバッグを行う方法
pwntoolsも使ってる
Writeup見ながら覚える
使えるようになると強そう
因みに許可されていないサーバーでやると最悪法に触れるので厳禁
リンクを張っていく
- mmap
- socket系 LinuxとC/C++によるソケット通信サンプル
- http://katc.hateblo.jp/entry/2016/10/17/001753 複雑すぎだろ
- https://qiita.com/nicklegr/items/51cbc4ff59d245646988#classic-pwn-pwn
- Exploit系複合テクニックのメモ
大体黒猫参照
-
Heap系
Use After Free
Double Free
off-by-one error
House of XXX -
Race Condition
struct pack
pwntools
ROP Gadgets