[红日安全]代码审计Day8 - preg_replace函数之命令执行
字数 1100 2025-08-18 11:37:33

preg_replace函数/e模式导致的代码执行漏洞分析与防御

1. preg_replace函数基础

preg_replace是PHP中执行正则表达式搜索和替换的函数,定义如下:

mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )

功能:搜索subject中匹配pattern的部分,如果匹配成功则以replacement进行替换。

2. /e模式修正符的危险性

preg_replace$pattern参数中存在/e模式修正符时,会导致安全漏洞:

  • /e模式使preg_replace$replacement当作PHP代码执行
  • 这是PHP 5.5及之前版本的一个特性,在后续版本中已被移除

3. 漏洞原理分析

3.1 基础示例

$regex = '/\S*/e';
$value = '${phpinfo()}';
preg_replace($regex, 'strtolower("\\1")', $value);

漏洞触发条件:

  1. 使用了/e模式修正符
  2. 攻击者能控制$pattern$subject参数
  3. 正则匹配成功

3.2 反向引用机制

  • 正则表达式中使用圆括号()捕获的子匹配会存储在临时缓冲区
  • 缓冲区编号从1开始,最多99个
  • 使用\n访问缓冲区内容(如\1表示第一个捕获组)

4. 实际案例分析(CmsEasy 5.5)

4.1 漏洞位置

/lib/tool/form.php文件中:

$form[$name]['default'] = preg_replace('/{([^\}]+)}/e', "eval('return \\1;')", $form[$name]['default']);

4.2 漏洞触发路径

  1. 用户通过GET/POST请求控制catid参数
  2. catid值传递到get_form()函数
  3. 最终进入存在漏洞的preg_replace调用

4.3 完整利用流程

  1. 访问游客投稿页面
  2. 构造payload:catid={?(phpinfo())}
  3. 触发代码执行

5. 漏洞防御方案

5.1 根本解决方案

  • 避免使用/e模式修正符
  • 升级到PHP 5.5以上版本(已移除该特性)

5.2 替代方案

使用preg_replace_callback函数替代:

// 不安全的方式
// preg_replace('/{([^\}]+)}/e', "eval('return \\1;')", $input);

// 安全的方式
preg_replace_callback('/{([^\}]+)}/', function($matches) {
    return eval('return '.$matches[1].';');
}, $input);

5.3 输入过滤

  • 对用户输入进行严格过滤
  • 使用白名单机制限制允许的字符

6. CTF题目分析

6.1 题目1 (index.php)

<?php
include 'flag.php';
if(isset($_GET['code'])){
    $code=$_GET['code'];
    if(strlen($code)>40){
        die("Long.");
    }
    if(preg_match("/[A-Za-z0-9]+/",$code)){
        die("NO.");
    }
    @eval($code);
}

解题思路:

  • 长度限制40字符
  • 不能包含字母数字
  • 需要使用非字母数字方式构造PHP代码

6.2 题目2 (index2.php)

<?php
include 'flag.php';
if(isset($_GET['code'])){
    $code=$_GET['code'];
    if(strlen($code)>50){
        die("Too Long.");
    }
    if(preg_match("/[A-Za-z0-9_]+/",$code)){
        die("Not Allowed.");
    }
    @eval($code);
}

解题思路:

  • 长度限制50字符
  • 不能包含字母数字和下划线
  • 需要使用更严格的字符限制构造PHP代码

7. 总结

preg_replace/e模式修正符是一个危险的特性,会导致远程代码执行漏洞。开发者应当:

  1. 避免使用/e模式
  2. 升级到最新PHP版本
  3. 使用preg_replace_callback替代
  4. 对所有用户输入进行严格过滤
  5. 遵循最小权限原则

通过理解漏洞原理和实际案例,开发者可以更好地防范此类安全问题。

preg_ replace函数/e模式导致的代码执行漏洞分析与防御 1. preg_ replace函数基础 preg_replace 是PHP中执行正则表达式搜索和替换的函数,定义如下: 功能:搜索 subject 中匹配 pattern 的部分,如果匹配成功则以 replacement 进行替换。 2. /e模式修正符的危险性 当 preg_replace 的 $pattern 参数中存在 /e 模式修正符时,会导致安全漏洞: /e 模式使 preg_replace 将 $replacement 当作PHP代码执行 这是PHP 5.5及之前版本的一个特性,在后续版本中已被移除 3. 漏洞原理分析 3.1 基础示例 漏洞触发条件: 使用了 /e 模式修正符 攻击者能控制 $pattern 或 $subject 参数 正则匹配成功 3.2 反向引用机制 正则表达式中使用圆括号 () 捕获的子匹配会存储在临时缓冲区 缓冲区编号从1开始,最多99个 使用 \n 访问缓冲区内容(如 \1 表示第一个捕获组) 4. 实际案例分析(CmsEasy 5.5) 4.1 漏洞位置 /lib/tool/form.php 文件中: 4.2 漏洞触发路径 用户通过GET/POST请求控制 catid 参数 catid 值传递到 get_form() 函数 最终进入存在漏洞的 preg_replace 调用 4.3 完整利用流程 访问游客投稿页面 构造payload: catid={?(phpinfo())} 触发代码执行 5. 漏洞防御方案 5.1 根本解决方案 避免使用 /e 模式修正符 升级到PHP 5.5以上版本(已移除该特性) 5.2 替代方案 使用 preg_replace_callback 函数替代: 5.3 输入过滤 对用户输入进行严格过滤 使用白名单机制限制允许的字符 6. CTF题目分析 6.1 题目1 (index.php) 解题思路: 长度限制40字符 不能包含字母数字 需要使用非字母数字方式构造PHP代码 6.2 题目2 (index2.php) 解题思路: 长度限制50字符 不能包含字母数字和下划线 需要使用更严格的字符限制构造PHP代码 7. 总结 preg_replace 的 /e 模式修正符是一个危险的特性,会导致远程代码执行漏洞。开发者应当: 避免使用 /e 模式 升级到最新PHP版本 使用 preg_replace_callback 替代 对所有用户输入进行严格过滤 遵循最小权限原则 通过理解漏洞原理和实际案例,开发者可以更好地防范此类安全问题。