SlideShare a Scribd company logo
たのしいpwn
SSR_CTF_BU
CTFってなんやねん
•Capture The Flag
• 直訳するとはた取りゲーム
• FPSとかでも使われる単語らしい?
•機密文書という設定のテキストファイル(Flag)を読みだして提出すると点数に
• そのファイルは与えられた権限では読めなかったり
• そもそもサーバーに入れてもらえなかったり
• 暗号化されていたり
•という感じで普通には読めないファイルを†ハッキング†して読んでくれ、という
競技
例
•IFMMP DUG XPSME!
• これは暗号文です
• 解読してみよう
•アルファベットが一文字ずつずらされているだけ
• シーザー暗号
•HELLO CTF WORLD!
pwnってなんやねん
•さっき説明したCTFの問題ジャンルの一つ
• pwning,pwnablesとか言われる(ownが転じてpwnらしい)(どうでもいい)
• 昔iPhoneで遊ぶツールにpwnagetoolとかあったよね
•実行ファイルの脆弱性を突いて任意機械語を実行してね、という問
題ジャンル
• 大体シェル(/bin/sh)を開くことが多い
• CTFではファイルを読めれば勝ちなのでファイルを読むことも
• 個人的に一番†ハッキング†っぽいジャンルだと思います(何)
やってみる(その前に)
•そんなに難しいことをしているわけではない
•が、プログラミングを知らないと厳しい
• 必要な事前知識は解説しますが、時間の都合上駆け足にならざるを得ない
• 分からなくてもムリダナ(・x・)ってならないでほしい
• C言語講習会の後にもう一度見直すとまた違った見え方をするかも
• 「こんなことも出来るんだ!」という雰囲気を感じてほしい
アセンブリ言語ってなんや
(時間次第では飛ばす)
•C言語で書いたプログラムは機械語に変換されて動く
• 機械語は01列だが、01011101…だと読みづらいので16進数で書かれることが多い
• ex:31 ffで xor edi,edi
• ediレジスタ同士でXORを取り、その結果をediに代入するという意味、これを行うと
ediに0を入れることができる
•31 ffとかいきなり言われてもなんのことだかわからないので人間に
分かりやすいように書きたい、それがアセンブリ言語
•アセンブリ言語は機械語と一対一対応する
• 上記の例だと、31 ffは絶対xor edi , edi、それ以外にはならない
•C言語は機械語と一対一対応しない
• 同じプログラムでもコンパイラや最適化度合で違う機械語が出る(動作は同じ)
アセンブリ言語ってなんや2
gccによるコンパイル結果
x86アセンブリ速習(まさかりを投げるな)
•これからの話を聞くのに必要最低限の命令だけ列記
• オペランドの種類とか面倒な部分はカット(今回の主目的でないため)
•mov dst , src :srcをdstにコピー
•push src :srcをスタックにプッシュ
•pop dst :dstにスタックからポップ
•call arg :次の命令のアドレス(戻り先)をスタックにpushし、argにジャンプ
•ret :スタックから 戻り先を取り出してそこにジャンプ
スタック1(時間次第で飛ばす)
•スタックの話(x86の話です、スタックが無いアーキテクチャもあり)
• プログラムが実行される時、ほとんどの情報はスタックに乗る
• よくお皿を積み上げていくことに例えられるデータ構造
8
push 8 push 0push 1
1
8
0
1
8
1
8
pop (0が出てくる)
スタック2 (時間次第で飛ばす)
•関数を呼び出す時、引数の情報はスタックに乗る
• esp:スタックのてっぺん(stack pointer)
• ebp:スタックの底(base pointer)
esp
ebp
4
1
5
4
1
1
スタック3
以下のコードが実行される時のスタックの様子を追いかけてみる
0x08048430 <+6>: sub esp,0x10 #スタック領域を0x10バイト確保
0x08048433 <+9>: mov DWORD PTR [esp+0x4],0x202 #スタックに514を書き込み
0x0804843b <+17>: mov DWORD PTR [esp],0x72 #514の一個上に114を書き込み
0x08048442 <+24>: call 0x804841d <func> #func呼び出し
0x08048447 <+29>: mov DWORD PTR [esp+0x4],eax #funcの結果をスタックに書きこみ
0x0804844b <+33>: mov DWORD PTR [esp],0x80484f0 #文字列のアドレスをスタックに書き込み
0x08048452 <+40>: call 0x80482f0 <printf@plt> printf呼び出し
0x08048457 <+45>: leave #このプログラムのためのスタック領域を後始末
0x08048458 <+46>: ret #終
func関数の中身
0x0804841d <+0>: push ebp
0x0804841e <+1>: mov ebp,esp
0x08048420 <+3>: mov eax,DWORD PTR [ebp+0xc]
0x08048423 <+6>: mov edx,DWORD PTR [ebp+0x8]
0x08048426 <+9>: add eax,edx
0x08048428 <+11>:pop ebp
0x08048429 <+12>:ret
sub esp 0x10
0xffffd178
0xffffd160 esp
esp
新たに0x10(16)バイトのスタック
領域を確保
ebp
mov二つ
114(0x72)
514(0x202)
0xffffd178
0xffffd160 esp
mov DWORD PTR [esp+0x4],0x202
mov DWORD PTR [esp],0x72
ebp
esp+4
call func
0x8048447
114(0x72)
514(0x202)
0xffffd178
0xffffd160
esp
C言語で表すとfunc(114,514);
第二引数->第一引数の順で積まれ
ていることがわかる
ここでの0x8048447は戻り先(callの
次のアドレス)
手元でスライドを見れる人は見ると
callの次の命令のアドレスだ
ということが分かるはず
ここで、処理は関数func内に移るebp
push ebp (時間次第で飛ばす)
0xffffd178
0x8048447
114(0x72)
514(0x202)
0xffffd178
0xffffd160
esp
関数func用の新たなスタック領域を
用意するが、mainに戻った時の
ために古いebp(スタックの底)を
スタックに記録しておく
ebp
mov ebp,esp
0xffffd178
0x8048447
114(0x72)
514(0x202)
0xffffd178
0xffffd160
esp
スタックの底を更新
ebp
mov eax,DWORD PTR [ebp+0xc]
mov edx,DWORD PTR [ebp+0x8]
0xffffd178
0x8048447
114(0x72)
514(0x202)
0xffffd178
0xffffd160
esp
ebp+0xcとebp+0x8はmain関数で
スタックに積んだ引数です
それをそれぞれeaxレジスタとedx
レジスタに入れています
eax=514
edx=114
ebp
ebp+0x8
ebp+0xc
add eax,edx
0xffffd178
0x8048447
114(0x72)
514(0x202)
0xffffd178
0xffffd160
esp
func関数の足し算の本質部分です
さっき入れた二つの数値を足し算
してeaxに入れています
(eax=eax+edx)
ちなみに関数の戻り値はeaxで
返されます
ebp
ebp+0x8
ebp+0xc
pop ebp (時間次第で飛ばす)
0xffffd178
0x8048447
114(0x72)
514(0x202)
0xffffd178
0xffffd160
esp 関数の先頭で保存したebp(スタック
の底)をポップします
これにより、スタックの底は再度
main関数のものに戻ります
ebp
ret
0xffffd178
0x8048447
114(0x72)
514(0x202)
0xffffd178
0xffffd160
esp callによって保存した戻り先(リター
ンアドレス)を使って戻ります。
次の命令(espが指している部分に
格納されている)は0x8048447です。
ebp
mov DWORD PTR [esp+0x4],eax
0xffffd178
0x8048447
114(0x72)
628(0x274)
0xffffd178
0xffffd160 esp
無事戻ってくることが出来たので
処理は続き、printfの引数をスタック
に積みます。
この時、eaxにはfuncの戻り値が
入っています。
ebp
今回扱う脆弱性
•関数を呼び出す時には戻り先をスタックに載せているらしい
• もしも戻り先がユーザーによって書き換えられてしまったら任意の場所
に処理を飛ばせてしまうのでは?
•バッファーオーバーフロー
• 確保したメモリの領域を超えて書き込んでしまう事
• これにより実際に戻り先を任意の場所にできてしまう!
脆弱なコード
C言語講習会とかでもやるはず
#include <stdio.h>
int main(){
char buf[10];
printf("buf_addr=%pn",buf);
printf(“what is your name?n> ");
scanf("%s",buf);
printf("Hello %s!n" ,buf);
return 0;
}
脆弱性
•なにがやばいの><
• scanfは長さを確認しないで入力を受け取ってしまう。
• buf[10]で10バイトしか領域を確保していない(本当はアラインメント等でもっと確保さ
れることもある)ので、それ以上の入力が来たらさっきの戻り先を上書きしてしまうか
も。
• やってみよう
これならセーフ(本当はアウト)
AAAA
AAAA
AAAA
0xdeadbeef
…
bufの先頭アドレス
戻り先アドレス
リターンアドレスは壊れていな
いので正しく戻れるが、関数
先頭でスタックに保存されて
いるはずのebpの値は破壊さ
れているので、戻った後ebp
の値が0x41414141(AAAA)に
なります
こうなるとヤバイ
AAAA
AAAA
AAAA
AAAA(0x41414141)
…
bufの先頭アドレス
戻り先アドレス
scanfの入力が想定より大き
かったためリターンアドレスを
上書きしてしまった!
任意コード実行の方針
AAAA
AAAA
AAAA
0xbeefbabe
シェルを起動するための
機械語列
bufの先頭アドレス
戻り先アドレス
入力であらかじめシェル起動
のための機械語列を
読み込んでおいて、
戻り先アドレスをそこに
すれば良い。
0xbeefbabe
既にやってみたものがこちらになります
文字列が格納されるbufの
アドレスが毎回変わって
いる
なにこれ
脆弱性の緩和策
•典型的な脆弱性にはOS側で緩和策が取られている
• ASLR(address space layout randomization)
• DEP(data execution prevention)
• SSP(stack-smashing protection)
•実際のCTFではこれらを回避して任意コードを実行せねばならない
が、今回は簡単のため全部外す
ASLR
•先ほど述べたスタックや、mallocなどで割り当てられるヒープのアドレスをラン
ダムにする機構
•スタックのアドレスがランダムだと、スタックに機械語を読み込み、それを実行
する、ということが難しくなる(リターンアドレスをどこにすればいいかわからない
ため。)
•これがオンになっている場合は、必要なアドレスのリークから始める(writeで標
準出力に書きだすとか)
•$ sudo sysctl –w kernel.randomize_va_space=0で無効化できる
DEP
•データ実行防止
• スタック上の機械語を実行することは普通は無い
• じゃあスタックを実行不可能にすればさっきみたいな攻撃は防げるよね
•実行ファイルに入っている機械語は実行できるのでそれをつぎはぎすれば攻
撃可能(ROP)
• 現実のゲーム機(3〇Sとか)のハックなどでも使われているテク
•コンパイル時に以下のオプションを付ければスタックが実行可能になる
• gcc –z execstack
SSP
•なんとかしてバッファーが溢れているのを検知できないか?
• スタックの底部分に検査用の値を仕込んでおいて、その値が書き変わっていたら不
正としてプログラムを落とせばよくない?
• 検査用の値のことをcanaryという(炭鉱のカナリアが由来らしい)
•正直CTFでこれがオンになっていると相当しんどい(つまり優秀な緩和策)
• SECCON 2016 Online CTF checker
• シェルを取るのは諦めて、SSP由来の情報漏洩を狙う
•canaryをリークしたり、SSP由来の情報漏洩を狙ったり手はいろいろ
• 他の脆弱性を探す事も
•$ gcc -fno-stack-protector bof.c でオフに出来る
任意コード実行の方針(再掲)
AAAA
AAAA
AAAA
0xbeefbabe
シェルを起動するための
機械語列
bufの先頭アドレス
戻り先アドレス
入力であらかじめシェル起動
のための機械語列を
読み込んでおいて、
戻り先アドレスをそこに
すれば良い。
0xbeefbabe
実際にやってみます
•$ sudo sysctl –w kernel.randomize_va_space=0 でASLR無効化
•$ gcc –m32 -fno-stack-protector -z execstack bof.c でコンパイル
•(python o.py [bufのアドレス] ; cat) | ./a.out
• python o.pyの結果を流し込んだ後、catでターミナルから入力を受け取ってそれ
を./a.outに流し込む
• シェルが起動していることが確認できるはずです(失敗したらごめん)
• pythonを使うのは、キーボードから入力できない文字を入力するから
• 0xffとか
宣伝2
•ロボット技術研究会としてCTFの大会に参加しています
• SSR_CTF_BU(CTF部という意味)
• SECCONの決勝大会に行ったりもした
• 興味を持ったら(@ymduu)まで。
参考文献(おすすめの本とか)
•セキュリティコンテストチャレンジブック
• CTFを始めるならコレ
• バイナリ問題の入門には最適
• Webやるならちょっと足りないかも
•Hacking: 美しき策謀 第2版 ―脆弱性攻撃の理論と実際
• 表紙がかっこいい
• 暗号とかも載ってる
•ももテク(ももいろテクノロジー)
• ブログ
• いろんなexploitテクが載っている
• http://inaz2.hatenablog.com/entry/2014/03/14/151011
まとめ
•今回は一番簡単かつ王道な攻撃手法を紹介しました
• シェルコード実行
•実際のCTFではセキュリティ機構(緩和策)があったりそもそもバイナリが大き
かったりと色々な手法を要求されます
•楽しい
•CTFやろうぜ!
•おはり
質問とか
NOPスレッド
•言ってもbufのアドレス表示してるのズルくない?
• 返す言葉もございません
•普通はbufのアドレスは分からないのでROPとかでリークをする(説明は長くなる
のでまたの機会)
•分からなくてもアドレスを適当にやって当ててしまえばいいのだ
• 無理
•一点張りで当てるのは無理でもこの区間に当たればシェル起動する、とかなら
なんだか行ける気がする
• 何もしない命令でその区間を埋めてしまえばいいのでは?
NOPスレッド2
x90x90x90x90
x90x90x90x90
……
……
x90x90x90x90
シェルを起動する
為の機械語列
シェルコードの前にNOP(x90)*大量
を入れる
->どこのNOPにジャンプしてもいいので
アドレスを適当にしても成功率がUP
どこにretしてもOK!
0x????????
NOP:「何もしない」という命令

More Related Content

What's hot

いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門
Fixstars Corporation
 
MCC CTF講習会 pwn編
MCC CTF講習会 pwn編MCC CTF講習会 pwn編
MCC CTF講習会 pwn編
hama7230
 
【DL輪読会】The Forward-Forward Algorithm: Some Preliminary
【DL輪読会】The Forward-Forward Algorithm: Some Preliminary【DL輪読会】The Forward-Forward Algorithm: Some Preliminary
【DL輪読会】The Forward-Forward Algorithm: Some Preliminary
Deep Learning JP
 
さくっとはじめるテキストマイニング(R言語)  スタートアップ編
さくっとはじめるテキストマイニング(R言語)  スタートアップ編さくっとはじめるテキストマイニング(R言語)  スタートアップ編
さくっとはじめるテキストマイニング(R言語)  スタートアップ編
Yutaka Shimada
 
先端技術とメディア表現1 #FTMA15
先端技術とメディア表現1 #FTMA15先端技術とメディア表現1 #FTMA15
先端技術とメディア表現1 #FTMA15
Yoichi Ochiai
 
異常検知と変化検知 9章 部分空間法による変化点検知
異常検知と変化検知 9章 部分空間法による変化点検知異常検知と変化検知 9章 部分空間法による変化点検知
異常検知と変化検知 9章 部分空間法による変化点検知
hagino 3000
 
SSII2021 [OS2-01] 転移学習の基礎:異なるタスクの知識を利用するための機械学習の方法
SSII2021 [OS2-01] 転移学習の基礎:異なるタスクの知識を利用するための機械学習の方法SSII2021 [OS2-01] 転移学習の基礎:異なるタスクの知識を利用するための機械学習の方法
SSII2021 [OS2-01] 転移学習の基礎:異なるタスクの知識を利用するための機械学習の方法
SSII
 
関数型プログラミング入門 for Matlab ユーザー
関数型プログラミング入門 for Matlab ユーザー関数型プログラミング入門 for Matlab ユーザー
関数型プログラミング入門 for Matlab ユーザー
Ichiro Maruta
 
DSB2019振り返り会:あのにっくき QWK を閾値調整なしで攻略した(かった)
DSB2019振り返り会:あのにっくき QWK を閾値調整なしで攻略した(かった)DSB2019振り返り会:あのにっくき QWK を閾値調整なしで攻略した(かった)
DSB2019振り返り会:あのにっくき QWK を閾値調整なしで攻略した(かった)
Takuji Tahara
 
#経済学のための実践的データ分析 12. 機械学習とAIな経済学と最終レポート
#経済学のための実践的データ分析 12. 機械学習とAIな経済学と最終レポート#経済学のための実践的データ分析 12. 機械学習とAIな経済学と最終レポート
#経済学のための実践的データ分析 12. 機械学習とAIな経済学と最終レポート
Yasushi Hara
 
自然言語処理のためのDeep Learning
自然言語処理のためのDeep Learning自然言語処理のためのDeep Learning
自然言語処理のためのDeep LearningYuta Kikuchi
 
規格書で読むC++11のスレッド
規格書で読むC++11のスレッド規格書で読むC++11のスレッド
規格書で読むC++11のスレッド
Kohsuke Yuasa
 
Scapyで作る・解析するパケット
Scapyで作る・解析するパケットScapyで作る・解析するパケット
Scapyで作る・解析するパケット
Takaaki Hoyo
 
Pythonと型チェッカー
Pythonと型チェッカーPythonと型チェッカー
Pythonと型チェッカー
Tetsuya Morimoto
 
こわくない Git
こわくない Gitこわくない Git
こわくない Git
Kota Saito
 
continual learning survey
continual learning surveycontinual learning survey
continual learning survey
ぱんいち すみもと
 
数学で解き明かす深層学習の原理
数学で解き明かす深層学習の原理数学で解き明かす深層学習の原理
数学で解き明かす深層学習の原理
Taiji Suzuki
 
CTF超入門 (for 第12回セキュリティさくら)
CTF超入門 (for 第12回セキュリティさくら)CTF超入門 (for 第12回セキュリティさくら)
CTF超入門 (for 第12回セキュリティさくら)
kikuchan98
 
ctfで学ぼうリバースエンジニアリング
ctfで学ぼうリバースエンジニアリングctfで学ぼうリバースエンジニアリング
ctfで学ぼうリバースエンジニアリング
junk_coken
 
パターン認識と機械学習 §6.2 カーネル関数の構成
パターン認識と機械学習 §6.2 カーネル関数の構成パターン認識と機械学習 §6.2 カーネル関数の構成
パターン認識と機械学習 §6.2 カーネル関数の構成
Prunus 1350
 

What's hot (20)

いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門
 
MCC CTF講習会 pwn編
MCC CTF講習会 pwn編MCC CTF講習会 pwn編
MCC CTF講習会 pwn編
 
【DL輪読会】The Forward-Forward Algorithm: Some Preliminary
【DL輪読会】The Forward-Forward Algorithm: Some Preliminary【DL輪読会】The Forward-Forward Algorithm: Some Preliminary
【DL輪読会】The Forward-Forward Algorithm: Some Preliminary
 
さくっとはじめるテキストマイニング(R言語)  スタートアップ編
さくっとはじめるテキストマイニング(R言語)  スタートアップ編さくっとはじめるテキストマイニング(R言語)  スタートアップ編
さくっとはじめるテキストマイニング(R言語)  スタートアップ編
 
先端技術とメディア表現1 #FTMA15
先端技術とメディア表現1 #FTMA15先端技術とメディア表現1 #FTMA15
先端技術とメディア表現1 #FTMA15
 
異常検知と変化検知 9章 部分空間法による変化点検知
異常検知と変化検知 9章 部分空間法による変化点検知異常検知と変化検知 9章 部分空間法による変化点検知
異常検知と変化検知 9章 部分空間法による変化点検知
 
SSII2021 [OS2-01] 転移学習の基礎:異なるタスクの知識を利用するための機械学習の方法
SSII2021 [OS2-01] 転移学習の基礎:異なるタスクの知識を利用するための機械学習の方法SSII2021 [OS2-01] 転移学習の基礎:異なるタスクの知識を利用するための機械学習の方法
SSII2021 [OS2-01] 転移学習の基礎:異なるタスクの知識を利用するための機械学習の方法
 
関数型プログラミング入門 for Matlab ユーザー
関数型プログラミング入門 for Matlab ユーザー関数型プログラミング入門 for Matlab ユーザー
関数型プログラミング入門 for Matlab ユーザー
 
DSB2019振り返り会:あのにっくき QWK を閾値調整なしで攻略した(かった)
DSB2019振り返り会:あのにっくき QWK を閾値調整なしで攻略した(かった)DSB2019振り返り会:あのにっくき QWK を閾値調整なしで攻略した(かった)
DSB2019振り返り会:あのにっくき QWK を閾値調整なしで攻略した(かった)
 
#経済学のための実践的データ分析 12. 機械学習とAIな経済学と最終レポート
#経済学のための実践的データ分析 12. 機械学習とAIな経済学と最終レポート#経済学のための実践的データ分析 12. 機械学習とAIな経済学と最終レポート
#経済学のための実践的データ分析 12. 機械学習とAIな経済学と最終レポート
 
自然言語処理のためのDeep Learning
自然言語処理のためのDeep Learning自然言語処理のためのDeep Learning
自然言語処理のためのDeep Learning
 
規格書で読むC++11のスレッド
規格書で読むC++11のスレッド規格書で読むC++11のスレッド
規格書で読むC++11のスレッド
 
Scapyで作る・解析するパケット
Scapyで作る・解析するパケットScapyで作る・解析するパケット
Scapyで作る・解析するパケット
 
Pythonと型チェッカー
Pythonと型チェッカーPythonと型チェッカー
Pythonと型チェッカー
 
こわくない Git
こわくない Gitこわくない Git
こわくない Git
 
continual learning survey
continual learning surveycontinual learning survey
continual learning survey
 
数学で解き明かす深層学習の原理
数学で解き明かす深層学習の原理数学で解き明かす深層学習の原理
数学で解き明かす深層学習の原理
 
CTF超入門 (for 第12回セキュリティさくら)
CTF超入門 (for 第12回セキュリティさくら)CTF超入門 (for 第12回セキュリティさくら)
CTF超入門 (for 第12回セキュリティさくら)
 
ctfで学ぼうリバースエンジニアリング
ctfで学ぼうリバースエンジニアリングctfで学ぼうリバースエンジニアリング
ctfで学ぼうリバースエンジニアリング
 
パターン認識と機械学習 §6.2 カーネル関数の構成
パターン認識と機械学習 §6.2 カーネル関数の構成パターン認識と機械学習 §6.2 カーネル関数の構成
パターン認識と機械学習 §6.2 カーネル関数の構成
 

たのしいPwn 公開用