チーム Harekaze で hxp CTF 2017 に参加しました。最終的にチームで 414 点を獲得し、順位は得点 499 チーム中 64 位でした。うち、私は 1 問を解いて 153 点を入れました。
以下、解いた問題の write-up です。
以下のようなソースコードが与えられました。
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}