Skip to content

Instantly share code, notes, and snippets.

@elliptic-shiho
Created June 30, 2015 12:55
Show Gist options
  • Save elliptic-shiho/a05e34c5e489d956d37d to your computer and use it in GitHub Desktop.
Save elliptic-shiho/a05e34c5e489d956d37d to your computer and use it in GitHub Desktop.
セキュキャン2015全国 応募用紙抜粋
### 共通問題
下記の共通問題にはすべて回答してください。
■ 共通問題1
セキュリティ・キャンプに応募した自分なりの理由とセキュリティ・キャンプで学んだことを何に役立てたいかを教えてください。
【以下に回答してください(行は適宜追加してください)】
SNSに代表される一般世代へのインターネットの普及によって情報セキュリティに関する技術は需要が高まっています。また、一般世代に対してもそれ相応の理解がそろそろ必要になって来ました。
しかし、現状情報セキュリティ技術者は不足しています。一般への理解に関してもマスコミの過激な報道による間違った理解をしていることがほとんどです。
私は現在高校一年生で、自分が切り拓くべき未来をどのようにするかを考えられる時間がありました。私は人にものを伝えることが苦手で、今までも話すことで興味を持ってもらえた例はほんのひと握り程度です。でも、私にはそれなりの技術があります。未来のためにその技術を磨き、そして私を見て少しでも興味を持ってもらえる人がいるような、そのような活動をしたいと思っています。
セキュリティ・キャンプは私一人やCTFをする中で知り合った方々との知見の共有やお話の中では得ることに限界のある、実際のセキュリティの現場の技術を学べる数少ない機会です。私は私自身が更に成長するために、ひいてはセキュリティというまだまだ出てきて間もない世界の発展に貢献したいと思い、このセキュリティ・キャンプへと応募しました。
【回答ここまで】
■ 共通問題2
セキュリティに関することで、過去に自分が経験したことや、ニュースなどで知ったことの中から、最も印象に残っていることを教えてください。また、その印象に残った理由も教えてください。
【以下に回答してください(行は適宜追加してください)】
私は過去にいくつものプログラムを作って来ました。中でもWebアプリケーションはかけた時間でも種類でも多くを占めます。ある時、そのようにして作っていたサイトをいくつか公開すると、画像アップローダやGitビューワーのアプリケーションに脆弱性があることを指摘されました。今から考えれば画像ファイルのXSS、OSコマンドインジェクション、ディレクトリトラバーサルといった典型的な脆弱性でしたが、当時の私は大変ショックを受けました。それからセキュリティに興味を持ち、今では自ら作るソリューションのどれにもそれなりのセキュリティの意識を持ったプログラミングができるようになりました。
最近ですと、年金機構への標的型攻撃に関して強い興味があります。岩井博樹著「標的型攻撃セキュリティガイド」という本を読んだことがあったので、それなりに理解をしてはいましたが、世間の認知度の低さ、学校でも「送信元のヘンなメールや添付ファイルはやすやすと開かない」とだけ教えられて少し違うんだよな、という感想を持ちました。これらに関しても啓蒙活動が更に必要だなと感じます。
【回答ここまで】
■ 共通問題3
その他に自己アピールしたいことがあれば自由に書いてください。(たとえば、あなたが希望する講座を受講する上で、どのような技術力を持っているか、部活動、技術ブログ、GitHub、ソフトウェア開発、プログラミングコンテスト、勉強会での発表・運営などの実績や熱意があれば、あるだけ書いてください。)
【以下に回答してください(行は適宜追加してください)】
私はCTFをすることで技術を付けてきました。現在は暗号に関する問題を解くことが多いですが、いずれバイナリの問題にもチャレンジできるようになりたいです。
CTFチームはvuls(ソフトバンク・テクノロジーズのセキュリティ関連の仕事をされている方々を中心に結成されたチーム)とscryptos(セキュリティ・キャンプ卒業生と非常にハイレベルな学生を中心に構成されたチーム)、CTF for Beginners in Hakata(Attack & Defense)で優勝した時のチームであるPh//shh/binに参加しており、しっかり貢献をできていると感じています。
また、私は「福井技術者の集い」という勉強会へ運営・発表者として参加させていただいています。発表したスライドの一つとして、 「綺麗なコードを書くために」(http://elliptic-shiho.xyz/kireina.pdf)というスライドを挙げます。
また、福井大学のセキュリティ・ゼミで攻撃・防御技術について講師として発表させていただきました。スライドはhttp://elliptic-shiho.xyz/sec-f.pdfにあります。
新潟ミニキャンプ応募用紙で紹介したecalcというコマンドライン計算プログラムや、Pythonで実装した独自実装のアセンブラ等私の書いたコードで公開しているものは http://github.com/elliptic-shihoにおいて有ります。
【回答ここまで】
===================
空白行として、あけたままにしてください
=====         =====
空白行として、あけたままにしてください
=====         =====
空白行として、あけたままにしてください
=====         =====
空白行として、あけたままにしてください
=====         =====
空白行として、あけたままにしてください
===================
### 選択問題
下記の選択問題の中から 5つ 選択して回答してください。
なお、回答した問題は、冒頭の□を■にしてください。
■ 選択問題5 (左側の□について、回答した問題は■にしてください)
以下のようなC言語の関数functionがあるとします。
void function(int *array, int n) {
int i;
for(i = 0; i < n; i++) {
array[i] = i * n;
}
}
上記プログラムをコンパイルした結果の一例 (i386)は以下となりました。
00000000 <function>:
0: 56 push %esi
1: 53 push %ebx
2: 8b 5c 24 0c mov 0xc(%esp),%ebx
6: 8b 4c 24 10 mov 0x10(%esp),%ecx
a: 85 c9 test %ecx,%ecx
c: 7e 18 jle 26 <function+0x26>
e: 89 ce mov %ecx,%esi
10: ba 00 00 00 00 mov $0x0,%edx
15: b8 00 00 00 00 mov $0x0,%eax
1a: 89 14 83 mov %edx,(%ebx,%eax,4)
1d: 83 c0 01 add $0x1,%eax
20: 01 f2 add %esi,%edx
22: 39 c8 cmp %ecx,%eax
24: 75 f4 jne 1a <function+0x1a>
26: 5b pop %ebx
27: 5e pop %esi
28: c3 ret
このとき以下の(1)~(5)の設問について、回答と好きなだけ深い考察を記述してください。知らない点は、調査したり自分で想像して書いてもらっても結構です。どうしてもわからない部分は、具体的にここがわかりませんと記述しても良いです。(1)~(2)の回答は必ず答えてください。(3)~(5)の回答は任意です。わかることを書いてください。CPU やコンパイラは特定の実装を例に説明しても良いですし、理想を自由に考えても良いです。
(1)【必須】上記の C 言語のプログラムはどのような動作をしますか。また、この関数を呼び出して利用する main 関数の例を作成してください。
(2)【必須】上記のアセンブリコードを、いくつかのブロックに分割して、おおまかに何をしている部分かを説明してください。もし、上記のアセンブリが気に入らないのであれば、好きなアーキテクチャやコンパイラのアセンブル結果を載せて説明しても良いです。
(3)【任意】 コンパイラがソースコードの関数を解釈して、ターゲットのアーキテクチャのバイナリを生成するまで、どのように内部で処理を行っていると思いますか。(キーワード: 構文解析、変数、引数、呼出規約、レジスタ、スタック、アセンブラ、命令セット)
(4)【任意】CPU の内部では、プログラムのバイナリはどのように解釈され実行されていると思いますか。(キーワード: フェッチ、デコード、オペコード、オペランド、命令パイプライン、回路)
(5)【任意】現在の CPU やコンパイラの不満点があれば自由に記述してください。
【以下に回答してください(行は適宜追加してください)】
1)
この関数functionは、int型のポインタarrayと数値nを引数に取ります。処理内容から、渡されたサイズnの配列にi*n(i = 0, 1, ... n-1)、つまりnの倍数という関係があるので、何らかのデータセットの作成に使われるものだと思われます。
```
#include <stdio.h>
void function(int *array, int n) {
int i;
for(i = 0; i < n; i++) {
array[i] = i * n;
}
}
int main (int ac, char **av) {
int dataset[256], i;
function(dataset, 256);
for (i = 1; i <= 256; i++) {
printf("%5d ", dataset[i-1]);
if (i % 16 == 0) {
putchar('\n');
}
}
putchar('\n');
return 0;
}
```
2) 普段はIntel記法を使っているので、Intel記法に直しました。
```
00000000 <function>
# A
0: 56 push esi
1: 53 push ebx
# B
2: 8b 5c 24 0c mov ebx, [esp+0xc]
6: 8b 4c 24 10 mov ecx, [esp+0x10]
a: 85 c9 test ecx,ecx
c: 7e 18 jle 26 <function+0x26>
# C
e: 89 ce mov esi,ecx
10: ba 00 00 00 00 mov edx, 0
15: b8 00 00 00 00 mov eax, 0
# D
1a: 89 14 83 mov dword [ebx+eax*4], edx
# E
1d: 83 c0 01 add eax, 1
20: 01 f2 add edx, esi
22: 39 c8 cmp eax, ecx
24: 75 f4 jne 1a <function+0x1a>
# F
26: 5b pop ebx
27: 5e pop esi
# G
28: c3 ret
```
私が考えたブロック分けをそれぞれA〜Gとしました。
ブロックAは、レジスタの保存を行なっています。これはx86アーキテクチャのABIによるもので、eax, ecx, edx以外のレジスタは関数の呼び出し時に破壊されないことが保証されないといけないという制約が存在するのが要因です。この関数の中では更にebx, esiを使うため、最初にスタックへ値をセーブしておくことでリターン時(ブロックG)には元の値に戻せています。
ブロックBは引数をそれぞれ取得し、ebxとecxに代入しています。さらに、ecx(つまり、第二引数であるnに当たる数値)が0か否かを判定し、0以下であればブロックFへとjmpしています。
この処理はC言語のコードには存在しなかったため、コンパイラ側の最適化によって追加されたものと考えられます。
ブロックCは、for文の初期化処理部分です。esiにecxを、edxとeaxには0を代入しています。
ブロックDは実際のfor文内の代入処理が記述されています。ebxには引数から来たarrayのアドレスが、eaxには現在のループカウンタの値が入っています。また、アクセスをDWORD、アドレス計算をeax*4にすることでint型のアドレス境界に揃えています。
edxを代入しているだけでどこにも乗算処理が無いと思っていましたが、ブロックEを読むことでなるほど、と思いました。そちらの説明は下に書きます。
ブロックEはfor文で言うカウンターの加算処理とループ判定処理です。eaxはループカウンタなので1が加えられます。edxにはesiが加算されていますが、これはブロックCでecxが代入されていました。なので、実質edx += nと同等の処理です。つまるところ、毎回の乗算処理を加算処理にコンパイラが書き換えたと取れます。最適化によったもの
【回答ここまで】
■選択問題8 (左側の□について、回答した問題は■にしてください)
gccが持つ-fno-stack-protectorは、どのようなセキュリティ機能を無効にするオプションであるのか、またこの機能により、どういった脆弱性からソフトウェアを守れるのかをそれぞれ記述してください。
【以下に回答してください(行は適宜追加してください)】
Buffer-overflowに代表されるソフトウェアの脆弱性はほとんどは、予想された以上の入力を受けたことによるスタックの破壊を利用してSaved-EBP/return-EIPを書き換えることを用いています。
そこで、スタックが破壊されたことを検知するのを目的として不定のランダムな値(Canaryという。具体的には、gsセグメントに存在するプロセスごとにランダムな固定値。)をsaved-EBPの直前に挿入し、関数から抜ける時にその値が書き換わっていないかをチェックすることで検知しようという機構がgccのセキュリティ機構に備わっています。それを、SSP(Stack Smashing Protector)といいます。
デフォルトでは一定以上のスタックを利用する関数に対してのみ有効になっていますが、全ての関数に対してSSPを有効化させたい場合には-fstack-protector-allをコンパイルオプションに付加することでSSPが強制的に有効になります。また、逆にこの機能を無効化したい場合には-fno-stack-protectorをコンパイルオプションに付加することで反対にSSPを取り除くことができます。
このセキュリティ機構は、バッファオーバーフローを利用する攻撃を殆どの場合無効化することができます。
例を挙げます。
#include <stdio.h>
void func() {
char buf[512];
gets(buf);
return;
}
int main(int ac, char **av) {
func();
return 0;
}
このプログラムは、512バイトのバッファを確保した後にgets関数を使ってデータを入力するプログラムです。変数bufを確保する際に512バイト分のスタック領域が確保されていますが、gets関数は書き込む先のポインタの範囲を考慮しない関数なので、長くてもその領域を超過して書き込む。スタックフレームを考慮することで、EIPを書き換えることも可能になります。
実際にSSPを付けずにコンパイルした実行ファイルとSSPを付けてコンパイルした実行ファイルを作り、それぞれに対して攻撃を試みてみました。
$ gcc -o no-ssp -fno-stack-protector ssp.c
$ gcc -o ssp -fstack-protector-all ssp.c
$ perl -e 'print "A"x511;' | ./no-ssp # OK
$ perl -e 'print "A"x512;' | ./no-ssp # NG!
SSPなしの場合はエラーも出ず、一定以上の長さを書き込むことでセグメンテーションフォールト、例では512バイト=ebpの一部を書き換えました。
次に、SSPありの場合を見てみます。
$ perl -e 'print "A"x511;' | ./ssp
$ perl -e 'print "A"x512;' | ./ssp
*** stack smashing detected ***: ./ssp terminated
======= Backtrace: =========
/lib/libc.so.6(__fortify_fail+0x4d)[0xb76d4f5d]
/lib/libc.so.6(+0xfbf0a)[0xb76d4f0a]
./ssp[0x8048463]
./ssp[0x8048493]
/lib/libc.so.6(__libc_start_main+0xe6)[0xb75efb36]
./ssp[0x8048361]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:03 11807950 /home/eshiho/prog/ssp
08049000-0804a000 rw-p 00000000 08:03 11807950 /home/eshiho/prog/ssp
0804a000-0806b000 rw-p 00000000 00:00 0 [heap]
b75a4000-b75c1000 r-xp 00000000 08:03 4460912 /lib/libgcc_s-4.4.5.so.1
b75c1000-b75c2000 rw-p 0001c000 08:03 4460912 /lib/libgcc_s-4.4.5.so.1
b75d8000-b75d9000 rw-p 00000000 00:00 0
b75d9000-b7746000 r-xp 00000000 08:03 4456471 /lib/libc-2.11.1.so
b7746000-b7747000 ---p 0016d000 08:03 4456471 /lib/libc-2.11.1.so
b7747000-b7749000 r--p 0016d000 08:03 4456471 /lib/libc-2.11.1.so
b7749000-b774a000 rw-p 0016f000 08:03 4456471 /lib/libc-2.11.1.so
b774a000-b774d000 rw-p 00000000 00:00 0
b7762000-b7763000 rw-p 00000000 00:00 0
b7763000-b7766000 r-xp 00000000 08:03 4456468 /lib/libSegFault.so
b7766000-b7767000 r--p 00003000 08:03 4456468 /lib/libSegFault.so
b7767000-b7768000 rw-p 00004000 08:03 4456468 /lib/libSegFault.so
b7768000-b7769000 rw-p 00000000 00:00 0
b7769000-b7786000 r-xp 00000000 08:03 4456464 /lib/ld-2.11.1.so
b7786000-b7787000 r--p 0001c000 08:03 4456464 /lib/ld-2.11.1.so
b7787000-b7788000 rw-p 0001d000 08:03 4456464 /lib/ld-2.11.1.so
bf919000-bf93a000 rw-p 00000000 00:00 0 [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
アボートしました
$
見事にスタックの破壊を検知することができました。検知された旨とデバッグメッセージを表示し、その後アボートしています。
繰り返すと、SSPはバッファオーバーフローを起点とする様々な脆弱性に対して非常に効果的な対策です。今回のようにgetsを使うことこそ無いにしてもうっかりstrcpyやmemcpy、入力レンジのチェックミス等で脆弱性を作りこんでしまったとしてもかなり高い確率でその攻撃からの防御が可能になります。
しかし、このSSPは完全というわけではありません。先のsspを逆アセンブルして検知部分を見てみました。
0804842b <func>:
804842b: 55 push ebp
804842c: 89 e5 mov ebp,esp
804842e: 81 ec 18 02 00 00 sub esp,0x218
8048434: 65 a1 14 00 00 00 mov eax,gs:0x14
804843a: 89 45 f4 mov DWORD PTR [ebp-0xc],eax
804843d: 31 c0 xor eax,eax
804843f: 83 ec 0c sub esp,0xc
8048442: 8d 85 f4 fd ff ff lea eax,[ebp-0x20c]
8048448: 50 push eax
8048449: e8 b2 fe ff ff call 8048300 <gets@plt>
804844e: 83 c4 10 add esp,0x10
8048451: 90 nop
8048452: 8b 45 f4 mov eax,DWORD PTR [ebp-0xc]
8048455: 65 33 05 14 00 00 00 xor eax,DWORD PTR gs:0x14
804845c: 74 05 je 8048463 <func+0x38>
804845e: e8 ad fe ff ff call 8048310 <__stack_chk_fail@plt>
8048463: c9 leave
8048464: c3 ret
0x8048452でスタックからCanaryを取り出し、gs:0x14と比較しています。その後、その値が異なっていた場合には__stack_chk_fail@pltをcallしていることがわかります。つまり、Unlink AttackなりFormat String Bugなりの他の脆弱性が存在した場合にはGOTを書き換えることでEIPを自由に書き換えることが可能になります。また、gadgetを適切に選ぶことでROPに持ち込むことができ、結果的に任意のコードを実行させることが可能になります。
他にも、Canaryはプロセスごとにランダムですがfork()された子プロセスの場合Canaryは同一になるという特性を生かしてSSPが有効なfork型サーバーソフトウェアに対して半ばブルートフォースのような手段でCanaryを推測することも可能です。
いずれにしてもSSPを有効にすることは常に行うべきだと感じます。それ以上にコードに残る脆弱性をできるだけ0にする努力も必要だと思います。
【回答ここまで】
■選択問題9 (左側の□について、回答した問題は■にしてください)
以下のコードは、与えられたテキスト内からURLらしき文字列を探して、それらを<a>要素でリンクにしたHTMLを生成するJavaScriptの関数であるとします。攻撃者が引数 text の中身を自由に制御可能な場合、このコードにはどのような問題点があるか、またこのコードを修正するとすればどのようにすればよいか、自分なりに考察して書いてください。
function makeUrlLinks( text ){
var html = text.replace( /[\w]+:\/\/[\w\.\-]+\/[^\r\n \t<>"']*/g, function( url ){
return "<a href=" + url + ">" + url + "</a>";
} );
document.getElementById( "output" ).innerHTML = html;
}
【以下に回答してください(行は適宜追加してください)】
検証のために、次のようなHTMLファイルを作って実験しました。
<html>
<head>
<title>test</title>
<script>
function makeUrlLinks( text ){
var html = text.replace( /[\w]+:\/\/[\w\.\-]+\/[^\r\n \t<>"']*/g, function( url ){
return "<a href=" + url + ">" + url + "</a>";
} );
document.getElementById( "output" ).innerHTML = html;
}
</script>
</head>
<body>
<textarea id="text" style="width: 200px; height: 60px;"></textarea><br>
<button onclick="makeUrlLinks(document.getElementById('text').value)">execute</button>
<div id="output"></div>
</body>
</html>
URIだけを処理していたのでスキームをjavascriptにしたXSSかと思っていましたが、何をどう試行錯誤しても上手く行きませんでした。
javascript://の時点でコメントアウトとして処理されてしまうのが原因でした。また、入力可能な文字で構造を破壊する攻撃も不可能でした。
そこで、ここでエスケープされている以外の文字列を使ったXSSに着目しました。よくコードを読んでみるとそのURI以外の部分に関しては何もエスケープ処理がされていなかったので、<img src="404" onerror="alert(1)">のような文字列をテキストボックスに挿入するだけでXSSが可能でした。
この関数はURIの部分のみをエスケープしており、それ以外の箇所については何も処理はされていませんでした。関数の名前からしても当たり前だとは思うので、私はこのXSSは本質ではなく、実際には別に何かしらの脆弱性が存在するものと考えています。残念ながら私の検索能力と知識ではそれはわかりませんでしたが、URIスキームへのXSSについては知見を得ることが出来ました。
【回答ここまで】
■選択問題11 (左側の□について、回答した問題は■にしてください)
下記バイナリを解析し、判明した情報を自由に記述してください
------------------------------------------------
D4 C3 B2 A1 02 00 04 00 00 00 00 00 00 00 00 00
00 00 04 00 01 00 00 00 88 EB 40 54 A2 BE 09 00
52 00 00 00 52 00 00 00 22 22 22 22 22 22 11 11
11 11 11 11 08 00 45 00 00 44 1A BD 40 00 80 06
3A 24 C0 A8 92 01 C0 A8 92 80 10 26 01 BB 86 14
7E 80 08 B3 C8 21 50 18 00 FC 0D 0E 00 00 18 03
03 00 17 01 0E FB 06 F6 CD A3 69 DC CA 0B 99 FF
1D 26 09 E1 52 8F 71 77 45 FA
------------------------------------------------
【以下に回答してください(行は適宜追加してください)】
バイナリデータの先頭4バイトに注目すると、pcapファイルだとわかります。同時に、Little-Endianであることもわかりました。
Pythonのコンソールを使ってバイナリデータをファイルに落としこみ、Wiresharkで実際にファイルを開いてみると、パケットがひとつだけあった。。判明した情報は以下の通りでした。
・MACアドレス11:11:11:11:11:11からMACアドレス22:22:22:22:22:22への通信
・IPアドレス192.168.146.1からIPアドレス192.168.146.128への通信
・Destination Portが443であることからHTTPSの通信
・TLS v1.2の通信
・暗号化されたHeartbeatパケット
もし企業内で利用されているのならばこれはサーバーからクライアントへの通信かな?と思えたのですが、判明している情報ではないので欄には書きませんでした。
【回答ここまで】
■選択問題13 (左側の□について、回答した問題は■にしてください)
これまでに起こったこと(データ)から、これまでにまだ起こっていないことを事前に予想する場合、どのような点に注意し、どのようなことを考慮すべきか熱烈にアピールしてください。
【以下に回答してください(行は適宜追加してください)】
まず、これまでに起こったデータを可能な限り詳細な情報まで収集し、その上でそのデータをデータベース化するのが主流だと思います。
そのデータベース化の際、RDBMSで言うテーブルのスキームをどのように定義するかには注意が必要だと考えます。
例えばシステム更新/メンテナンスのような日々の事象から侵入の痕跡発見等の結果的な事象に関してはそれぞれ相関があると考えられますが、そのスキームの定義を例えば重要度, 事象の種類, 日時, 事象の発生した中心となる箇所(ソフトウェア、ハードウェア、インフラ、...)等にしておくことで過去の事象からこの先起こりえる事象をかなりの精度で予測することが可能になります。
しかし、この手法ではそれなりのサンプル数が存在しない限りその予測の結果の信頼性は低いままです。なので、この手法を活用できるのはそれなりの大企業かデータの入出力が頻繁に起こり、サンプルの量が取りやすい業務でのみとなるでしょう。
データをどのように使うかという面では、さらに先の例で言う重要度というパラメータの重み付けを行うことで結果の信用性を上げることができるかもしれません。ここに関しては憶測なのですが、日々のアップデート作業のデータが200件、そのあとにインシデントが発生したのが1件、加えてその直接の原因がとあるアップデート作業のデータ1件に関連するというような複雑なリレーションを我々人間は簡単に構築できます。しかし、機械/データベースのようなソフトウェアにとってこのリレーションはあまりに複雑過ぎます。なので、重要度やELFのSHDRヘッダ内におけるsh_linkフィールドのようなリンク機構が必要となります。そこまで複雑なものをたかがデータ予測程度に使うのはもったいないという考えも有るでしょうが、予測の精度を上げるという意味ではこれでもまだまだ足りないと感じます。
【回答ここまで】
以上
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment