1. 漏洞背景与环境搭建
zzzcms作为一款轻量级PHP建站系统,凭借其模板标签化和低学习成本的特点,在中小型网站建设中颇受欢迎。但正是这样一个看似简单的系统,在1.7.5版本中存在一个致命的前台RCE漏洞。我第一次复现这个漏洞时,发现它的利用链设计非常巧妙——攻击者无需任何登录凭证,仅通过精心构造的HTTP请求就能在服务器上执行任意命令。
搭建测试环境其实很简单,我这里用的是phpstudy 2018 + PHP 5.6的组合。下载好zzzcms 1.7.5的安装包后,解压到WWW目录,访问安装页面一路下一步就行。有个细节要注意:安装完成后记得删除install目录,否则会影响后续漏洞触发。我遇到过好几次因为没删install目录导致payload执行失败的情况。
2. 漏洞原理深度解析
这个漏洞的核心在于模板解析过程中的代码注入。zzzcms的模板引擎在处理{if}标签时,会直接对条件表达式进行eval执行。正常情况下这个功能是用来做简单的逻辑判断,但开发者没有对传入的参数做严格过滤,导致攻击者可以通过进制编码绕过关键字检测。
我通过动态调试发现,当请求/search/路由时,系统会将keys参数直接拼接到模板解析逻辑中。比如我们构造一个包含base_convert的payload,PHP会先执行进制转换,最终还原出危险的函数名。这种利用方式非常隐蔽,因为请求中不会出现明显的system、exec等危险函数名。
3. 利用链完整构造过程
3.1 进制编码的艺术
要成功利用这个漏洞,关键是要掌握base_convert的妙用。这个PHP函数能在不同进制间转换数字,配合36进制可以完美绕过关键字过滤。举个例子:
base_convert(1751504350,10,36) // 会转换成"system"我在测试时整理了一份常用命令的转换表:
base_convert(784,10,36)→ "ls"base_convert(15941,10,36)→ "cat"base_convert(727432,10,36)→ "flag"
3.2 分步攻击演示
完整的攻击流程分为三个阶段:
- 探测漏洞是否存在:发送包含phpinfo的payload,观察返回结果
- 写入webshell:通过进制编码拼接文件写入操作
- 连接webshell获取控制权
最精妙的部分是文件路径的构造。由于直接写绝对路径容易被WAF拦截,我采用动态拼接的方式:
(base_convert(25,10,36)^base_convert(1,10,36)^base_convert(23,10,36)) // 得到斜杠"/"这样组合出来的路径字符串既不会触发安全检测,又能准确定位到web目录。
4. 防御方案与修复建议
官方在后续版本中修复了这个漏洞,主要做了三方面改进:
- 增加模板标签白名单机制
- 禁用base_convert等危险函数
- 引入模板编译缓存
对于还在用1.7.5版本的用户,我建议立即升级。如果暂时不能升级,可以在nginx配置中添加以下规则来缓解风险:
location ~* /search/ { if ($args ~* "base_convert") { return 403; } }5. 实战中的技巧与坑点
在实际测试中我发现几个值得注意的地方:
- PHP版本差异会影响payload执行结果,5.6环境下最稳定
- 某些安全模块会拦截array_map调用,需要调整调用方式
- 写入webshell时要注意目录权限问题
有一次我在测试时遇到payload执行失败的情况,后来发现是因为php.ini中disable_functions包含了base_convert。这时候就需要换用其他编码方式,比如hex2bin配合十六进制字符串。
这种漏洞的挖掘思路也值得学习:重点关注模板引擎的实现方式,特别是涉及动态代码执行的部分。我在审计其他CMS时,就曾用类似方法发现过多个同类型漏洞。