st98 の日記帳


[ctf] hxp CTF 2017 の write-up

チーム Harekaze で hxp CTF 2017 に参加しました。最終的にチームで 414 点を獲得し、順位は得点 499 チーム中 64 位でした。うち、私は 1 問を解いて 153 点を入れました。

以下、解いた問題の write-up です。

[Web 150 + 3] cloud18

以下のようなソースコードが与えられました。

index.php

<?php

require_once("User.php");

session_start();

if (isset($_POST["username"]) && isset($_POST["password"])) {
    $user = (new User($_POST["username"]))->login($_POST["password"]);
    if (!$user->hasFailed()) {
        $_SESSION["user"] = $user;
    }
}

?>
<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" href="stylesheet.css">
</head>
<body>
<div id="page-wrap">
    <h1>cloud18 Editor - Your better development environment, in the cloud</h1>
    <p>Powerful Workspaces - All the freedom you’d expect!</p>
    <div id="menu">
        <?php
        if ($_SESSION["user"]) {
            echo "<a href='/editor.php'>editor</a>";
            echo "<a href='/logout.php'>logout</a>";
        } else {
            echo "<a href='/register.php'>register</a>";
        }
        ?>
    </div>
    <?php
    if($_SESSION["user"]){
        echo "<div class='alert success'>login sucessful</div>";
        if($_SESSION["user"]->getName() === "admin"){
            echo "<div class='alert success'>" . shell_exec("/usr/bin/get_flag") . "</div>";
        }
    }
    ?>
    <form action="/index.php" method="post">
        <input placeholder="enter username" type="username" name="username">
        <input placeholder="enter password" type="password" name="password">
        <input class="pseudo-btn" type="submit" value="submit">
    </form>
</div>
</body>
</html>

ログイン処理やメニューの表示などが行われています。

User.php では User というクラスの定義が行われており、この中で登録、ログイン、パスワードの変更のようなメソッドが定義されています。

ログイン後、もしユーザ名が admin であれば /usr/bin/get_flag を実行してフラグを表示するようです。

editor.php

<?php

session_start();

require_once("User.php");

if (preg_match("/exec|system|passthru|`|proc_open|popen/", strtolower($_POST["method"].$_POST["text"])) != 0) {
    exit("Do you really think you could pass something to the command line? Functions like this are often disabled! Maybe have a look at the source?");
}

?>
<!DOCTYPE html>
<html>
<head>
    <title>Editor</title>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" href="stylesheet.css">
</head>
<body>
<div id="page-wrap">
    <h1>cloud18 Editor - Your better development environment, in the cloud</h1>
    <p>Powerful Workspaces - All the freedom you’d expect!</p>
    <div id="menu">
        <?php
        if ($_SESSION["user"]) {
            echo "<a href='/logout.php'>logout</a>";
        } else {
            echo "<a href='/index.php'>login</a>";
            echo "<a href='/register.php'>register</a>";
            exit();
        }
        ?>
    </div>
    <?php
    $editedText = preg_replace_callback("/" . $_POST["regex"] . "/", function ($matches) {
        return call_user_func($_POST["method"], $matches[0]);
    }, $_POST["text"]);
    if($editedText) {
        echo("<div class='alert success'>" . $editedText . "</div>");
    }
    ?>
    <form action="/editor.php" method="post">
        <select name="method">
            <option value="" disabled selected>select a method</option>
            <option value="strtoupper">to upper case</option>
            <option value="strtolower">to lower case</option>
            <option value="ucfirst">first letter to upper case</option>
        </select>
        <input placeholder="enter valid regex" type="text" name="regex">
        <textarea id="text" placeholder="enter your text here" name="text"></textarea>
        <input class="pseudo-btn" type="submit" value="submit">
    </form>
</div>
</body>
</html>

関数 (strtoupper strtolower ucfirst の 3 択)、正規表現、テキストの入力を行えるフォームがあります。送信すると、入力した正規表現にマッチした文字列を第一引数として、選択した関数を呼び出してその返り値を表示しています。

<select name="method">…</select><input type="text" name="method"> に変えることで任意の関数を入力できるようになりますが、以下のように呼び出せる関数のチェックが行われています。

if (preg_match("/exec|system|passthru|`|proc_open|popen/", strtolower($_POST["method"].$_POST["text"])) != 0) {
    exit("Do you really think you could pass something to the command line? Functions like this are often disabled! Maybe have a look at the source?");
}

OS コマンドを実行するのは厳しそうなので、直接 /usr/bin/get_flag の内容を得られないか試してみましょう。関数に file_get_contents、正規表現に .+、テキストに /usr/bin/get_flag を入力すると、関数の返り値を出力する部分に ELF ファイルが表示されました。

HTML 部分を削って実行するとフラグが得られました。

$ ./get_flag 
hxp{Th1s_w2sn't_so_h4rd_now_do_web_of_ages!!!Sorry_f0r_f1rst_sh1tty_upload}
hxp{Th1s_w2sn't_so_h4rd_now_do_web_of_ages!!!Sorry_f0r_f1rst_sh1tty_upload}
このエントリーをはてなブックマークに追加
st98.github.io / st98 の日記帳