TAMUctf 2018 Write-up

[TAMUctf](https://ctf.tamu.edu/)

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">今開催されてるTAMUCTFにsecure coding って新ジャンルが出題されてました。この出題方法なら防御問題としていいかもしれません。</p>&mdash; kazkitictf (@kazkiti_ctf) <a href="https://twitter.com/kazkiti_ctf/status/965732308098564096?ref_src=twsrc%5Etfw">2018年2月19日</a></blockquote>

ということで、試しに解いてみた。大学の学生向けのコンテストを外にもう公開している（？）からか、見た問題はどれもわりと簡単。コンテストは終了したけれど、しばらくは問題を公開したままらしい。

## システム

運営がGitLabサーバーを動かしていて、各問題ではリポジトリのURLが与えられる。forkして脆弱性を修正してpushすると、CIが走る。正常系が動作することと、脆弱性が無いことが自動でチェックされ、パスすれば、フラグが表示される。競技プログラミングっぽい。

## nginx

nginxの設定ファイル。

```
	root /;

	# Add index.php to the list if you are using PHP
	index index.html index.htm index.nginx-debian.html;

	server_name _;

	location / {
        try_files $uri $uri/ =404;
        index /usr/share/nginx/html/index.html;
        autoindex on;
	}

```

`/`を公開しているw

```
	root /usr/share/nginx/html;

	# Add index.php to the list if you are using PHP
	index index.html index.htm index.nginx-debian.html;

	server_name _;

	location / {
	}
```

で通った。

`gigem{f1x1N_conF1g5_0533cfc}`

## sql

ログインフォーム。

```php
    // Ensure admin will always be the first record, though really unnecessary
    $sql = "SELECT * FROM Users WHERE User='$user' AND Password='$pass' ORDER BY ID";
```

プリペアドステートメントを使うべき。ただ、全体的に書き換える必要がある。エスケープをするにしても自分で実装はせずに用意された関数を使うべき。しかし、[mysql_real_escape_string](http://php.net/manual/ja/function.mysql-real-escape-string.php)はPHP7で削除された。仕方がないので、自分で`'`を`''`に書き換えたら通った。

```php
    // Ensure admin will always be the first record, though really unnecessary
    $sql = "SELECT * FROM Users WHERE User='".str_replace("'","''",$user)."' AND Password='".str_replace("'","''",$pass)."' ORDER BY ID";
```

`gigem{cAn_y0U_sQL_TH3_Pr0bL3m?_9f431b}`

## maze

express製のサーバー。

```javascript
app.get('/*', function(request, response){
    console.log('request starting...');

    var filePath = __dirname + '/..' +request.url;
    if (filePath == __dirname)
        filePath = __dirname + '/../public/index.html';
    var extname = path.extname(filePath);
```

これで、ディレクトリトラバーサルができるようになっていたので、

```javascript
    var filePath = __dirname + '/../public' +path.normalize(request.url);
```

に直した。

`gigem{LifES_4_m4ze_37c83f}`

## shell-plugin

Pythonの[SimpleXMLRPCServer](https://docs.python.org/2/library/simplexmlrpcserver.html)で、OSのユーザーを追加するスクリプト。

```python
def add_user_func(name, password):
    os.system("./add-user.sh " + name + " " + password)
```

この部分は`subprocess`を使えば良いけれど、`add-user.sh`の中身は、

```bash
#!/bin/bash

mkdir /home/$1
useradd -G ctf-users --home /home/$1 -s /bin/bash $1

chown $1:$1 /home/$1

echo -e "$2\n$2" | passwd $1
```

シェルスクリプトでのエスケープなんてどうするのだろう？　ということで、英数字以外は弾くようにしたら通った。

```python
def add_user_func(name, password):
    name = re.sub(r'\W', '', name)
    password = re.sub(r'\W', '', password)
    os.system("./add-user.sh " + name + " " + password)
```

`gigem{gH0s7_in_7h3_Sh3ll_fb63a0}`

## 感想

たしかに、「守るためのコンテスト」感はある。SQLインジェクションとか他のコンテストで攻撃するのは慣れていても、「じゃあ守ってみて」と言われると戸惑いがあって、面白い。

とはいえ、これで正しい守り方が学べるかというと、上のような雑な回答でも通ってしまうという問題がある。mazeはまだディレクトリトラバーサルができるし、shell-pluginもユーザーが入力したもの違うnameとpasswordを渡してしまっているのは良くない。`password*|>?+$|!('"-`というパスワードが`password`になるので辞書攻撃で破られる。

この方式だと、テストを通るようなプログラムを一から実装するという最終手段があるので、一定以上に難しい問題は作れない。

防御側を問題にするのは難しそうだ。