PHP eval 代码沙箱中断

信息安全 php 应用安全 代码执行
2021-08-27 00:21:46

我注意到这里有一个被严重低估的评论:http: //php.net/manual/en/function.php-check-syntax.php

function eval_syntax($code)
{
    $braces = 0;
    $inString = 0;

    // We need to know if braces are correctly balanced.
    // This is not trivial due to variable interpolation
    // which occurs in heredoc, backticked and double quoted strings
    foreach (token_get_all('<?php ' . $code) as $token)
    {
        if (is_array($token))
        {
            switch ($token[0])
            {
            case T_CURLY_OPEN:
            case T_DOLLAR_OPEN_CURLY_BRACES:
            case T_START_HEREDOC: ++$inString; break;
            case T_END_HEREDOC:   --$inString; break;
            }
        }
        else if ($inString & 1)
        {
            switch ($token)
            {
            case '`':
            case '"': --$inString; break;
            }
        }
        else
        {
            switch ($token)
            {
            case '`':
            case '"': ++$inString; break;

            case '{': ++$braces; break;
            case '}':
                if ($inString) --$inString;
                else
                {
                    --$braces;
                    if ($braces < 0) return false;
                }

                break;
            }
        }
    }

    // If $braces is not zero, then we are sure that $code is broken.
    // We run it anyway in order to catch the error message and line number.

    // Else, if $braces are correctly balanced, then we can safely put
    // $code in a dead code sandbox to prevent its execution.
    // Note that without this sandbox, a function or class declaration inside
    // $code could throw a "Cannot redeclare" fatal error.

    echo "Braces: ".$braces."\r\n";
    $braces || $code = "if(0){{$code}\n}";

    if (false === eval($code)) {}
}

eval_syntax("file_put_contents('/home/yourname/Desktop/done.txt', 'OVERWRITTEN');");

我试图绕过代码并导致恶意用户输入执行eval,但我做不到。我想知道为什么它被否决了。

如您所见,如果大括号不匹配,它不会添加'if(0){' . $code . '}并按原样执行用户输入,不匹配的大括号将引发异常并且不会真正运行。

如果大括号匹配,它会调用eval,但由于它在if {0}“沙盒”内部,它什么也不做。有人怎么能绕过这个?

我知道 eval 是不安全的,但我想知道这里有什么诀窍。如何绕过上面代码中的 if (0) 和大括号检查的安全性?

我试图添加 // { 所以它会不平衡大括号,它不会添加 if (0) 并调用 eval,但是 token_get_all 破坏了它。

1个回答

我认为您发布的代码中的这条评论总结了我的想法:

// We need to know if braces are correctly balanced. // This is not trivial due to variable interpolation // which occurs in heredoc, backticked and double quoted strings

请记住,不正确地执行代码检查的结果是远程代码执行漏洞。在不平凡的项目工作当然是工程师的规范,但如果你是在完成一项任务,是非常困难的,并一个错误会导致最严重的安全漏洞——嗯,很明显,这是灾难的根源。事实上,值得指出的是,您发布的评论是作者对此的第二次尝试。他的第一次尝试至少包含一个错误(大概)容易受到“沙盒逃逸”的影响,并要求他重新开始。我当然不会将我的应用程序的安全性信任写在网络上某个随机页面上的评论框中的一次性脚本。特别是因为(除非我遗漏了什么)这个评论恰好出现在描述一种内置语言的页面上,它做同样的事情。在互联网上一些随机的人之前,我会相信内置的语言。

不管是否有人发现了漏洞利用,它都不会改变这样一个事实,即这通常是一个坏主意。如果还有其他作者没有想到的转义选项怎么办?例如,许多漏洞利用都依赖于对不同编码的混淆。攻击者可能会使用与文件中不同的编码注入大括号,但 PHP 仍然支持,因此不会在他的检查中注册为大括号,但会被 PHP 识别为大括号,从而允许攻击者突破支撑平衡检查。当然,这种特定的攻击途径实际上可能并不有可能,但我主要是想强调一般观点。在这种情况下,可能会有许多难以捕捉的“陷阱”,而在此代码中缺少其中一个的结果就是远程代码执行漏洞。

当面对“让它完美或极度脆弱”时,我的第一选择是“不要这样做”。紧随其后的是强烈的“不要相信互联网上的随机评论”,特别是如果有一种易于访问的内置语言可以做完全相同的事情但(大概)安全。

编辑以添加. 值得对此发表评论eval你说“我知道 eval 是不安全的,但是”......这并不完全正确。 eval由于以下几个原因,通常不赞成使用:

  1. 如果没有别的,它往往表现不佳
  2. 如果使用不当,它肯定会造成真正的安全问题
  3. 它通常违反最佳编程实践

然而,就像任何工具一样,它也有它的时间和地点。所以要明确的是,这个问题并不是eval不安全的。问题是这里是否eval安全(和正确)使用。由于上述所有原因,我认为它在这里没有被正确使用,但这与笼统的“eval 不安全”声明不同。