有人可以解释/ e正则表达式修饰符吗?

时间:2013-06-07 14:17:14

标签: php regex

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

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

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

4 个答案:

答案 0 :(得分:45)

PHP中的e正则表达式修饰符,带有示例漏洞&amp;替代

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",则此功能的输出将为secretdemo)。因此,对我来说很容易访问会话变量,后端使用的所有变量甚至通过这个编写得很糟糕的代码对你的应用程序(eval('cat /etc/passwd');?)进行更深层次的控制。< / p>

与类似已弃用的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秒)与e modifier(对于50,000次操作为0.32秒)

答案 1 :(得分:4)

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

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

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

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

具体考虑您引用的代码:

我在问题中给出的示例代码中没有看到e修饰符。它的每一端都有一个斜线作为正则表达式分隔符; e必须在那之外,而事实并非如此。因此,我不认为您引用的代码可能直接容易被注入e修饰符。

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

因此,使用未经验证的用户输入字符串作为正则表达式模式的一部分是一个坏主意 - 即使您确定它不能被黑客攻击以使用e修饰符,也有很多可以通过它实现的其他恶作剧。

答案 2 :(得分:1)

这是邪恶的,这就是你需要知道的全部:p

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

您应该使用preg_replace_callback代替。

答案 3 :(得分:1)

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

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

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

如果您在任意用户输入上运行此操作,任何用户都有机会将某些内容放在实际上将被评估为PHP代码的内容中。如果他正确地做到了,用户可以利用这个机会执行他想要的任何代码。在上面的示例中,假设在第二步中文本将是"<hX>" . strtoupper("" . shell('rm -rf /') . "") . "<hX>"