前言
最近主要在学JAVA,不过PHP审计相关的技能也不能生疏了,于是打算去找点代码来审审,在CTFSHOW上找到了一款源码,而且目前也没有WP
那么就开审罢
(因为这套系统使用量比较少,而且是好几个月前提交的了,现在基本都给修好了,所以直接把这篇分析发出来了。)
框架分析
进来之后看到传参,估计是个MVC架构
来看看源码是怎么实现的,index.php中接受了action、do、id、userid等传参
继续往下看,发现MV的不是很C,可能是系统比较简单,直接把action的传值放在switch里决定包含什么文件。
点进一个文件看看,发现do的传值决定了程序要进行的操作
所以这里的action文件可以简单的理解为控制器,do传入的东西可以简单地理解为要执行的方法。
权限控制以及SQL语句执行方式分析
在开始审计之前,我还想知道这套系统是用什么方式来校验用户身份的,我发现了两个比较重要的函数
没有使用什么取巧的判断方式,这个我们是绕不过去的,并且鉴权失败会直接exit()。那么再看看sql语句的执行是怎么实现的,这里使用了query方法,这个方法在mysql类中定义,我们看看怎么实现
如下图,没有额外的过滤,直接执行传入的SQL语句,那么猜测这套系统应该会存在SQL注入相关的问题
未授权访问其一
刚刚我们分析了两个权限控制函数If_rabc()和is_admin(),并且提到这两个函数绕不过去,那么我们需要找到一些不存在这两个函数的方法进行调用。这里先找到了一个,address控制器在传入的do参数为空时可以触发
这里的display函数其实是用于加载视图的,因为和本文关系不大而且比较复杂,所以不展开分析了。总之我们直接get传入action=address,就可以访问到通讯录管理界面了
SQL注入其一
既然上述点的权限校验不严格,那么我们是否可以进一步利用呢?进一步分析代码
可以看到,在要执行的sql语句中有三个变量,我们逐一分析看看是否会出问题。首先是$search变量,对于$search变量来说,首先系统会判断是否POST传入kewords,如果有的话,将其拼接至一个语句中
但是注意,这里的kewords被魔术引号转义了,并且拼接的语句里也有单引号,所以这里我们是没有操作空间的。
继续往后看,下面的代码又进行了一个判断
这里是判断是否传入time_strat和time_over,如果存在那么又拼接到一个sql语句里,并且还会和我们上面的and name like ‘%strip_tags(kewords)%’进行拼接。但是非常不幸,这里用strtotime()函数进行了处理。
所以$search这个点算是彻底没用了,那么第二个点$pageNum呢?这个变量的值是这样定义的
可以看到,尽管没有过滤,但是它会被进行数字运算,这个点最终也无法利用。那么只剩下$numPerPage这个可控变量了。
可以看到,如果我们没传入numPerPage,那么其值为10。如果传入了那么就用我们传入的值。尽管它也用魔术引号进行转义了,但是并不影响我们直接执行SQL语句(因为没有引号)
这里有个小细节,首先这里是limit注入,并且有order by,不能直接联合注入,这里尝试使用 PROCEDURE ANALYSE()语句结合延时注入进行尝试。
下面是正常传参的返回时间
而传入sql语句之后产生延时,说明该点存在延时注入
如下图,可以使用sqlmap一把梭
任意用户注册(0day)
靠上面的sql注入比较水,主要是在limit后面注入还是有点麻烦,于是我又找到了一个没有进行权限校验的点,user控制器的add方法(添加用户)
其实刚开始看到这个点,我还觉得不太能利用,主要是这里,以为有Token校验机制会比较棘手
但往上看了一下token的实现方法,实在是被蠢哭了
把$module、$timestamp的值和#[email protected]%!^*拼接一下,md5加密之后就算token了,而且$module、$timestamp变量的值还是可控的。
那我们试着给module和timestamp传入1,拼接之后就变成1#[email protected]%!^*1,然后再对其MD5加密
然后POST传入一下,如图,如果不带任何东西访问的话就会提示非法数据来源
传入构造好的token值就可以往后执行了
绕过了这里就继续往后看,其实后面也没什么好看的了。这里把一堆值直接插入到了数据库里
这些变量的来源都在上面,全都可控
唯一需要注意的就是这个$id,为什么它需要注意,因为id在index.php中使用get传入
因此这里可以实现任意用户添加
先来演示一下添加用户,使用如下POC即可添加一个用户名为SSS,密码为test123的用户
这还不是最骚的,最骚的是他后台隐藏密码的圆点符是前端实现的,而用户管理还能看到admin
可以直接看到md5加密后的admin密码,不过解不出来,这里姑且也算一个小漏洞罢。
后台XSS1(0day)
后台有好多点,从数据库里取数据回显到视图上
直觉告诉我这种地方都容易出现XSS,试着改改上面任意用户添加的POC。这里是”><img src=1>的url编码
如图,成功实现存储型XSS
那么去代码层面看看到底是怎么产生的。这里是user控制器,没有传入方法
如图,这里先是执行了上面的sql语句,然后执行了fetchAll()方法。开发者已经给出了fetchAll方法的功能
往后看到这个点调用的user_list.htm视图,
跟进user_list.htm,不难发现,这里的意思大概就是把$list变量的值(也即fetchAll函数执行结果)遍历,也即我们之前写入的那些用户信息,然后输出出来
这里没有任何过滤就进行了输出,后台的大量视图都存在这个问题。
后台XSS2(0day)
上述是存储型XSS,看了一会代码,我又发现了一些反射型XSS。注意看user_list.html视图中的这个点。未经任何过滤就把time_start和time_over接收到的值输出出来了,因为这里使用的是$_REQUEST来接收参数,所以存在反射型XSS
构造如下Payload
address_list.htm同理
后记
这篇文章属于代码审计的练手之作,涉及到的漏洞原理都相对简单。其实一开始我是有点被误导的,因为题目给的条件是前台getshell,当时没往sql注入去想,以为是命令执行或者代码执行,再不济也是文件上传或者文件写入,于是找到危险的命令执行函数一路往上跟,但是跟到最后都没法利用,最后都没有啥可控点。最后突然醒悟不一定非得要往rce的方向去挖,挖洞还是不能太死脑筋!最后也是靠这道题收获了两个通用型编号,属于是意外之喜了。
推荐阅读:
实战 | 记一次1000美金的TikTok盲打XSS的漏洞挖掘
原创投稿作者:[email protected]