当前位置: 首页 > news >正文

代码审计入门:手把手带你分析ThinkAdmin那个未授权文件读取的CVE-2020-25540

代码审计实战:ThinkAdmin未授权文件读取漏洞深度剖析

在安全研究领域,PHP应用的代码审计一直是发现高危漏洞的重要途径。今天我们要解构的是一个经典案例——ThinkAdmin框架中的CVE-2020-25540漏洞,这个漏洞允许攻击者在未授权情况下读取服务器任意文件。不同于简单的漏洞复现教程,我们将从代码层面揭示漏洞形成的完整链条,理解开发者容易陷入的安全误区。

1. 漏洞背景与核心问题

ThinkAdmin是基于ThinkPHP的后台管理系统框架,2020年曝光的这个漏洞影响v5和v6版本。其本质是权限控制缺失路径校验不严的双重缺陷组合:

  • 未授权访问app/admin/controller/api/Update.php中的nodeget方法未做身份验证
  • 路径遍历:通过精心构造的$rules参数可突破目录限制
  • 过滤绕过checkAllowDownload函数的校验逻辑存在缺陷

典型攻击场景分为两个阶段:

  1. 通过node方法列目录结构
  2. 使用get方法读取敏感文件(如配置文件、源码)

2. 漏洞链深度解析

2.1 未授权访问入口点

漏洞始于Update.php控制器,其三个关键方法均未实现权限控制:

namespace app\admin\controller\api; use think\admin\Controller; class Update extends Controller { public function version() { /* 获取版本信息 */ } public function node() { /* 文件列表获取 */ } public function get() { /* 文件内容读取 */ } }

这种设计违反了最小权限原则,API接口默认应视为需要认证,除非显式声明为公开。

2.2 目录遍历实现路径

node()方法将用户输入的rules参数直接传递给InstallService::getList()

public function node() { $this->success('获取文件列表成功!', InstallService::instance()->getList( json_decode($this->request->post('rules', '[]', ''), true), json_decode($this->request->post('ignore', '[]', ''), true) )); }

跟踪getList()方法,发现其使用_scanList()处理用户输入的路径:

public function getList(array $rules, array $ignore = []) { foreach ($rules as $rule) { $name = strtr(trim($rule, '\\/'), '\\', '/'); $data = array_merge($data, $this->_scanList($this->root . $name)); } // ...忽略处理逻辑... }

关键问题在于:

  • 未对$rule进行规范化校验
  • 直接拼接$this->root(网站根目录)与用户输入
  • 递归扫描目录时未检查...等特殊路径

2.3 文件读取的过滤缺陷

get()方法的危险之处在于其解码逻辑与不完善的过滤:

public function get() { $filename = decode(input('encode', '0')); if (!ModuleService::instance()->checkAllowDownload($filename)) { $this->error('下载的文件不在认证规则中!'); } // 文件读取操作... }

checkAllowDownload()的校验规则存在明显缺陷:

校验类型规则绕过方法
黑名单禁止database.phpWindows下使用database"php
白名单允许public/static等路径通过../跨目录

典型的攻击Payload构造:

public/static/../../etc/passwd

3. 安全编码实践建议

3.1 输入验证原则

应建立多层次的防御策略:

  1. 规范化校验

    // 检查路径是否在允许范围内 function validatePath($path) { $realpath = realpath($this->root . $path); return strpos($realpath, $this->root) === 0; }
  2. 禁用特殊字符

    if (preg_match('/\.\.|\x00|[<>]/', $path)) { throw new InvalidArgumentException('非法路径'); }

3.2 权限控制方案

推荐采用ThinkPHP的中间件机制:

// 创建Auth中间件 php think make:middleware Auth // 中间件内容 public function handle($request, Closure $next) { if (!$this->isLogin()) { return redirect('/admin/login'); } return $next($request); } // 注册中间件 Route::group('admin/api', function() { Route::post('update/node', 'api.Update/node'); })->middleware(Auth::class);

3.3 安全函数对比

危险函数与替代方案:

危险函数风险安全替代
file_get_contents无路径限制fopen+stream_get_contents
scandir暴露目录结构预定义文件索引
include代码执行使用模板引擎

4. 漏洞挖掘方法论

4.1 审计切入点清单

进行代码审计时应优先检查:

  1. 未鉴权的控制器方法
  2. 接收用户输入的文件操作
  3. 动态包含(include/require)
  4. 反序列化操作
  5. 数据库裸查询

4.2 典型漏洞模式识别

PHP中常见的危险模式:

// 模式1:直接包含用户输入 include $_GET['page'] . '.php'; // 模式2:未过滤的文件操作 file_put_contents($user_upload, $data); // 模式3:危险的反射调用 $class = new $controller_name; $class->$action();

4.3 工具链推荐

提高审计效率的工具组合:

  • 静态分析

    • PHPStan(类型安全检查)
    • Psalm(漏洞模式识别)
  • 动态测试

    • Xdebug(调用栈跟踪)
    • Burp Suite(参数变异测试)
  • 辅助工具

    # 查找敏感函数使用 grep -rn "file_get_contents" ./app # 查找未鉴权路由 grep -rn "->withoutMiddleware" ./routes

在真实项目中,建议建立代码审计检查表,对每个用户输入点进行"数据从哪里来,到哪里去"的完整跟踪。ThinkAdmin这个案例告诉我们,即使是在成熟的框架基础上开发,忽视基础安全原则仍会导致严重漏洞。

http://www.jsqmd.com/news/540430/

相关文章:

  • Windows下用Rclone挂载WebDAV的完整指南:从安装到开机自启(含常见问题解决)
  • 3月当地美食攻略,本地人喜欢的美食品牌推荐必吃分析,招牌美食/麻辣鱼/招牌江湖菜/江湖川菜/江湖菜,当地美食品牌有哪些 - 品牌推荐师
  • 学术文献格式转换工具:caj2pdf本地化解决方案
  • Python并发编程实战:线程、进程、协程,到底怎么选?
  • 颠覆级英雄联盟全流程辅助工具:League-Toolkit重新定义游戏体验
  • 你的DICOM数据安全吗?SPM12转换NII格式前必须检查的3个细节(以脑影像为例)
  • 数学在线组卷系统 kmath.cn
  • PC+APP双端企业考勤打卡系统——部门级配置继承、GPS围栏/内网双模打卡、节假日方案、定时预生成
  • 重构AI交互体验:SillyTavern多模态对话系统全解析
  • 5个维度解析:如何通过Excel可视化突破AI算法学习瓶颈
  • 数据分析师必看:卡方、t、F分布实战应用指南(附Python代码)
  • Degrees of Lewdity中文本地化版本完全指南:从安装到精通
  • 5倍效率提升:Motrix WebExtension让浏览器下载速度突破极限
  • 抗震支架性能对比:聚焦国内口碑制造企业,市面上抗震支架优质品牌分析更新 - 品牌推荐师
  • 稚晖君亲自面试!智元机器人(Agibot)大模型技术面经全记录(含Transformer高频考点)
  • 【MX-X8-T7】「TAOI-3」2236 A.D.
  • GIL之下如何真正掌控内存?深度解析Python智能体的4层内存调度架构,立即生效
  • 5步打造专属管理系统界面:vue-vben-admin主题定制全指南
  • 告别Web界面!用Postman和Java代码自动化发布GeoServer图层(附中文包避坑)
  • ROS2接口实战:从传感器数据到自定义消息的完整开发流程(附Python示例)
  • 2026年欧姆龙传感器厂家推荐榜:欧姆龙PLC,欧姆龙行程开关,欧姆龙光栅厂家推荐榜——优选靠谱欧姆龙传感器供应商 - 海棠依旧大
  • 在Linux上无缝运行Windows应用:deepin-wine技术深度解析
  • 钉钉机器人Markdown表格发送实战:绕过限制的创意方案
  • 3个维度突破:SillyTavern如何重构AI多模态交互体验
  • 基于Coqui TTS的高质量语音合成实战:从模型部署到生产环境优化
  • 5步掌握MOOTDX:Python通达信数据接口的完整实战指南
  • 手把手教你用STM32驱动迪文屏:从RS232配置到页面控件交互全流程
  • HC-05蓝牙模块与STM32双向通信避坑指南:从数据打包、校验到APP控件交互全流程
  • Vue全屏功能避坑指南:如何解决F11全屏后键盘事件监听失效问题
  • “不战而屈人之兵”——山东齐某涉商业秘密刑事案撤销纪实