Skip to content

Instantly share code, notes, and snippets.

@shigeki

shigeki/kadai.md Secret

Last active September 6, 2016 11:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save shigeki/b70bd5433e95722b5fa3 to your computer and use it in GitHub Desktop.
Save shigeki/b70bd5433e95722b5fa3 to your computer and use it in GitHub Desktop.
セキュリティ・ミニキャンプ 北海道 2015 TLS, HTTP/2演習課題手順書

セキュリティ・ミニキャンプ in 北海道 2015 専門講座 演習

TLS, HTTP/2演習 大津繁樹

注意事項

本専門講座の演習は、演習者各自にインターネットのクラウド上のサーバを1つ割り当て、管理者権限を使って作業を進めます。

演習サーバは実際にインターネットにつながっているため、世界中から絶えず不正侵入を試みる攻撃を受けています。仮に外部から演習サーバへ侵入を許すと、他のシステムに攻撃する踏み台やDDoSを行うノードとして利用され、全く関係のない第3者に迷惑を及ぼすことがあります。

このようなリスクを避けるため、演習サーバ上の作業では細心の注意を払い、演習に必要な作業のみ行ってください。講師やチュータの許可なく、資料に記載されている以外のソフトウェアを演習サーバにインストールしたり、演習に不要なオペレーションを行ったりすることは禁止です。

また、サーバ上で何か不正侵入されているような疑わしい挙動を見つけた場合には、講師・チューター・事務局に速やかに連絡してください。

常にセキュリティリスクを意識して作業に取り組むことが大事です。

事前学習で公開鍵の登録されていますので seccamp アカウントでログインできます。

時間・環境

  • 12/12(土) 18:30〜21:00 2:30
  • 12/13(日) 9:00〜12:00 3:00
  • 12/13(日) 13:00〜14:00 1:00

特に細かい時間割を決めていません。講義中休憩は適宜入れる予定ですが、演習中は自由に休憩をとっても構いません。 体調が悪くなったと感じたら講師やチューターに相談してください。

初日と2日目で会場が異なります。初日の会場ネットワークは、外部へ ssh できないので替りのネットワークを一時的に用意する予定ですが、もしネットワークが提供できなければ初日は講義中心の時間割に切り替えます。 2日目は ssh で作業できる環境で演習を行います。

0. 演習準備

0.1 パスワード

演習当日に seccamp アカウントのパスワードを伝えます。sudo を使ってパスワードを入力すると管理者権限でコマンドが実行できます。

0.2 環境のアップデート

OSをインストール直後からアップデートをしていないので、演習作業に入る前に環境を apt-get 最新のものに更新します。 おそらく再起動が必要になるので再起動を行います。

$ sudo apt-get upgrade
$ sudo apt-get dist-upgrade
$ sudo reboot

再起動後 ssh でログインできることを必ず確認してください。もしログインできない場合は講師・チュータに相談してください。

1. TLS演習

1.1 エントロピー プール

  • サーバのエントロピー プール量を確認します。
  • 人為的に Disk I/Oを発生させます。
  • エントロピー プールが増加したことを確認します。
  • /dev/urandom から乱数データを抽出します。
  • エントロピー プールが減少したことを確認します。
ubuntu@server21:~$ cat /proc/sys/kernel/random/entropy_avail
340
ubuntu@server21:~$ find / > /dev/null 2>&1
ubuntu@server21:~$ cat /proc/sys/kernel/random/entropy_avail
347
ubuntu@server21:~$ head -10 /dev/urandom > /dev/null
ubuntu@server21:~$ cat /proc/sys/kernel/random/entropy_avail
336

1.2 wiresharkによる pcap データの確認

1.2.1 RSA鍵交換の pcap データ

https://nopfs.hokkaido.koulayer.com/exam.pcap にアクセスして pcap データをダウンロードします。

wireshark を起動して exam.pcap を読み込みます。

1.3 nginxのビルド

1.3.1 ソースの取得

以下のディレクトリから最新版のソースをサーバにダウンロードします。

ダウンロードツールはなんでもいいですが、ターミナルで行うなら wget や curl など使いましょう。

$ wget https://www.openssl.org/source/openssl-1.0.2e.tar.gz

1.3.2 nginxのビルド・インストール

ダウンロードしたソースを展開します。ディレクトリはお好みの場所で構いません。

seccamp@server21:~/src$ tar zxvf nginx-1.9.8.tar.gz
他のソースも展開

全部展開したら nginx のソース中でビルド・インストールします。インストールパスは /usr/local/nginx 以下です。

seccamp@server21:~/src$ ./configure --with-openssl=../openssl-1.0.2e/ --with-http_ssl_module --with-pcre=../pcre-8.38 --with-zlib=../zlib-1.2.8  --with-http_v2_module --with-debug
seccamp@server21:~/src$ make
seccamp@server21:~/src$ sudo make install

1.3.3 証明書の準備

Wo Signから発行された証明書のzipファイル中には nginx用の証明書zip (for Nginx.zip) が入っているが、ここでは手動で準備します。

nginxではサーバ証明書と中間証明書を一つのファイルに結合したものを設定ファイルで渡します。ただしサーバ証明書を必ず先頭にする必要があります。

-rw-r--r-- 1 seccamp adm  2300 Nov 29 16:53 1_cross_Intermediate.crt
-rw-r--r-- 1 seccamp adm  2029 Nov 29 16:53 2_issuer_Intermediate.crt
-rw-r--r-- 1 seccamp adm  1708 Nov 29 16:53 3_user_server21.hokkaido.koulayer.com.crt

ここでは server.crt ファイル名をつけます。

seccamp@server21:~/cert$ touch server.crt
seccamp@server21:~/cert$ cat 3_user_server21.hokkaido.koulayer.com.crt  >> server.crt
seccamp@server21:~/cert$ cat 2_issuer_Intermediate.crt  >> server.crt
seccamp@server21:~/cert$ cat 1_cross_Intermediate.crt  >> server.crt

この server.crt と private.key を /usr/local/nginx/conf ディレクトリへコピーします。 private.key が root の read only になっていることを確認します。

seccamp@server21:~/cert$ sudo cp server.crt private.key /usr/local/nginx/conf/
[sudo] password for seccamp:
seccamp@server21:~/cert$ ls -l /usr/local/nginx/conf/private.key
-r-------- 1 root root 1679 Dec 11 18:08 /usr/local/nginx/conf/private.key

1.3.4 nginxの設定

/usr/local/nginx/conf/nginx.conf を修正します。ファイルの修正位置は下記の nginx.conf の最終形を参照してください。 http:// は利用しないので、listen 80 が記載されているサーバ設定をコメントアウトします。

#   server {
#           listen       80;
#           server_name  localhost;
(中略)
#
#  }

次にhttps:// で利用する 443 ssl を listen するサーバの設定部分のコメントを削除して有効にします。 server_name のフィールドに自分のサーバ名(以下の例では server21.hokkaido.koulayer.com)を記載します。 1.3.3でコピーした証明書と秘密鍵ファイルも設定します。

    server {
	         listen       443 ssl;
		     server_name  server21.hokkaido.koulayer.com;
		     ssl_certificate      server.crt;
			 ssl_certificate_key  private.key;
			      (中略)
	}

nginx のサーバを起動させます。

seccamp@server21:~/src/nginx-1.9.8$ sudo /usr/local/nginx/sbin/nginx
seccamp@server21:~/src/nginx-1.9.8$ tail /usr/local/nginx/logs/error.log
2015/12/11 17:18:03 [notice] 3008#0: signal process started

その他の nginx のプロセスコマンド

nginx のサーバを強制停止させる場合は -s stop オプションを使います。

seccamp@server21:~/src/nginx-1.9.8$ sudo /usr/local/nginx/sbin/nginx -s stop
seccamp@server21:~/src/nginx-1.9.8$ ps aux |grep nginx
seccamp   3029  0.0  0.0  11740   932 pts/0    S+   17:19   0:00 grep --color=auto nginx

プロセス起動中に設定ファイル /usr/local/nginx/conf/nginx.conf を変更して、設定再読み込みしたい場合は -s reload オプションを利用します。

seccamp@server21:~/src/nginx-1.9.8$ sudo vi /usr/local/nginx/conf/nginx.conf
seccamp@server21:~/src/nginx-1.9.8$ sudo /usr/local/nginx/sbin/nginx -s reload

1.3.5 TLSサーバへの接続・確認をします。

ブラウザで自分のサーバにアクセスします。アクセスログ /usr/local/nginx/logs/access.log でアクセスを確認します。

seccamp@server21:~/src/nginx-1.9.8$ tail -f /usr/local/nginx/logs/access.log
210.160.37.27 - - [11/Dec/2015:17:30:36 +0900] "GET / HTTP/2.0" 304 168 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36"

nginx の defaultのページが醜いと思う人は自分で好きなようにページを変えてもいいです。 (ただし公序良俗に反しないコンテンツに限ります。) また最後の HTTP/2 の演習で html のディレクトリを変更しますのでそのつもりで。

seccamp@server21:~/src/nginx-1.9.8$ sudo vi  /usr/local/nginx/html/index.html

1.4 SSLLabのテスト

default の設定のままSSLLabのテストを行います。

https://www.ssllabs.com/ssltest/index.html

"Do not show the results on the boards" をチェックすると記録が他人に見られることはありません。 今回は演習目的なので結果を公開する必要なありません、チェックしておきましょう。

1.5 DHEの鍵長増加

2048bit のDHパラメータファイルを生成します。

$ openssl dhparam -out dhparam.pem 2048
seccamp@server21:/usr/local/nginx/conf$ openssl dhparam -text -in dhparam.pem  -noout
    PKCS#3 DH Parameters: (2048 bit)
	        prime:
		            00:bc:17:c2:76:93:f1:83:d0:50:a6:ad:07:49:f3:
		            20:5a:1d:35:08:cb:da:b9:e5:65:7f:f8:69:ff:df:
		            be:15:57:16:8e:60:82:2a:98:79:38:e5:35:c6:95:
		            57:a6:5a:e2:79:34:f2:ff:6b:e5:fd:ab:3a:57:25:
		            bc:43:ee:a5:ef:d2:55:f6:7b:f3:44:ad:a4:3c:a7:
		            05:a3:78:d3:fb:39:73:7d:ea:0f:f3:63:a6:84:b0:
		            3b:ee:fd:59:7e:3c:d0:90:93:b5:88:ab:84:57:cb:
		            98:0f:94:0a:90:91:d3:8b:af:eb:bb:3a:a5:32:f1:
		            75:3f:a2:c9:74:00:84:99:c1:95:a6:11:6e:db:f5:
		            1f:a7:76:db:f2:b3:2d:7e:67:bb:f9:35:4f:cb:10:
		            fc:c9:9b:9b:6c:d3:61:52:60:82:62:cb:10:2b:c8:
		            24:3a:a5:02:9f:a5:a4:74:c7:28:95:d0:35:ad:f9:
		            37:13:ec:b3:75:44:ab:31:9e:7e:59:7b:0d:54:34:
		            74:d0:ab:5f:9e:f7:a1:47:c5:37:35:2d:a4:5b:26:
		            b9:35:23:77:fc:2d:bb:2e:74:a7:b4:5d:fd:e9:cf:
		            4f:8e:de:2f:8a:78:dc:a3:49:e4:29:43:d9:ee:5a:
		            f0:4b:91:4a:05:19:ff:85:7f:6d:12:8f:c2:9b:f8:
		            cc:ab
		        generator: 2 (0x2)

dhparamファイルを /usr/local/nginx/conf ディレクトリにコピーします。 nginx.con の設定ファイルのsslサーバの部分にDHパラメータのファイルを加えます。

ssl_dhparam          dhparam.pem;

nginxのプロセスを設定ファイルを読み込みをさせます。

seccamp@server21:/usr/local/nginx/conf$ sudo /usr/local/nginx/sbin/nginx -s reload
[sudo] password for seccamp:

終わったらブラウザで接続を確認します。 再度 SSLLab のテストを行い、A判定が出たら終わりです。 SSLlabの結果にキャッシュが残っている場合はクリアしておきましょう。

1.6 目指せA+

A+ のスコアを取るため HSTSヘッダを返すように以下の設定を ssl のサーバに追加します。 max-age は、半年: 15768000秒 に設定しておきます。(長くないとスコアがよくならない)

add_header Strict-Transport-Security "max-age=15768000; includeSubdomains";

nginxのプロセスを再起動し、エラーが出力されていないことを確認したらブラウザーで https ページにアクセスして問題なく表示がされるか確認します。確認後 http:// でアクセスします。ブラウザが自動的に https:// に変換してアクセスできていることを確認します。

ブラウザでの設定を確認するため

chrome://net-internals/#hsts

を開きます。Query Domain に自分のサーバ名を入力し Query ボタンをクリックします。

dynamic_sts_domain: server21.hokkaido.koulayer.com
dynamic_upgrade_mode: STRICT
dynamic_sts_include_subdomains: true
dynamic_sts_observed: 1449822637.075221
dynamic_pkp_domain:
dynamic_pkp_include_subdomains:
dynamic_pkp_observed:
dynamic_spki_hashes:

上記のように mode が STRICT になっていれば成功です。

最後に SSLlab のテストを行います。 A+ のスコアが出れば終了です。

2 TLSを壊る FREAK攻撃

https://nopfs.hokkaido.koulayer.com/exam.pcap のデータを破ります。

2.1 pre master secretの取得

WoSignからの証明書は、 https://nopfs.hokkaido.koulayer.com/nopfs.hokkaido.koulayer.com_sha256_en.zip にあります。for Other Server.zip中のサーバサーバ証明書を openssl x509 -text コマンドで出力します。 Modules と Exponent の公開鍵情報が出力されますので、Modulesを因数分解します。

因数分解のヒントは口頭で伝えます。

因数分解の答えである素数(1つだけでよい)と証明書中の公開鍵情報(Modules, Exponent)を https://hokkaido1.hokkaido.koulayer.com/ に入力します。PKCS1形式の秘密鍵データのPEMが出力されます。

Wiresharkから ClientKeyExchange のデータを取得します。バイナリーが扱える環境ならbinary保存のほうが楽です。 テキスト形式でコピーした場合は、xxd を使って Hex 文字列をバイナリー(DER形式)に変換します。

$ cat > encrypted_premaster_secret.txt
0d9909953798f・・・・・721
$ xxd -p -r encrypted_premaster_secret.txt > encrypted_premaster_secret.der

Wiresharkから抽出した暗号化されたPreMasterSecretデータを因数分解して生成した秘密鍵を使って復号化します。 PKCS1形式で暗号化されているので -pkcs オプションが必要です。出力を16進数で表示するため -hexdump をつけます。

$ openssl rsautl -decrypt -pkcs -inkey private.key -in encrypted_premaster_secret.der -hexdump
0000 - ・・・・・・  ..F.y.....)i,`.0
0010 -  ・・・・・・ P......}.?C..c..
0020 -  ・・・・・・ .x..Z.p..OK..ep.

全体のバイト数と頭の2オクテットのデータを求めてください。

3 上級者向けの課題

PreMasterSecret取得以降は、

  • PreMasterSecretからMasterSecretの求め方、
  • MasterSecretから各利用鍵の導出
  • AES-GCMのデータ書式

などが必要です。情報は、 http://www.slideshare.net/shigeki_ohtsu/security-camp2015-tls にありますが、RFC5246を直接参照するのもありです。

後は、好きにやってください。解けたら平文データを教えて下さい。 正解だったらTLSコース修了です。

HTTP/2演習

4 1 HTTP/2の有効化

TLS演習で利用したTLSサーバで http2 を有効化します。 まず listen 設定に http2 を追加するだけです。

    server {
	         listen       443 ssl http2;
		     server_name  server21.hokkaido.koulayer.com;
		     ssl_certificate      server.crt;
			 ssl_certificate_key  private.key;
			      (中略)
	}

nginxのプロセスを再読み込みしてブラウザーでアクセスします。

4.2 エラーの修正

INADEQUITE SECURITY のエラーを以下の設定を追加して修正します。

        ssl_ciphers  ECDHE+AESGCM:DHE+AESGCM:HIGH:!aNULL:!MD5;

nginxのプロセスを再読み込みしてブラウザーでアクセスします。 WireSharkでTLSハンドシェイクを確認します。 ClientHello/ServerHelloの Extension で ALPN が交換されていることを確認します。

5 HTTP HoLを再現させる

5.1 イメージサーバのインストールと起動

イメージサーバは https://github.com/shigeki/seccamp-imageserver/ から git で取得します。 画像表示用の html ファイルも seccamp-imageserver/html ディレクトリ以下にあるので nginx.conf の設定を変更し / 宛のリクエストが seccamp-imageserver/image を参照するよう設定を変更します。

ここではホームディレクトリ(/home/seccamp/)以下に git clone する場合を例とします。

seccamp@server21:~$ git clone https://github.com/shigeki/seccamp-imageserver/
seccamp@server21:~$ ls -l seccamp-imageserver/
total 16
drwxr-xr-x 2 seccamp adm 4096 Dec  8 13:39 html
drwxr-xr-x 2 seccamp adm 4096 Dec  9 01:14 lib
-rw-r--r-- 1 seccamp adm 1081 Dec  8 13:39 LICENSE
-rw-r--r-- 1 seccamp adm   67 Dec  8 13:39 README.md

html ディレクトリがあることを確認したら nginx.conf の location をこのディレクトリに変更します。 また image server は localhost の port 8080 で動作します。 /image ディレクトリのアクセスを image server 側に回すよう proxy_pass の設定も加えます。 nginx.conf は以下のようになります。

        location / {
		            root   /home/seccamp/seccamp-imageserver/html;
		            index  index.html index.htm;
		        }

        location /images {
		             proxy_pass http://localhost:8080;
		         }

nginx のプロセスを reload して設定を再読み込みを行い、seccamp-imageserver/lib 以下にある server.js を node から起動します。 (port 8080 なので一般ユーザ権限で動作します。バックグラウンドプロセスにしても構いませんが、標準出力にログが出ます。)

seccamp@server21:~/seccamp-imageserver/lib$ sudo /usr/local/nginx/sbin/nginx -s reload
seccamp@server21:~/seccamp-imageserver/lib$ node server.js
Litening on port 8080

/usr/local/nginx/log 以下のログを見てエラーが出てなければ、ブラウザでトップページを確認します。

5.1 HTTP Head of Line Blocking の試験

トップページからのリンクにある、2つのページを見てみます。 10枚と50枚のイメージの2種類のページです。 http2 でのページの確認が終わったら nginx.conf で http2 の設定を外し、nginx プロセスを再読込してみましょう。 http/1.1 で同じページを見た時にどう表示が変わるか確認してください。

メニューから Chrome Developer Tool を起動し、ネットワークのタブを開けてアクセスしてみましょう。 スライドにあるようHTTPリクエストとレスポンスまでの時間グラフが出力されますので http/1.1 で HoLが発生していることがわかはずです。

今度は html ファイルを自由に変えてみましょう。

      <img src="/images/face-00.png"/>
      <img src="/images/face-01.png"/>
      <img src="/images/face-02.png"/>

face-00.pn の 00 の番号が3で割り切れる番号は泣き顔画像で3秒後にレスポンスが帰ります。(数字は 00-99まで2桁) 自分なりに画像の番号を増やしてどうなるのか確認してみましょう。

nginx.conf の最終形

nginx.conf の最終形を添付しておきますので、つまずいた時は参考にしてください。

#user nobody;
worker_processes 1;
#error_log logs/error.log debug;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
server {
listen 443 ssl http2;
server_name server21.hokkaido.koulayer.com;
add_header Strict-Transport-Security "max-age=15768000; includeSubdomains";
ssl_certificate server.crt;
ssl_certificate_key private.key;
ssl_dhparam dhparam.pem;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers ECDHE+AESGCM:DHE+AESGCM:HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
root /home/seccamp/seccamp-imageserver/html;
index index.html index.htm;
}
location /images {
proxy_pass http://localhost:8080;
}
}
}
@ww24
Copy link

ww24 commented Dec 12, 2015

1.3.3 証明書の準備server.certserver.crt の typo だと思います。

@shigeki
Copy link
Author

shigeki commented Dec 13, 2015

ありがとうございます。先ほど修正しました。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment