PHP eval code sandbox break

11

Noté un comentario muy desviado aquí: enlace

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');");

Intenté omitir el código y conducir a una ejecución de entrada de usuario malintencionada con eval , pero no pude. Me pregunto por qué se bajó de votación.

Como puede ver si los corchetes no coinciden, no agrega el 'if(0){' . $code . '} y ejecuta la entrada del usuario tal cual con corchetes que no coinciden, lo que generará una excepción y no se ejecutará realmente.

Si los corchetes son una coincidencia, llama a eval , pero debido a que está dentro de if {0} "sandbox", no hace nada. ¿Cómo puede alguien pasar por alto esto?

Sé que eval es inseguro, pero quiero saber cuál es el truco aquí. ¿Cómo puede pasar por alto la seguridad de if (0) y las llaves verifique el código anterior?

Intenté agregar // {para que desequilibre las llaves y no agregue if (0) y llame a eval, pero token_get_all lo arruina.

    
pregunta JohnDoes 24.01.2018 - 02:28
fuente

1 respuesta

1

Creo que este comentario del código que has publicado resume mis pensamientos:

// 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

Tenga en cuenta que el resultado de ejecutar incorrectamente la verificación del código es una vulnerabilidad de ejecución remota de código. Por supuesto, trabajar con elementos no triviales es la norma para los ingenieros, pero si está trabajando en una tarea que es extremadamente difícil y , un error conduce al tipo más grave de vulnerabilidad de seguridad: bueno, claramente eso Es una receta para el desastre. De hecho, vale la pena señalar que el comentario que publicaste fue el segundo intento de los autores. Su primer intento de contener al menos un error que (presumiblemente) era vulnerable a "escapar de la caja de arena" y le obligó a comenzar de nuevo. Ciertamente no voy a confiar la seguridad de mi aplicación a un script único escrito en un cuadro de comentarios en alguna página aleatoria de la web. Especialmente porque (a menos que me esté perdiendo algo), este comentario está en una página que describe un lenguaje incorporado que hace exactamente lo mismo. Confiaría en el lenguaje incorporado antes de que alguien aleatorio en internet.

Independientemente de si alguien ha encontrado o no un exploit todavía, no cambia el hecho de que esto es generalmente una mala idea en primer lugar. ¿Qué pasa si hay otras opciones de escape que el autor no ha pensado? Por ejemplo, un montón de explotaciones por ahí se han basado en la confusión sobre diferentes codificaciones. Podría ser posible que un atacante inyecte una llave utilizando una codificación diferente a la del archivo, pero aún con el soporte de PHP, que por lo tanto no se registrará como una llave en sus cheques, pero será reconocido como tal por PHP, permitiendo Un atacante para romper el chequeo de equilibrio. Por supuesto, esa avenida de ataque en particular puede no ser en realidad posible, pero principalmente estoy tratando de enfatizar el punto general. Puede haber muchos "errores" difíciles de atrapar en situaciones como esta, y el resultado de perder uno de ellos en este código es una vulnerabilidad de ejecución remota de código.

Cuando me enfrento a "Hazlo perfecto o eres extremadamente vulnerable" mi primera preferencia es "Simplemente no lo hagas". A esto le sigue un fuerte "no confíe en un comentario aleatorio en Internet", especialmente si hay un lenguaje incorporado de fácil acceso que hace exactamente lo mismo pero (probablemente) de forma segura.

Editar para agregar . Vale la pena hacer un comentario sobre eval . Usted dijo: "Sé que eval es inseguro, pero" ... Esto no es estrictamente cierto. El uso de eval generalmente está mal visto por varias razones:

  1. Si nada más tiende a tener un bajo rendimiento
  2. Si se usa incorrectamente, ciertamente puede crear problemas de seguridad reales
  3. En general, viola las mejores prácticas de programación

Sin embargo, como cualquier herramienta, puede tener su tiempo y lugar. Entonces, para ser claros, el problema no es que eval sea inseguro. La pregunta es si o no eval se está utilizando de forma segura (y correctamente) aquí. Por todas las razones descritas anteriormente, no creo que se esté utilizando correctamente aquí, pero eso es diferente a una afirmación general de "la evaluación es insegura".

    
respondido por el Conor Mancone 11.10.2018 - 14:29
fuente

Lea otras preguntas en las etiquetas