ハッキング実演 2018
平木 康傑
はじめまして
• 平木と申します
• 普段は趣味で競技プログラミングをしています
• IOI(国際情報オリンピック)という数学オリンピックの親戚がある
• 今年は日本で開催
• IAちゃんが歌うよ!
• 高3のプロが日本代表に選ばれました
• 僕も2軍として戦力外から国際大会に参加します
何をするの
• 今回は脆弱な暗号化を破ります
• 脆弱(ぜいじゃく): 安全でない,もろい
• 結構ヤバい代物ですが,実は小学生でも理解できます
• 去年を反省して分かりやすさを心がけています
何をするの
• 本来はブロッキングに関連したやつ(こっちも結構ヤバい)をするつもりだった
• 何度やっても再現できなかったのでLTに回した
• CombNada見てね
はじまりはじまり
• 背景がきれい
旅路の地図
• 後で書く
よく見るアレ
• 見たことありますか?
↑この緑のやつ↑
通信
• ブラウザ君(クライアント)とサーバ君が文通をしている
通信
• ブラウザ君(クライアント)とサーバ君が文通をしている
• ク「やっほ^^」
通信
• ブラウザ君(クライアント)とサーバ君が文通をしている
• ク「やっほ^^」
• サ「ん,あんたか」
通信
• ブラウザ君(クライアント)とサーバ君が文通をしている
• ク「やっほ^^」
• サ「ん,あんたか」
• ク「サーバ君,早速だけどそっちのページ見せて?おいしいクッキーあげるから」
通信
• ブラウザ君(クライアント)とサーバ君が文通をしている
• ク「やっほ^^」
• サ「ん,あんたか」
• ク「サーバ君,早速だけどそっちのページ見せて?おいしいクッキーあげるから」
• サ「はいはい.これだよ: (コンテンツ)」
通信
• ブラウザ君(クライアント)とサーバ君が文通をしている
• ク「やっほ^^」
• サ「ん,あんたか」
• ク「サーバ君,早速だけどそっちのページ見せて?おいしいクッキーあげるから」
• サ「はいはい.これだよ: (コンテンツ)」
• 変態郵便屋 (へぇ~…)
通信
• ブラウザ君(クライアント)とサーバ君が文通をしている
• ク「やっほ^^」
• サ「ん,あんたか」
• ク「サーバ君,早速だけどそっちのページ見せて?おいしいクッキーあげるから」
• サ「はいはい.これだよ: (コンテンツ)」
• 変態郵便屋 (へぇ~…)
• 覗かれる!
通信
• ブラウザ君(クライアント)とサーバ君が文通をしている
• ク「はい,手作りクッキー!サーバ君にあげる!」
通信
• ブラウザ君(クライアント)とサーバ君が文通をしている
• ク「はい,手作りクッキー!サーバ君にあげる!」
• 変態郵便屋 (やっぱり恋する乙女のクッキーは美味いな)
通信
• ブラウザ君(クライアント)とサーバ君が文通をしている
• ク「はい,手作りクッキー!サーバ君にあげる!」
• 変態郵便屋 (やっぱり恋する乙女のクッキーは美味いな)
• 変態郵便屋 (しまった,つい…そうだ!偽の手紙を用意しよう…)
通信
• ブラウザ君(クライアント)とサーバ君が文通をしている
• ク「はい,手作りクッキー!サーバ君にあげる!」
• 変態郵便屋 (やっぱり恋する乙女のクッキーは美味いな)
• 変態郵便屋 (しまった,つい…そうだ!偽の手紙を用意しよう…)
• ク(偽)『ごめん…家が燃えちゃった…クッキーはまた今度ね…』
通信
• ブラウザ君(クライアント)とサーバ君が文通をしている
• ク「はい,手作りクッキー!サーバ君にあげる!」
• 変態郵便屋 (やっぱり恋する乙女のクッキーは美味いな)
• 変態郵便屋 (しまった,つい…そうだ!偽の手紙を用意しよう…)
• ク(偽)『ごめん…家が燃えちゃった…クッキーはまた今度ね…』
• サ「は?」
通信
• ブラウザ君(クライアント)とサーバ君が文通をしている
• ク「はい,手作りクッキー!サーバ君にあげる!」
• 変態郵便屋 (やっぱり恋する乙女のクッキーは美味いな)
• 変態郵便屋 (しまった,つい…そうだ!偽の手紙を用意しよう…)
• ク(偽)『ごめん…家が燃えちゃった…クッキーはまた今度ね…』
• サ「は?」
• 内容をいじられる!
• これを改竄(かいざん)といいます
SSL/TLS
• 悪いやつから文通の内容を守りたい
• そこで暗号化をする
• 厳密には本人確認もいるけどそこは今回の話の本質ではない
• 鍵を用意して,それで暗号化しながら通信を行う
• 『サマーウォーズ』でも出てきたRSA暗号はここや本人確認でよく使われる
SSL/TLS
• 悪いやつから文通の内容を守りたい
• そこで暗号化をする
• 厳密には本人確認もいるけどそこは今回の話の本質ではない
• 鍵を用意して,それで暗号化しながら通信を行う
• 『サマーウォーズ』でも出てきたRSA暗号はここや本人確認でよく使われる
• 暗号化のプロトコル(仕組み)がSSL/TLS
あなたはだあれ
• Webサイトが,ログインしたことを覚えてくれていることがあります
• YouTubeとか
• どうやって覚えてるんだろう?
あなたはだあれ
• Webサイトが,ログインしたことを覚えてくれていることがあります
• YouTubeとか
• どうやって覚えてるんだろう?
• Cookieやセッションというものがある
COOKIE? セッション?
画像出典: ぱくたそ
COOKIE
• ユーザがどんな情報に興味があるのかを調べるために,ページへのアクセス回数を記録
したいとします
ブラウザ サーバ
COOKIE
• ユーザがどんな情報に興味があるのかを調べるために,ページへのアクセス回数を記録
したいとします
• 初めてアクセスした時に…
ブラウザ サーバ
COOKIE
• ユーザがどんな情報に興味があるのかを調べるために,ページへのアクセス回数を記録
したいとします
• 初めてアクセスした時に
サーバが”1回目”という情報を発行し,ブラウザに送信して覚えさせる
ブラウザ サーバ
1回目
1回目(Cookie)
COOKIE
• ユーザがどんな情報に興味があるのかを調べるために,ページへのアクセス回数を記録
したいとします
• 初めてアクセスした時に
サーバが”1回目”という情報を発行し,ブラウザに送信して覚えさせる
• 2回目以降はブラウザが既に情報を持っているので,それをサーバに送信
ブラウザ サーバ
42回目
42回目(Cookie)
COOKIE
• ユーザがどんな情報に興味があるのかを調べるために,ページへのアクセス回数を記録
したいとします
• 初めてアクセスした時に
サーバが”1回目”という情報を発行し,ブラウザに送信して覚えさせる
• 2回目以降はブラウザが既に情報を持っているので,それをサーバに送信
サーバはそれをもとに,新しく情報を発行してブラウザに渡す
ブラウザ サーバ
43回目
43回目(Cookie)
42回目(Cookie)
COOKIE
• Cookieはサーバが発行してブラウザが記録する情報
• “回数: 43”といったようにキーと値のペアで保持する
• これはSessionも同様
ブラウザ サーバ
43回目
43回目(Cookie)
42回目(Cookie)
SESSION
• ログインしている間,本人確認をしないといけない
• ユーザ名とパスワードを一々送っていては面倒だし危険
ブラウザ サーバ
User: Nada-taro, Password: 1nf|n!+y8
SESSION
• ログインしている間,本人確認をしないといけない
• ユーザ名とパスワードを一々送っていては面倒だし危険
• そこでユーザに対応するSession IDを発行する
ブラウザ サーバ
User: Nada-taro, Password: 1nf|n!+y8
538b2df7 -> Nada-taro
SESSION
• ログインしている間,本人確認をしないといけない
• ユーザ名とパスワードを一々送っていては面倒だし危険
• そこでユーザに対応するSession IDを発行し,割り振られた本人側に送る
ブラウザ サーバ
User: Nada-taro, Password: 1nf|n!+y8
SessionID: 538b2df7
538b2df7 -> Nada-taro538b2df7
SESSION
• ログインしている間,本人確認をしないといけない
• ユーザ名とパスワードを一々送っていては面倒だし危険
• そこでユーザに対応するSession IDを発行し,割り振られた本人側に送る
• ブラウザはSession IDを使用期限の短いCookieとして記録し,ログイン情報として使う
ブラウザ サーバ
I am 538b2df7. ChangePassword: steamisfun
Successfully changed.
538b2df7 -> Nada-taro538b2df7
SESSION
• ログインしている間,本人確認をしないといけない
• ユーザ名とパスワードを一々送っていては面倒だし危険
• そこでユーザに対応するSession IDを発行し,割り振られた本人側に送る
• ブラウザはSession IDを使用期限の短いCookieとして記録し,ログイン情報として使う
• Session IDを知らないと本人確認をパスできない!
悪いやつ サーバ
I am 11451419. ChangePassword: 12345678
F*ck you.
538b2df7 -> Nada-taroSessionIDを知らない
SESSION
• Cookieと違って,Sessionはサーバが発行してサーバが記録する
• クライアントごとに割り振られたSessionIDを,
寿命の短いCookieとしてブラウザ側で保存
ブラウザ サーバ
I am 538b2df7. ChangePassword: steamisfun
Successfully changed.
538b2df7 -> Nada-taro538b2df7
SSL/TLSの説明に入る
• その前に
データ→バイト列
• コンピュータ上で,データは2進法での数値や数値列(=「バイト列」)として扱われる
• 文章,音声,画像,動画,プログラム,あらゆるファイル
• 2進法での1桁を1bitという
• 2進法での8桁=8bitを,1byteとする
• 厳密さのためにoctetということも多いです
• 1byteのデータは00~FF (0~255)の範囲にある,28 = 256個の整数を表せる
• 1byteのデータを並べた列を「バイト列」という
• 8つ並べたら「長さ8のバイト列」
10110101
↑1bit
↑ 8bit = 1byte ↑
F8 04 8C 9A DE AD BE EF
↑8bit
XOR (排他的論理和)
• XORという演算がある
• 足し算を改造した感じのやつ
• 結構うれしい性質を持つ
• こいつが足し算だ!!!!→
1 0 1 1 0 1 0 1
1 0 0 1 1 1 0 1
0 1 0 1 0 0 1 0
+
XOR (排他的論理和)
• XORという演算がある
• 足し算を改造した感じのやつ
• 結構うれしい性質を持つ
• こいつが足し算だ!!!!→
1 0 1 1 0 1 0 1
1 0 0 1 1 1 0 1
0 1 0 1 0 0 1 0
+
XOR (排他的論理和)
• XORという演算がある
• 足し算を改造した感じのやつ
• 結構うれしい性質を持つ
• こいつが足し算だ!!!!→
• かわいそう
1 0 1 1 0 1 0 1
1 0 0 1 1 1 0 1
0 1 0 1 0 0 1 0
+
XOR (排他的論理和)
• XORという演算がある
•
• こいつがXORだ!!!!→
1 0 1 1 0 1 0 1
1 0 0 1 1 1 0 1
0 0 1 0 1 0 0 0
⊕
XOR (排他的論理和)
• XORという演算がある
• 足し算には繰り上がりがあったが,
XORでは繰り上がりを無視する
• こいつがXORだ!!!!→
1 0 1 1 0 1 0 1
1 0 0 1 1 1 0 1
0 0 1 0 1 0 0 0
⊕
XOR (排他的論理和)
• XORという演算がある
• 足し算には繰り上がりがあったが,
XORでは繰り上がりを無視する
• こいつがXORだ!!!!→
• もっと簡単に言うと,
同じ桁は0に,違う桁は1になる
1 0 1 1 0 1 0 1
1 0 0 1 1 1 0 1
0 0 1 0 1 0 0 0
⊕
XOR (排他的論理和)
• XORという演算がある
• 足し算には繰り上がりがあったが,
XORでは繰り上がりを無視する
• こいつがXORだ!!!!→
• もっと簡単に言うと,
同じ桁は0に,違う桁は1になる
• 桁溢れも起きない
1 0 1 1 0 1 0 1
1 0 0 1 1 1 0 1
0 0 1 0 1 0 0 0
⊕
XORのうれしい性質
• A⊕(B⊕C) = (A⊕B)⊕C …結合法則
• A⊕B = B⊕A …交換法則
• A⊕A = 0
• 足し算みたいな感覚で扱える
• [ ] ⊕ A = Bの形の式から[ ]を逆算できる
1 0 1 1 0 1 0 1
1 0 0 1 1 1 0 1
0 0 1 0 1 0 0 0
⊕
LET’S ENCRYPT!
• やっと本題
• ここではSSL3.0について話します
ブロック暗号
• 共有鍵暗号方式のひとつ
• 暗号はこれと公開鍵暗号に大別される
• 共有鍵暗号はこれとストリーム暗号に大別される
• AESが有名
• 入力が特定の桁数(AESなら128bit)で固定,鍵の長さにも制約あり
• 今回は深くは触れません
入力の長さ
• 当然世の中の通信が全部128bitの長さというわけにはいかない(大抵はもっと長い)
• じゃあどうする?
入力の長さ
• 当然世の中の通信が全部128bitの長さというわけにはいかない(大抵はもっと長い)
• じゃあどうする?
• 分割すればいい!
暗号利用モード
• 平文を128bitごとのブロックに分割する
• 足りない部分は”パディング”(詰め物)で埋める
• これらのブロックをどう扱うかの方法を「暗号利用モード」という
平文
ブロック ブロック ブロック ブ ロック
暗号利用モード
• 平文を128bitごとのブロックに分割する
• 足りない部分は”パディング”(詰め物)で埋める
• これらのブロックをどう扱うかの方法を「暗号利用モード」という
• SSL3.0のブロック暗号ではCBC方式というものが使われる
平文
ブロック ブロック ブロック ブ ロック
準備はOK?
• ついてこれた?
• ここからが肝心
最も単純な方式(ECB方式)
• 皆さんの中にも
思いついた方がいると
思います
• 同じブロックを
暗号化すると
常に同じ結果になる
• 使うべきでない
暗号化
CIPHER 3
PLAIN 3
暗号化
CIPHER 2
PLAIN 2
暗号化
CIPHER 1
PLAIN 1
CBC方式
• 1976年にIBMが開発
暗号化
CIPHER 3
PLAIN 3
XOR
暗号化
CIPHER 2
PLAIN 2
XOR
暗号化
CIPHER 1
PLAIN 1
XOR
IV
CBC方式
• 1976年にIBMが開発
• 平文ブロックに
「直前の暗号ブロック」とXORしてから
暗号化にかける
• 同じブロックでも違う結果になるので
より安全
暗号化
CIPHER 2
PLAIN 2
XOR
CIPHER 1
CBC方式
• 1976年にIBMが開発
• 平文ブロックに
「直前の暗号ブロック」とXORしてから
暗号化にかける
• 同じブロックでも違う結果になるので
より安全
• 最初のブロックではランダムに生成した ブロック(IV) を
XORのために使う
暗号化
CIPHER 1
PLAIN 1
XOR
IV
CBC方式の復号
• 暗号ブロックを復号した後,
「直前の暗号ブロック」とXORする
• 要はさっきの逆をするだけ
• かんたん
CIPHER 1
復号
CIPHER 2
PLAIN 2
XOR
SSL3.0の弱かったところ
• SSL3.0ちゃんはドジっ子なので今までも様々なヤバい脆弱性を指摘されてきた
• 野獣に喰われたり(BEAST, 2011年)悪魔に憑かれたり(Lucky Thirteen, 2013年)
• なんとか対策してきたが,POODLE攻撃(2014.10.14)で遂にとどめを刺された
• 突かれた穴は「パディングの正当性を判断する方法が雑だった」
パディングの詰め方
• パディングは必ず1byte以上入れる
• パディング長を入れなければならないため
• 平文の末尾に,長さがブロック長の倍数になるようにつける
平文
ブロック ブ ロック
ブロック
パディングの詰め方
• パディングは必ず1byte以上入れる
• パディング長を入れなければならないため
• 平文の末尾に,長さがブロック長の倍数になるようにつける
• →つまり,平文がブロック長の倍数ちょうどであれば,
パディングのみのブロックが出来る
平文
ブロック ブロック ブロック ブロック
パディングの詰め方
• パディングは必ず1byte以上入れる
• パディング長を入れなければならないため
• 平文の末尾に,長さがブロック長の倍数になるようにつける
• →つまり,平文がブロック長の倍数ちょうどであれば,
パディングのみのブロックが出来る
• パディングの値は,各1byteがパディングの長さを表す値で,
SSL3.0では末尾1byteだけしかチェックされない
平文
ブロック ブ ロック
パディングの長さが9ならば,
パディングの各byteの値は9-1=8
ブロック
考えてみよう
• みんなも
SSL3.0を
破ってみよう
復号
CIPHER 2
PLAIN 2
XOR
復号
CIPHER 1
PLAIN 1
XOR
復号
CIPHER 3
PLAIN 3
XOR
IV
POODLE攻撃が成立する前提条件
• 標的となるクライアントを,攻撃者の指定したURLに誘導できる
• 暗号文の正当性(=パディングの正当性)を確認した結果(OKかNGか)を知れる
• 解読結果が分かる必要はない
• SSL3.0を使っている
TLS1.0も実装によっては該当,TLS1.1以降は大丈夫
• 大体こんな感じ
ヒント
• https://example.net/distribute?name=Mr.+Test&message=Howdy%21
• こういうURLに誘導することを考える
• 右図は通信内容(の平文)の例
• 背景色: 赤(&濃い青)がクライアントのリクエスト
• その中にある濃い青の部分がCookie
• 上の赤枠と下の緑枠がそれぞれURLの赤/緑に対応
• 何が言いたいかというと,
Cookieの位置や平文の長さを調整できる
↓
→
というわけで
• リクエストを1文字ずつずらして,パディングonlyのブロックを作らせました
• 攻撃者にはCIPHER側だけが分かる
復号
CIPHER P
PADDING
XOR
CIPHER 9
というわけで
• リクエストを1文字ずつずらして,パディングonlyのブロックを作らせました
• 攻撃者にはCIPHER側だけが分かる
• 解読したい暗号ブロックで末尾を置換して送り,復号させる
復号
CIPHER 3
PADDING
XOR
CIPHER 9
↓置き換えた
というわけで
• リクエストを1文字ずつずらして,パディングonlyのブロックを作らせました
• 攻撃者にはCIPHER側だけが分かる
• 解読したい暗号ブロックで末尾を置換して送り,復号させる
• もしパディングが正当と判断されれば,
その瞬間にとある1byteが解読できます
復号
CIPHER 3
PADDING
XOR
CIPHER 9
というわけで
• 末尾が分かっているブロックを黄色の枠で示します
• 解読したいブロックそのものの末尾1byteは
実は不要なので無視します
復号
CIPHER 3
PADDING
XOR
CIPHER 9
というわけで
• 末尾が分かっているブロックを黄色の枠で示します
• 解読したいブロックそのものの末尾1byteは
実は不要なので無視します
• むしろ必要なのは
PADDING
復号
CIPHER 3
XOR
CIPHER 9
というわけで
• 末尾が分かっているブロックを黄色の枠で示します
• 解読したいブロックそのものの末尾1byteは
実は不要なので無視します
• むしろ必要なのはこっち
PADDING
復号
CIPHER 3
XOR
CIPHER 9
DECRYPT
というわけで
• 末尾が分かっているブロックを黄色の枠で示します
• 解読したいブロックそのものの末尾1byteは
実は必要ではありません
• むしろ必要なのはこっち
• XORは1byteごとに計算できます(定義を思い出そう)
• XORは逆算が可能なので,暗号ブロックの復号直後の末尾1byteがわかる
PADDING
復号
CIPHER 3
XOR
CIPHER 9
DECRYPT
というわけで
• 末尾が分かっているブロックを黄色の枠で示します
• へぇ~
復号
CIPHER 3
DECRYPT
というわけで
• 末尾が分かっているブロックを黄色の枠で示します
• あれ?
PLAIN 3
復号
CIPHER 3
XOR
CIPHER 2
DECRYPT
というわけで
• 末尾が分かっているブロックを黄色の枠で示します
• あれれ?
PLAIN 3
復号
CIPHER 3
XOR
CIPHER 2
DECRYPT
というわけで
• 末尾が分かっているブロックを黄色の枠で示します
• あれれれ?
PLAIN 3
復号
CIPHER 3
XOR
CIPHER 2
DECRYPT
というわけで
• 末尾が分かっているブロックを黄色の枠で示します
• あれれれ?
PLAIN 3
というわけで
• 末尾が分かっているブロックを黄色の枠で示します
• あれれれ?
PLAIN 3
確率はどうなるの
• リクエストごとにIVもKeyもランダムに変わります
• 各暗号ブロックもランダムになると考えてよいです
• ということで,書き換え後の
最終ブロックの復号結果もランダムと考えられます
• SSL3.0の脆弱性より,末尾1byteが合致すればよいので,
確率は平均して1/256 (1byteの取り得る値は256通り)です
• つまり平均256回で1byte解読できる
• ヤバい
復号
CIPHER 3
PADDING
XOR
CIPHER 9
他のBYTEはどうなるの
• URLを変えることで,長さを維持したまま1byteずつずらせる
• なので任意のbyteをブロックの末尾に持って来ることが出来る
• これによってCookieを含む多くの部分を解読することができ,
攻撃者はセッションIDを使ってなりすましに成功する
• こわいね
実演
• 1byteあたり平均256回ほどのリクエストで解読できるでしょう
• 誰か適当にパスフレーズを打ち込んでみて下さい
対策
• TLS1.0以降ではパディング全体を調べることで防止している
• 中間者攻撃でSSL3.0にダウングレードさせられる恐れがあるため,
SSL3.0は無効にしなければならない(今のブラウザはみんなそうしているはず)
• 人間は万能じゃないので,現行のTLS(に限らず様々な仕組み)に新たな脆弱性が
見つかる可能性も十分にあります
• そのうち見つかると思う
• 被害に遭わないためにもアップグレードは積極的に行いましょう
FINALE
• どうでしたか?
• 小学生でも理解できるよう噛み砕いて説明したつもりです
• 内容に関してよくわからなかったところとかはありますか
• 遠慮せず聞いてください

Hacking demonstration 2018