【问题标题】:preg_match kills pagepreg_match 杀死页​​面
【发布时间】:2012-05-17 16:50:40
【问题描述】:

我正在使用 preg_match 在文件中查找和删除经过评估的 base64 编码病毒。

下面的正则表达式:

/\s*eval\s*\(\s*base64_decode\s*\(\s*('[a-zA-Z0-9\+\/]*={0,2}'|"[a-zA-Z0-9\+\/]*={0,2}")\s*\)\s*\s*\)\s*(;)?\s*/

匹配以下代码:

eval(base64_decode("BASE64+ENCODED+VIRUS+HERE")); 

上面的正则表达式工作正常。

我想通过连接匹配自动换行的 base64 字符串。所以它也应该匹配以下内容 "BASE64+EN" 。 “编码+病毒+这里”。

所以我把正则表达式改成:

/\s*eval\s*\(\s*base64_decode\s*\(\s*\'([a-zA-Z0-9\+\/]*(\'\s*\.\s*\')?[a-zA-Z0-9\+\/]*)*={0,2}\'|"([a-zA-Z0-9\+\/]*("\s*\.\s*")?[a-zA-Z0-9\+\/]*)*={0,2}"\s*\)\s*\s*\)\s*(;)?\s*/

找到部分匹配项:

"BASE64+ENCODED+VIRUS+HERE"));

但是当我尝试在整个文件上应用匹配时:http://pastebin.com/ED8sFUP0 页面因浏览器消息“加载页面时与服务器的连接已重置”而死机。

我已激活错误报告:

error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('scream.enabled', TRUE);

但这里没有显示任何内容,也没有显示在 apache 的错误日志中。

在不包含违规字符串的文件上使用相同的正则表达式可以按预期工作; preg_match 不返回布尔值 false 它返回 0 表示没有正则表达式错误并且它没有找到任何匹配项。

我担心的不一定是为什么正则表达式只能找到部分匹配。这可能是我写的一些错字,碰巧有效。

我想知道正则表达式编译器何时以及如何失败破坏整个进程链

apache > php > regex_compiler

我知道这很可能是“因为”我的正则表达式恰好编译正确但不正确匹配。它可能会导致一些不好的事情发生。但我的兴趣是为什么 regex 编译器失败且没有错误,以及我如何获得应该产生的错误消息。

此处讨论了类似但未解决的问题:php preg_match_all kills page for unknown reason

【问题讨论】:

标签: php regex preg-match pcre


【解决方案1】:

编辑:

 \s*
 eval \s*
 \( \s*
    base64_decode \s* 
    \( \s* 
        (?:
            (?>
               '
                 [a-zA-Z0-9+/]*
                 (?:
                    '
                      \s* \. \s*
                    '
                    [a-zA-Z0-9+/]*
                 )*
                 ={0,2}
               '
            )
          |
            (?>
               "
                 [a-zA-Z0-9+/]*
                 (?:
                    "
                      \s* \. \s*
                    "
                    [a-zA-Z0-9+/]*
                 )*
                 ={0,2}
               "
            )
        )
        \s*

    \)\s*

 \)\s* ;? \s*

如何处理 "".'' 连接

您没有尝试解析语言(您不能这样做),所以您可以
使用这个非常快速的正则表达式处理连接条件"".''...

~
 \s*
 eval \s*
 \( \s*
    base64_decode
    \s* 
    \(
       \s* 
        ["']
        (?> [a-zA-Z0-9+/]* (?: ["']\s*\.\s*["'] [a-zA-Z0-9+/]* )* )
        ={0,2}
        ["']
       \s*
    \)
    \s*
 \)
 \s* ;? \s*

~x

【讨论】:

  • 这会很有趣,@stema 修复了整体性能差距,您可能修复了准确性。我还没有测试你的解决方案。我的代码基于 eval+base64+gzinflate/gzuncompress/bzdecompress+str_rot13 的多种组合生成正则表达式,它还考虑了隐藏在 ascii-hexcodes/unicode-hexcodes 下的字符串。这一切都使得整合您的解决方案变得困难。因此,我会在早上做。
  • 由于您的代码保留了性能问题,而我的问题是“为什么我的正则表达式崩溃”,我想我会接受 @stema 对“灾难性回溯”的回答。
  • @Mihai Stancu - 没问题,很高兴你能成功。我原以为从([a-zA-Z0-9\+\/]*(\'\s*\.\s*\')?[a-zA-Z0-9\+\/]*)*[a-zA-Z0-9+/]*(?:'\s*\.\s*'[a-zA-Z0-9+/]*)* 不会导致太多的回溯失败。我将您的文件加载到 2.4 兆字节,在结尾处插入了一个“=”符号(但无效)。失败花了 1/2 秒,你的只是挂了。所以我添加了原子分组,现在需要 1/4 秒才能失败。代码在我的编辑中。我还发布了您的正则表达式扩展和一个问题。 - 祝你好运!
  • 另外一件事,如何阻止串联使用两种形式 "".''
  • 我们有两种不同形式的引用(和引用拆分)base64 代码。这个 "([a-zA-Z0-9\+\/]*("\s*\.\s*")?[a-zA-Z0-9\+\/]*)* ={0,2}" 用于可以用双引号分割的双引号 base64 代码。还有一个是单引号,可以用单引号分割。
【解决方案2】:

我认为您的正则表达式有很多匹配的可能性 ==> Catastrophic Backtracking

/\s*eval\s*\(\s*base64_decode\s*\(\s*\'([a-zA-Z0-9\+\/]*(\'\s*\.\s*\')?[a-zA-Z0-9\+\/]*)*={0,2}\'|"([a-zA-Z0-9\+\/]*("\s*\.\s*")?[a-zA-Z0-9\+\/]*)*={0,2}"\s*\)\s*\s*\)\s*(;)?\s*/
                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

正则表达式需要很多步骤来匹配我标记的部分==>你有性能问题,正则表达式没有及时完成!

由于(\'\s*\.\s*\')? 是可选的,您需要执行很多步骤,直到正则表达式找出与[a-zA-Z0-9\+\/]* 之前匹配的内容以及可选部分之后的相同内容。

您可以做的是使用possessive quantifiers(您可以通过在其后添加+ 来使量词具有所有格)。它们防止回溯,并且所有格量词不会返回匹配的字符。所以,试试这个

/\s*eval\s*\(\s*base64_decode\s*\(\s*\'([a-zA-Z0-9\+\/]*+(\'\s*\.\s*\')?[a-zA-Z0-9\+\/]*+)*={0,2}\'|"([a-zA-Z0-9\+\/]*+("\s*\.\s*")?[a-zA-Z0-9\+\/]*+)*={0,2}"\s*\)\s*\s*\)\s*(;)?\s*/
                                                       ^^                               ^^                           ^^                            ^^

【讨论】:

  • 很棒的伙伴,它确实解决了性能问题。我猜这与我喂它的 260k 的 base64 编码病毒文件有关。我只是没有在“时间”域中考虑,而是在内存域中想到了它。
  • 我曾想过使用 [a-zA-z]*?进行惰性匹配(作为性能增强),但在我测试它并没有看到任何变化之后,我忘记了回溯需要时间!
猜你喜欢
  • 2015-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多