PHPCMS漏洞分析合集(下)

2019-07-27 约 191 字 预计阅读 1 分钟

声明:本文 【PHPCMS漏洞分析合集(下)】 由作者 mochazz 于 2019-07-27 09:36:00 首发 先知社区 曾经 浏览数 26 次

感谢 mochazz 的辛苦付出!

本篇详细分析了 PHPCMS 的部分历史漏洞。其中多是以获取到漏洞点为场景,反向挖掘至漏洞触发入口(假设自己发现了漏洞点,模拟如何找寻整个攻击链及其入口点),旨在提高自身代码审计能力。当中包含一些网络上未公开的触发点,以及补丁对比分析与绕过。

v9.6.1任意文件读取

这个版本的 任意文件读取 漏洞和上个版本的 SQL注入 漏洞原理是类似的,且出问题的文件均在 phpcms/modules/content/down.php 中。在该文件的 download 方法中最后一行调用了 file_down 文件下载函数,我们可以看到其第一个参数是要读取的文件路径。

我们再来看看 download 方法中有哪些限制条件。可以看到其开头部分的代码,和上一个版本的 SQL注入 类似,唯一不同的是这里加解密的 key 变成了 $pc_auth_key ,我们等下就要来找找使用 $pc_auth_key 进行加密的可控点。继续看 download 方法,里面对要下载的文件后缀进行了黑名单校验,但是末尾又对 >< 字符进行替换,这就导致后缀名正则可被绕过,例如: .ph<p 。(下图对应文件位置:phpcms/modules/content/down.php)

现在我们就要来找找使用 $pc_auth_key 作为加密 key 的可控点。通过搜索关键字,我们可以看到有三处地方。然而前两处地方是不可以利用的,因为都有登录检测。而第三个点就可以利用,我们看其中 $i、$d、$s 作为明文字符串被加密。(下图对应文件位置:phpcms/modules/content/down.php)

有了加密字符串,我们如何能够从前台获取呢,这里其实在最后一行包含模板文件时,将加密字符串 $downurl 输出了,这样也就解决了我们获取的问题。

$i、$d、$s 这三个变量从哪里来?我们往前看,代码有没有相当熟悉?这里只对 $i 进行了 intval 过滤,其他两个变量还是可以利用。而且加密字符串 $a_k 的获取,就和上个版本的 SQL注入 漏洞攻击链的前2步是一样的,这里不再赘述。(下图对应文件位置:phpcms/modules/content/down.php)

我们在构造 payload 的时候,我们要注意整个攻击过程会经过两次 safe_replace 、两次 parse_str 、一次 str_replace(array('<','>'), '',$fileurl) ,而程序对 ..php 字符进行了检测。所以我们要想访问 php 文件或进行路径穿越,后缀可以设置成 ph>p ,路径符可以变成 .>. 。但是 safe_replace 函数会 str_replace('>','>',$string) ,所以 > 字符需要编码两次,变成 %25253e

我们可以将整个漏洞的触发过程整理成下图:

最后来看一下官方发布的 PHPCMS v9.6.2 中是如何修复这个漏洞的,补丁如下:

可以看到补丁将后缀匹配规则放在离下载文件最近的地方,貌似能防止规则中的文件被读取,但是我们可以利用 windows 的特性,在 windows 下绕过这个正则,这也是网传的一种 PHPCMS v9.6.2任意文件下载 漏洞。

v9.6.2前台SQL注入

这个版本的的注入,是建立在任意文件读取漏洞存在的情况下才可利用。通过任意文件读取漏洞获得加解密的 key 值,我们可以用这个 key 加密我们的 SQL注入payload 。由于程序对解密后的数据并未过滤,最终导致漏洞发生。严格上来讲 v9.6.2 版本的注入只能在 windows 上利用,具体原因在上面的任意文件读取漏洞分析时也说了。下面我们来具体分析一下这个漏洞。

漏洞文件位于 phpcms/modules/member/classes/foreground.class.php ,代码如下图。我们可以明显看到下图第33行,程序直接将解密后的数据未经过滤直接带入查询。而待解密数据 $phpcms_auth 和解密秘钥 $auth_key 均可构造。

我们先来看一下待解密数据 $phpcms_auth 如何构造。从下图中,可以看出程序将从 cookie 中的 xxx_auth 字段经过 sys_auth 函数解密后,返回给了 $phpcms_auth ,而默认情况下使用 pc_base::load_config('system', 'auth_key') 作为加解密的 key 值。

pc_base::load_config('system', 'auth_key') 的值在网站搭建好后,会存储在 caches/configs/system.php 中,我们可以通过任意文件读取来获得这个值。

现在 $phpcms_auth 已经搞定了,我们再来看看 $auth_key = get_auth_key('login') 如何构造,跟进 get_auth_key 的代码。我们可以看到 $auth_key$prefix、pc_base::load_config('system','auth_key')、ip() 三个元素决定。前两个都是已知的,而第三个获取用户IP的函数存在IP伪造的问题,也可以是固定的。

所以 get_auth_key('login') 的值也是我们可以构造的,剩下的事情只要我们将 payload 传给加密函数加密两次即可。我们最后再来看一下 PHPCMS v9.6.3 中是如何修复这个漏洞的,补丁如下:

可以明显看到,补丁将解密后获得的 $userid 进行了强转。

结束语

分析历史漏洞好处在于,可以使自身对这个 CMS 更熟悉,摸清该 CMS 普遍存在的问题,甚至有机会通过 bypass 补丁来发现新的 0day 。有些补丁只是暂时修复了漏洞,安全隐患仍然存在。随着 CMS 功能越来越多,我们可以将新功能中的利用点,结合之前的风险点,打出一条漂亮的攻击链,期待下个 0day 的诞生。

关键词:[‘安全技术’, ‘漏洞分析’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now