我们已经准备好了,你呢?

2024我们与您携手共赢,为您的企业形象保驾护航!

这是酒仙桥六队第93篇文章。

全文共2986个字,预计阅读需要11分钟。

前言

记得在一次授权渗透测试中遇到过这样一个项目,开始fuzz前端,扫描端口,没发现可利用的漏洞,本来可以挖出xss,结果没找到,不行就挖出信息泄露,果然挖出了信息泄露,拿到了程序的指纹。

php域名授权_域名授权使用_域名授权码在哪里

它是一个开源网站系统,我在百度上搜索了程序暴露的漏洞,并进行了测试,发现全部失败,我猜测是程序升级了较新的版本,导致网上暴露的漏洞被修复了。既然没有捷径,只能去官网下载一份源码审计测试一下。

源代码审计

1.数据采集

通过查看程序源码发现,程序封装了自己的数据获取辅助函数:get()、post()、()等,其获取流程如下:以post()函数为例:post('name', 'vars')。

php域名授权_域名授权码在哪里_域名授权使用

可以看到我们传入的数据又被传递到了函数中:

域名授权码在哪里_域名授权使用_php域名授权

在函数中会对获取的数据进行一系列强过滤,比如这里的vars只能传递汉字、字母、数字、点、逗号、空格等。(PS:因为不能传递括号“(,)”,所以SQL注入中的函数无法使用,也导致了误注入、盲注,只能使用联合查询。)然后函数最后进行处理。

域名授权码在哪里_php域名授权_域名授权使用

跟进功能:

域名授权使用_域名授权码在哪里_php域名授权

数据也经过双重处理。

数据采集​​流程图如下所示:

域名授权码在哪里_php域名授权_域名授权使用

现在我们对这个程序的数据获取已经有了初步的了解,主要的数据获取是通过post()、get()、get()三个辅助函数来实现的。

2. 注入开采

在审计过程中,发现该程序含有大量如下代码:

域名授权使用_域名授权码在哪里_php域名授权

这里我重点讲一下DB类库中封装的where方法,代码如下:

php域名授权_域名授权码在哪里_域名授权使用

如果这里传入的$where变量是索引数组,那么就会输入红框里的代码,并将值连接起来。

明确了目标之后,我们就可以开始寻找目标了:

php域名授权_域名授权使用_域名授权码在哪里

域名授权码在哪里_域名授权使用_php域名授权

一番查找之后发现,要么是数据不可控,要么是数据经过了函数,加上单引号的保护,达到了过滤的效果。

域名授权使用_域名授权码在哪里_php域名授权

3. 事态突然转变

经过多次搜索where等关键字,均未获得突破性进展,随后尝试搜索$GET、$POST等原生态数据:

php域名授权_域名授权码在哪里_域名授权使用

问题出现在apps\home\\.php文件中的方法中:由于此方法代码较长,因此仅抓取关键部分。

php域名授权_域名授权码在哪里_域名授权使用

可以看到,首先遍历了$_POST数组,然后把该key作为$where数组的键。(这个就是key),但是这里我们需要验证一下key的值是不是1,以及这个1是整数还是字符串,因为我们要控制索引数组的输入。

域名授权使用_php域名授权_域名授权码在哪里

是int类型的,完全满足我们上述的要求。

此时我们可以控制这个$array的key和value了,但是$key:只能是/^[\w-.]+$/,$value:只能是/^[\x{4e00}-\x{9fa5}\w-.,\s]+$/u。

然后继续看代码:

php域名授权_域名授权使用_域名授权码在哪里

这里的$page是true,因为默认值就是true,而重新赋值的时候我们也没有办法控制,所以这里肯定会执行该方法。

方法代码如下:代码较长,只截取关键部分。

域名授权使用_域名授权码在哪里_php域名授权

我们传递的$array已成功传递给where方法。

然后执行一个页面方法:

php域名授权_域名授权使用_域名授权码在哪里

这里设置了一个sql属性,后面会用到。

然后执行了最后一个方法。

php域名授权_域名授权使用_域名授权码在哪里

做法就是把我们之前设置的属性值组合起来,形成一个完整的SQL语句

php域名授权_域名授权使用_域名授权码在哪里

这里我们直接通过where、order、page等链式操作把我们之前设置的属性进行替换和串联起来了,而且因为我们前面分析过,在where方法中,如果传入的是索引数组,是不受单引号保护的,所以看到这里,我们差不多可以明白我们成功逃脱了单引号的保护。

总体流程图如下:

域名授权码在哪里_php域名授权_域名授权使用

整个过程已经基本完成,测试结果如下:

域名授权码在哪里_域名授权使用_php域名授权

可以看到我们的输入已经成功带入SQL语句执行了,需要注意的是,括号()里面是我们输入的内容。

结合上面辅助函数的过滤,我们知道输入的数据只能是指定的字符:

php域名授权_域名授权码在哪里_域名授权使用

常规的错误注入是无法成功的,比如:

页面并没有像上面一样报错,而是返回了一个正常的页面,因为检测到了括号,直接将我们的数据设置为了null。

4. 旁路注射

因为可控制点在where之后,所以where后面可以跟子查询,如图:

域名授权使用_域名授权码在哪里_php域名授权

域名授权使用_php域名授权_域名授权码在哪里

所以我们绕过这个问题的方法是通过子查询进行操作,因为子查询不需要使用括号,如:

我们的注入没有被过滤,成功引入到了SQL语句中。但是由于不能使用括号,不能使用mid等截断函数,也不能使用=等一些比较运算符,如何获取精准数据又成了问题?

这里的突破目标是改造SQL语句,首先需要了解SQL的执行顺序。

域名授权码在哪里_php域名授权_域名授权使用

可以看到之前已经执行了where,那么如何使用呢?如下:

域名授权码在哪里_php域名授权_域名授权使用

可以看出,即使是常量,如果不满足后面的where条件,那么也不会查询出任何数据,我们可以利用where比例来进行数据对比。

因为不能使用=之类的比较运算符,所以我们需要找一些东西来代替它,而且因为不能使用截取函数,所以我们不能逐一比较数据,所以我们必须想办法逐一进行比较。

找到一个完美的替代,因为它后面可以跟一个正则表达式,而且 . 可以代表任意字符,* 代表任意数字,刚好满足我们的要求。用法如下:

域名授权使用_php域名授权_域名授权码在哪里

把我们需要查询的字段放到where中,通过where来控制返回的数据。

(请使用^来定义开头。例如:^ad.*)

因为数据不能使用引号,所以我们需要将引号里的数据用十六进制进行编码,效果是一样的。

对返回的内容进行控制,实现的效果如下:

域名授权使用_域名授权码在哪里_php域名授权

在Sql语句中,先执行的是子查询,而在整个父语句中,我们的子查询的结果在where语句中,而且使用了AND连接。也就是说,我们的子查询的结果也控制了整个sql语句的结果,因此才可以准确的判断数据。

5. 本地测试

正确的页面显示:

错误页面显示:

我们的真实数据:

域名授权使用_域名授权码在哪里_php域名授权

我们将我们的正则表达式编码成16进制并执行,通过页面返回的内容判断数据量,最终达到绕过过滤,输出数据的目的。

最终整体流程图可以分为三步,如图所示:

域名授权使用_php域名授权_域名授权码在哪里

域名授权码在哪里_域名授权使用_php域名授权

域名授权使用_域名授权码在哪里_php域名授权

测试结果证明我们的注入漏洞被成功利用,接下来就是将其映射到项目网站上,经过大量的,我们成功获取了管理员账号密码:

php域名授权_域名授权码在哪里_域名授权使用

后台

易受攻击的文件:core\\file.php

域名授权使用_域名授权码在哪里_php域名授权

后缀白名单来自于函数的第三个参数,寻找函数被调用的地方。

域名授权使用_php域名授权_域名授权码在哪里

后缀白名单来自于函数的第二个参数,搜索函数调用。

触发文件:apps\home\\.php

域名授权使用_php域名授权_域名授权码在哪里

继续跟进方法。

域名授权码在哪里_域名授权使用_php域名授权

方法是返回对应的配置项,通过self::()来加载配置项内容。

域名授权码在哪里_域名授权使用_php域名授权

部分配置项来自于md5().php文件,我们只要控制这个文件中的选项,就能控制允许上传的后缀白名单。

这是您修改配置文件的地方。

文件:apps\admin\\\.php

php域名授权_域名授权码在哪里_域名授权使用

从 $_POST 遍历的键被传递到 $this-> 方法中。

php域名授权_域名授权码在哪里_域名授权使用

php域名授权_域名授权码在哪里_域名授权使用

程序会先把修改后的配置内容更新到数据表中,然后再把数据表中的内容写入到md5().php文件中,这样我们就可以添加任意类型的后缀文件了。

使用

登录后台->全局配置->配置参数->立即提交,使用burp抓包。

只需在 POST 数据中添加 :=php 字段。

php域名授权_域名授权码在哪里_域名授权使用

已成功将其写入文件。

php域名授权_域名授权码在哪里_域名授权使用

设置好允许上传白名单之后,我们可以通过上传PHP来实现。

上传文件 exp: .html

<html lang="en"><head>    <meta charset="UTF-8">    <title>pbootcms文件上传title>head><body><form action="http://xxxxx/?member/upload" method="post" enctype="multipart/form-data">    <input type="file" name="upload">    <input type="submit" name="mufile">form>body>html>

将exp保存为HTML文件,修改对应域名后直接上传,如文件上传证明所示。

在本地顺利走完流程之后,在项目网站上使用也很顺利,直接就搞定了,又可以开开心心的喝冰可乐了。

总结

整个过程从网站获取指纹开始,然后找到源代码进行审计。审计过程中还是花了不少时间,主要是寻找前端审计的入口点,绕过过滤器注入数据。当时觉得根本用不上,还好当时没放弃,慢慢一步步做,最后搞定了。

二维码
扫一扫在手机端查看

本文链接:https://by928.com/1972.html     转载请注明出处和本文链接!请遵守 《网站协议》
我们凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求,请立即点击咨询我们或拨打咨询热线: 13761152229,我们会详细为你一一解答你心中的疑难。

项目经理在线

我们已经准备好了,你呢?

2020我们与您携手共赢,为您的企业形象保驾护航!

在线客服
联系方式

热线电话

13761152229

上班时间

周一到周五

公司电话

二维码
微信
线