【问题标题】:Can someone explain the /e regex modifier? [duplicate]有人可以解释 /e 正则表达式修饰符吗? [复制]
【发布时间】:2013-06-07 14:17:13
【问题描述】:

我目前正在提高对 HTML、PHP、JavaScript 等安全漏洞的了解。 几个小时前,我偶然发现了正则表达式中的/e 修饰符,但我仍然不明白它是如何工作的。我查看了文档,但这并没有真正帮助。

我的理解是,可以操纵这个修饰符,让某人有机会在其中执行 PHP 代码(例如,preg_replace())。我已经看到以下描述安全漏洞的示例,但没有解释,所以有人可以解释一下如何在以下代码中调用 phpinfo() 吗?

$input = htmlentities("");
if (strpos($input, 'bla'))
{
   echo preg_replace("/" .$input ."/", $input ."<img src='".$input.".png'>", "bla");
}

【问题讨论】:

标签: php regex


【解决方案1】:

PHP 中的e 正则表达式修饰符以及示例漏洞和替代方法

e 做了什么,举个例子……

e 修饰符是一个已弃用的正则表达式修饰符,它允许您在正则表达式中使用 PHP 代码。这意味着您解析的任何内容都将作为程序的一部分进行评估。

例如,我们可以这样使用:

$input = "Bet you want a BMW.";
echo preg_replace("/([a-z]*)/e", "strtoupper('\\1')", $input);

这将输出BET YOU WANT A BMW.

如果没有 e 修饰符,我们会得到这个非常不同的输出:

strtoupper('')Bstrtoupper('et')strtoupper('') strtoupper('you')strtoupper('') strtoupper('want')strtoupper('') strtoupper('a')strtoupper('') strtoupper('')Bstrtoupper('')Mstrtoupper('')Wstrtoupper('').strtoupper('')

e 的潜在安全问题...

e 修饰符是 deprecated for security reasons。这是一个使用e 很容易遇到的问题示例:

$password = 'secret';
...
$input = $_GET['input'];
echo preg_replace('|^(.*)$|e', '"\1"', $input);

如果我将输入提交为"$password",则此函数的输出将为secret。因此,对我来说访问会话变量非常容易,所有变量都在后端使用,甚至可以通过这段写得不好的简单代码对您的应用程序进行更深层次的控制 (eval('cat /etc/passwd');?)。

与同样被弃用的mysql 库一样,这并不意味着您不能使用e 编写不受漏洞影响的代码,只是这样做更难。

你应该改用什么...

您应该在几乎所有您会考虑使用e 修饰符的地方使用preg_replace_callback。在这种情况下,代码绝对没有那么简短,但不要被它欺骗了——它的速度是原来的两倍:

$input = "Bet you want a BMW.";
echo preg_replace_callback(
    "/([a-z]*)/",
    function($matches){
        foreach($matches as $match){
            return strtoupper($match);
        }
    }, 
    $input
);

在性能方面,没有理由使用e...

mysql 库(出于安全目的也已弃用)不同,e 在大多数操作中并不比它的替代品快。对于给出的示例,它的速度要慢两倍:preg_replace_callback(50,000 次操作为 0.14 秒)vs e modifier(50,000 次操作为 0.32 秒)

【讨论】:

  • 您的示例不包括也不需要e 修饰符。
  • 已修复,不知道为什么我偏离了那条切线。
  • +1,提供了一个很好的清晰示例。这也说明了为什么它对性能如此不利——在一行代码中调用了 14 个eval()。哎哟。 eval() 已经足够慢了。
  • @Spudley:preg_replace_callback(50,000 次操作为 0.14 秒)与 e modifier(50,000 次操作为 0.32 秒)的性能比较
【解决方案2】:

e 修饰符是 PHP 特定的修饰符,它触发 PHP 将生成的字符串作为 PHP 代码运行。它基本上是一个包裹在正则表达式引擎中的eval()

eval() 本身被视为安全风险和性能问题;将其包装在正则表达式中会显着放大这两个问题。

因此,这种做法被认为是不好的做法,并在即将发布的 PHP v5.5 中正式弃用。

PHP 已经提供了几个版本,现在以preg_replace_callback() 的形式提供了一种替代解决方案,它使用回调函数而不是使用eval()。这是做这种事情的推荐方法。

特别注意您引用的代码:

我在您在问题中提供的示例代码中没有看到 e 修饰符。它在每一端都有一个斜杠作为正则表达式分隔符; e 必须不在此范围内,但事实并非如此。因此,我认为您引用的代码可能不会直接受到注入 e 修饰符的影响。

但是,如果$input 包含任何/ 字符,它将很容易被完全破坏(即由于无效的正则表达式而引发错误)。如果它有其他任何使它成为无效正则表达式的东西,这同样适用。

因此,将未经验证的用户输入字符串用作正则表达式模式的一部分是一个坏主意 - 即使您确定使用 e 修饰符不会被破解,还有很多其他的可以用它来实现的恶作剧。

【讨论】:

  • “我在你给出的示例代码中没有看到 e 修饰符。” 是的,应该使用 $input 变量注入 e 修饰符。那是我卡住的地方。如何操纵此输入以注入 e 修饰符。
  • @Yami - 是的,看起来我是唯一一个真正试图解决你问题的那部分的人 :-) 正如我所说,我真的看不到获得e 修饰符,因为修饰符必须在分隔符之外,并且您已经将分隔符固定到位。如果您没有对分隔符进行硬编码并且期望$input 包含它们,那么是的,这将很容易被利用。正如我所说,即使指定了分隔符,黑客仍然很容易在这里造成错误,但我认为他无法使用e 修饰符。
【解决方案3】:

如手册中所述,/e 修饰符实际上评估正则表达式作用于的文本作为 PHP 代码。手册中给出的例子是:

$html = preg_replace(
    '(<h([1-6])>(.*?)</h\1>)e',
    '"<h$1>" . strtoupper("$2") . "</h$1>"',
    $html
);

这匹配任何“&lt;hX&gt;XXXXX&lt;/hX&gt;”文本(即标题 HTML 标记),将此文本替换为 "&lt;hX&gt;" . strtoupper("XXXXXX") . "&lt;hX&gt;",然后 执行 "&lt;hX&gt;" . strtoupper("XXXXXX") . "&lt;hX&gt;" 作为 PHP 代码,然后将结果放回字符串。

如果您在任意用户输入上运行此程序,任何用户都有机会滑入实际上将被评估为 PHP 代码的内容。如果他做得正确,用户可以利用这个机会执行他想要的任何代码。在上面的例子中,想象如果在第二步中文本是"&lt;hX&gt;" . strtoupper("" . shell('rm -rf /') . "") . "&lt;hX&gt;"

【讨论】:

    【解决方案4】:

    这是邪恶的,这就是你需要知道的一切:p

    更具体地说,它正常生成替换字符串,然后通过eval 运行它。

    您应该改用preg_replace_callback

    【讨论】:

      猜你喜欢
      • 2014-12-10
      • 1970-01-01
      • 1970-01-01
      • 2015-11-16
      • 1970-01-01
      • 2013-09-18
      • 2015-11-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多