Speaker Deck
Speaker Deck Pro
Sign in
Sign up
for free
RIG#3-1
RIG
October 09, 2019
Technology
0
54
RIG#3-1
2019/10/09に実施されたRIGの第3回勉強会で使用した発表資料「Shellcode Injectionの実践」です.
RIG
October 09, 2019
Tweet
Share
More Decks by RIG
See All by RIG
sfcrig
0
30
sfcrig
0
89
sfcrig
0
170
Other Decks in Technology
See All in Technology
oracle4engineer
1
210
suzukiry
0
200
line_developers
PRO
3
470
shimacos
2
280
zaki134rp
1
180
humank
0
210
tdys13
4
3.4k
unifa_dev
0
300
kurochan
0
530
vkbaba
0
100
kenya888
1
110
asaju7142501
0
250
Featured
See All Featured
hannesfritz
27
930
chriscoyier
684
180k
bryan
30
3.3k
kneath
219
15k
sstephenson
144
12k
destraynor
223
47k
addyosmani
1348
190k
lynnandtonic
270
16k
dotmariusz
94
5.1k
revolveconf
200
9.6k
ddemaree
274
31k
philhawksworth
192
8.8k
Transcript
Shellcode Injection RIG#3-1 (2019/10/09) Yuma Ueda (cyan)
Shellcode Injection • BOFを利用してコンピュータに任意コードを実行させる攻撃 • そもそも/bin/shなどシェルの実行を目的とした攻撃が大半であったためこの 種の攻撃を行うためのペイロードを総称してShellcodeと呼んでいる 2
How does it work? スタックオーバーフロー • スタックに乗っているリターンアドレスを書き換え,配置したshellcodeを実 行させる ヒープオーバーフロー •
ハンドラーなどのアドレスを書き換える 3
実践 • 何事も手を動かして実践,実証! • 簡単なpwnableの問題でshellcode Injectionを実践しよう! 4
start from pwnable.tw (https://pwnable.tw/challenge/#1) pwnable • 基本的にはサーバ上で動作するプログラ ムの脆弱性を突きflagを奪取する • バイナリはダウンロードさせてくれる
(当然) とりあえずディスアセンブル • objdump -D $path_to_binary • コマンドはLinux前提で書いてます • 右のような出力が得られる 5
start アセンブリを追う 8048060 push %esp 8048061 push $0x804809d <_exit> 8048066
xor %eax, %eax 8048068 xor %ebx, %ebx 804806a xor %ecx, %ecx old_esp esp 何をしている? • スタックにespの値を積む. • ここで注意すべきはpush %espが 実行され,espが4Byte下がる前の 値がスタックに積まれること. 6
start アセンブリを追う 8048060 push %esp 8048061 push $0x804809d <_exit> 8048066
xor %eax, %eax 8048068 xor %ebx, %ebx 804806a xor %ecx, %ecx old_esp 0x804809d <_exit> esp 何をしている? • _exitセクションのアドレスをス タックに積む(ここにRETしたい) 7
start アセンブリを追う 8048060 push %esp 8048061 push $0x804809d <_exit> 8048066
xor %eax, %eax 8048068 xor %ebx, %ebx 804806a xor %ecx, %ecx 804806c xor %edx, %edx old_esp 0x804809d <_exit> esp 何をしている? • レジスタのゼロクリアを行ってい る なんでmov %eax, $0じゃないの? • xor命令はバイナリサイズが小さい (2Byte) 8
start アセンブリを追う 804806c xor %edx, %edx 804806e push $0x3a465443 8048073
push $0x20656874 8048078 push $0x20747261 804807d push $0x74732073 8048082 push $0x2774654c old_esp 0x804809d <_exit> 0x3a465443 (:FTC) 0x20656874([ws]eht) 0x20747261 ([ws]tra) 0x74732073 (ts[ws]s) 0x2774654c(‘teL) esp 何をしている? • “Let’s start the CTF:”という文字列をスタックに積む(リトルエンディアン) 9
コラム: バイトオーダ リトルエンディアン • データの下位から1Byteずつメモリの 下位へ格納 10 ビッグエンディアン • データの上位から1Byteずつメモリの
下位へ格納 図は2つともhttp://www.ertl.jp/~takayuki/readings/info/no05.htmlより引用
start アセンブリを追う 8048082 push $0x2774654c 8048087 mov %esp, %ecx 8048089
mov $014, %dl 804808b mov $0x1, %bl 804808d mov $0x4, %al 804808f int $0x80 old_esp 0x804809d <_exit> 0x3a465443 (:FTC) 0x20656874([ws]eht) 0x20747261 ([ws]tra) 0x74732073 (ts[ws]s) 0x2774654c(‘teL) esp 11 int $0x80 • eaxに指定されたシステムコール番号に対応するシステムコールを発行 • システムコール番号→cat /usr/include/asm/unistd_32.h (今回は32bitなので) • 引数はどう渡すの?→この場合はbl, cl, dlと汎用レジスタに順に格納すればよい
start アセンブリを追う 8048082 push $0x2774654c 8048087 mov %esp, %ecx 8048089
mov $014, %dl 804808b mov $0x1, %bl 804808d mov $0x4, %al 804808f int $0x80 old_esp 0x804809d <_exit> 0x3a465443 (:FTC) 0x20656874([ws]eht) 0x20747261 ([ws]tra) 0x74732073 (ts[ws]s) 0x2774654c(‘teL) esp 12 何をしている? • 命令はwrite(1, esp, 20)と解釈できる • espから20Byte読み出す→”Let`s start the CTF:”と標準出力される 20Byte
start アセンブリを追う 804808f int $0x80 8048091 xor %ebx, %ebx 8048093
mov $0x3c, %dl 8048095 mov $0x3, %al 8048097 int $0x80 old_esp 0x804809d <_exit> 0x3a465443 (:FTC) 0x20656874([ws]eht) 0x20747261 ([ws]tra) 0x74732073 (ts[ws]s) 0x2774654c(‘teL) esp 13 60Byte 何をしている? • 命令はread(0, esp, 60)と解釈できる • 標準入力から受け取った文字列をespか ら60Byteまで書き込む
start アセンブリを追う 8048097 int $0x80 8048099 add $0x14, %esp 804809c
ret old_esp 0x804809d <_exit> 0x3a465443 (:FTC) 0x20656874([ws]eht) 0x20747261 ([ws]tra) 0x74732073 (ts[ws]s) 0x2774654c(‘teL) esp 14 何をしている? • スタックポインタを20Byte上げて ,ret命令を発行 • _exitセクションに処理が移る だがしかし • 先程のread命令が発行された際に 20Byte以上のデータが書き込まれてい れば,_exitセクションのアドレスが書 き換えられる. esp 60Byte
start アセンブリを追う 8048097 int $0x80 8048099 add $0x14, %esp 804809c
ret old_esp 0x804809d <_exit> 0x3a465443 (:FTC) 0x20656874([ws]eht) 0x20747261 ([ws]tra) 0x74732073 (ts[ws]s) 0x2774654c(‘teL) esp 15 何をしている? • スタックポインタを20Byte上げて ,ret命令を発行 • _exitセクションに処理が移る だがしかし • 先程のread命令が発行された際に 20Byte以上のデータが書き込まれてい れば,_exitセクションのアドレスが書 き換えられる. esp 60Byte esp
start ペイロードの作成 (1) readシステムコール発行 • |----適当な値20Byte----|----リターンしたいアドレス----| • 上記のようなデータを送信することで特定のアドレスに処理を移させられる ワンステップでShellcodeを実行させることはできない •
ASLR有効 &&スタックの上部の空間を使う→old_espの値をリークさせる必 要がある • 1回目のret実行後のesp→old_espを指している && このバイナリはespから 20Byteのデータをwriteシステムコールを発行し標準出力している→もう一 度この処理を呼び出せば出力の先頭4Byteにold_espが含まれる! • これを実現するために,0x8048087にリターンさせる 16
start ペイロードの作成 (2) 前ページの処理の実装 17 Pwntools • 有名なCTFチームがPwnableを解く際 に使ってるライブラリ •
pwntoolsのほうが好きなんだけど ,socketについてちゃんと知ってほ しい感じがあるので今回は使用しない
start ペイロードの作成 (3) Shellcodeの注入 • 処理が進んでいくと,再びreadシステ ムコールを発行する • | ----適当な値20Byte----
| ---- old_esp + 20 ---- | ---- Shellcode ---- | のようなデータを送信すること でShellcodeが実行される 18 old_esp 0x804809d <_exit> esp esp old_esp + 20 esp | old_esp + 20 Shellcode old_esp
start ペイロードの作成 (4) 前ページの処理の実装 • Shellが起動していることを確認できる • Shellcodeはragg2 -i exec
-b 32 で作成 • 19
start ペイロードの作成 (5) せっかくだしフラッグも取っていこう • 先程起動したShellでfind / -iname “*flag*”を実行 •
~/flagを確認できる 20
コラム: shellcodeとバリデーション対策 NULL文字排除 • Shellcode→文字列(char *)として与えられる→0x00を含むことができない • mov eax, 1
→ NULLバイトを含む • xor eax, eax inc eax→NULLバイトを含まない Unicode / 英数字のみShellcode • 上で示したような自己書き換えコードを用いて実現可能 21
参考文献 • https://blog.ohgaki.net/modern-shellcode-and-secure-defensive-progr amming (2019/10/08 参照) • http://www.ertl.jp/~takayuki/readings/info/no05.html (2019/10/08 参
照) • https://ja.wikipedia.org/wiki/%E3%82%B7%E3%82%A7%E3%83%AB% E3%82%B3%E3%83%BC%E3%83%89#%E7%AC%A6%E5%8F%B7%E5% 8C%96%E6%96%B9%E6%B3%95 (2019/10/08 参照) • http://web.archive.org/web/20150308214411/https://www.eecis.ude l.edu/~bmiller/cis459/2007s/readings/buff-overflow.html (2019/10/08 参照) 22