ThinkPHP后台框架安全审计入门:以ThinkAdmin未授权文件读取漏洞(CVE-2020-25540)为例

发布时间:2026/5/19 14:55:05

ThinkPHP后台框架安全审计入门:以ThinkAdmin未授权文件读取漏洞(CVE-2020-25540)为例 ThinkPHP框架安全审计实战从CVE-2020-25540看未授权访问漏洞挖掘在开源框架的生态中安全问题往往隐藏在看似平常的功能实现里。ThinkAdmin作为ThinkPHP生态中广泛使用的后台管理系统其2020年曝光的未授权文件读取漏洞CVE-2020-25540为我们提供了一个绝佳的研究样本。本文将带您深入代码层剖析漏洞成因并建立系统的审计方法论。1. 漏洞背景与影响分析ThinkAdmin是基于ThinkPHP5.1开发的后台管理系统主要面向企业级应用开发。2020年8月安全研究人员发现其v6版本存在严重的未授权访问漏洞攻击者无需登录即可读取服务器任意文件。该漏洞影响范围包括ThinkAdmin ≤ 2020.08.03.01v5版本任意文件读取v6版本目录遍历任意文件读取典型攻击场景表现为通过未授权接口获取服务器目录结构构造特殊路径读取敏感文件如配置文件、日志文件进一步获取数据库凭证等关键信息提示这类漏洞常出现在未严格校验权限的API接口中特别是在自动更新、文件管理等模块2. 环境搭建与调试准备2.1 基础环境配置审计PHP项目需要准备以下工具链# 使用Docker快速搭建PHP7.2环境 docker run -it --name thinkaudit -p 8080:80 -v $(pwd):/var/www/html php:7.2-apache # 进入容器安装必要组件 docker exec -it thinkaudit bash apt update apt install -y git unzip curl -sS https://getcomposer.org/installer | php -- --install-dir/usr/local/bin --filenamecomposer2.2 漏洞版本部署获取特定版本源码并安装依赖git clone https://github.com/zoujingli/ThinkAdmin.git cd ThinkAdmin git checkout v2020.08.03.01 # 使用国内镜像加速依赖安装 composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/ composer install关键配置文件需要特别注意文件路径安全配置要点config/database.php数据库连接凭证config/app.php应用密钥和加密设置public/index.php入口文件安全过滤3. 漏洞原理深度剖析3.1 未授权访问入口定位通过对比版本更新日志我们发现修复重点在app/admin/controller/api/Update.php文件。该控制器包含三个关键方法version()- 版本信息获取node()- 文件列表获取get()- 文件内容读取问题核心在于控制器继承链class Update extends Controller { // 未实现权限校验 }而父类Controller的初始化方法中缺少必要的权限检查// think-library/src/Controller.php protected function initialize() { // 缺少类似以下的权限验证 // if (!$this-checkAuth()) { // $this-error(Unauthorized); // } }3.2 文件遍历漏洞分析node()方法的危险实现public function node() { $this-success(获取文件列表成功, InstallService::instance()-getList( json_decode($this-request-post(rules, [], ), true), json_decode($this-request-post(ignore, [], ), true) )); }攻击者可控制rules参数传入任意路径通过_scanList()方法实现目录遍历private function _scanList($path, $data []): array { foreach (NodeService::instance()-scanDirectory($path, [], null) as $file) { $data[] $this-_getInfo(strtr($file, \\, /)); } return $data; }典型攻击PayloadPOST /admin.html?sadmin/api.Update/node Content-Type: application/x-www-form-urlencoded rules[../../../../etc]3.3 任意文件读取漏洞链get()方法的安全缺陷public function get() { $filename decode(input(encode, 0)); if (!ModuleService::instance()-checkAllowDownload($filename)) { $this-error(下载的文件不在认证规则中); } // 读取文件内容... }虽然存在checkAllowDownload()检查但存在两个关键问题Windows系统下可通过字符替换绕过限制public/static/../../config/databasephp白名单规则本身包含危险路径$data [config, public/static, public/router.php];4. 安全审计方法论实践4.1 敏感函数追踪法在PHP审计中这些函数需要特别关注危险函数常见风险审计要点file_get_contents文件读取参数是否用户可控include/require文件包含路径是否经过校验exec/system命令执行参数是否过滤unserialize反序列化数据是否可信通过grep快速定位风险点grep -rn file_get_contents app/4.2 权限校验检查清单在审计控制器时应验证以下防护措施是否继承自安全基类是否实现initialize权限检查敏感操作是否有adminAuth等注解路由配置是否强制身份验证4.3 输入过滤验证矩阵建议建立参数过滤检查表参数来源过滤函数安全示例GET/POSThtmlspecialcharsinput(name, , htmlspecialchars)文件路径realpathrealpath(trim($path, /))JSON输入json_decodejson_decode($input, false, 3)5. 防御方案与最佳实践5.1 代码层修复方案对于类似漏洞推荐采用多层防御控制器基类强制权限校验abstract class BaseController { protected function initialize() { if (!$this-checkAuth()) { $this-error(Access Denied); } } }文件操作实现安全封装class SafeFile { public static function read($path) { $realpath realpath($path); if (strpos($realpath, ROOT_PATH) ! 0) { throw new Exception(Invalid file path); } return file_get_contents($realpath); } }5.2 架构安全建议使用最小权限原则运行PHP进程敏感目录设置open_basedir限制定期进行依赖组件安全更新关键操作记录详细审计日志在项目实践中我们发现多数文件操作漏洞源于两个误区过度信任前端输入和缺乏深度防御设计。建议在代码审查时将文件操作相关代码标记为高风险点进行重点检查。

相关新闻