XUT_ / COURSES / PENETRATION TESTER

Second-Order SQL Injection

La second-order SQLi, también conocida como SQLi stored, explota vulnerabilidades donde el input dado por el usuario es guardado y después usado en una parte diferente de la aplicación, posiblemente tras un procesado inicial. Este tipo de ataque pasa más desapercibido porque el código malicioso SQL no aparece en errores u otros sitios obvios. La inyección ocurre en el segundo uso de los datos, cuando es recuperada y usada en un comando SQL, de ahí el nombre.

Second-Order SQL Injection


Impacto

El peligro de este tipo de inyección recae en su habilidad de bypassear defensas típicas del front end como validación o sanitización básica, la cual sólo ocurre en el punto inicial de introducción de información. Como no causa errores durante el primer paso, puede ser sebreseído hasta que ya es demasiado tarde, haciéndolo particularmente sigiloso.

Ejemplo

Usaremos una aplicación de reseñas de libros. La aplicación permite a los usuarios añadir nuevos libros vía una página web (add.php). A los usuarios se les piden los detalles sobre el libro que desean añadir a la base de datos. La información recolectada incluye SSN, book_name y author. Consideremos añadir un libro con los siguientes detalles: {SSN:UI00012, book_name:Intro to PHP, author:Tim}. Esta información se rellena mediante un formulario en la página add.php.

Second-Order SQL Injection

Como ya sabemos, la inyección SQL de segundo orden, es notablemente más difícil de identificar. Al contrario que la inyección SQL tradicional, la cual explota en tiempo real las vulnerabilidades, esta ocurre cuando información previamente guardada en la base de datos es usada más adelante en una query SQL.

Análisis del Código

Considera el código PHP usado en nuestra aplicación para añadir libros:

php
if (isset($_POST['submit'])) {

    $ssn = $conn->real_escape_string($_POST['ssn']);

    $book_name = $conn->real_escape_string($_POST['book_name']);

    $author = $conn->real_escape_string($_POST['author']);

    $sql = "INSERT INTO books (ssn, book_name, author) VALUES ('$ssn', '$book_name', '$author')";

    if ($conn->query($sql) === TRUE) {

        echo "<p class='text-green-500'>New book added successfully</p>";

    } else {

        echo "<p class='text-red-500'>Error: " . $conn->error . "</p>";

    }

}

El código usa el método real_escape_string() para escapar caracteres especiales en el input. Aunque este método puede mitigar algunos riesgos de la inyección SQL inmediata, no securiza la aplicación frente a second-order SQLi. El problema clave es la falta de queries parametrizadas lo que es esencial para prevenir ataques de SQLi. Cuando se inserta la información usando este método se pueden incluires caracteres que no causan daño inmediato, pero que de ser metidos en una query secuencial pueden resultar en inyección de segundo orden como Intro to PHP'; DROP TABLE books;--.

Probemos a añadir un libro con el SSN test'.

Second-Order SQL Injection

El SSN test' fue insertado exitosamente en la base de datos. La aplicación incluye una funcionalidad para actualizar detalles de un libro a través de una interfaz como update.php. Esta interfaz puede mostrar detalles de libros existentes en campos de formulario. El pentester investigará si la aplicación reutiliza información como book_name. Entonces contruiríamos las queries SQL para actualizar registros usando la información manipulada sin sanitización. Manipulando la funcionalidad de actualización, el tester puede ver si el payload malicioso añadido se ejecuta durante la operación de actualización. Si la aplicación no consigue filtrar estos caracteres o emplear buenas prácticas de seguridad, el payload '; DROP TABLE books; -- podría activarse llevando a la ejecución de un comando SQL malicioso.

Second-Order SQL Injection

Revisemos ahora el código de update.php. Este script permite a los usuarios actualizar detalles de libros en la base de datos de BookStore. A través de la estructura query, analizaremos un escenario típico donde un pentester pueda buscar vulnerabilidades SQLi, especialmente centrándonos en cómo el input se maneja y utiliza en queries SQL.

php
if ( isset($_POST['update'])) {
    $unique_id = $_POST['update'];
    $ssn = $_POST['ssn_' . $unique_id];
    $new_book_name = $_POST['new_book_name_' . $unique_id];
    $new_author = $_POST['new_author_' . $unique_id];

    $update_sql = "UPDATE books SET book_name = '$new_book_name', author = '$new_author' WHERE ssn = '$ssn'; INSERT INTO logs (page) VALUES ('update.php');";
..
...

El script comienza comprobando si el método de petición es POST y si el botón "Update" ha sido presionado, indicando que el usuario pretende actualizar los detalles del libro. Siguiendo esto, el script recupera el input del usuario directamente de la información POST.

php
$unique_id = $_POST['update'];
$ssn = $_POST['ssn_' . $unique_id];
$new_book_name = $_POST['new_book_name_' . $unique_id];
$new_author = $_POST['new_author_' . $unique_id];

Estas variables son usadas para construir más tarde una query SQL para actualizar los detalles del libro especificado en la base de datos:

php
$update_sql = "UPDATE books SET book_name = '$new_book_name', author = '$new_author' WHERE ssn = '$ssn'; INSERT INTO logs (page) VALUES ('update.php');";

El script usa multi_query para ejecutar múltiples queries.


Preparando el Payload

Sabemos que podemos añadir o modificar los detalles del libro basado en su ssn. La query normal para actualizar un libro podría verse así:

sql
UPDATE books SET book_name = '$new_book_name', author = '$new_author' WHERE ssn = '123123';

Sin embargo, el comando SQL podría ser manipulado si un atacante inserta un valor ssn construído por él. Por ejemplo, si el atacante usa el valor ssn:

sql
12345'; UPDATE books SET book_name = 'Hacked'; --

Cuando este valor es usado en la query de actualización, finaliza el comando UPDATE después de 12345 y comienza otro nuevo comando. Esto cambiaría el book_name de todas las entradas de la tabla books a Hacked.

Hagamos lo Siguiente

  1. Inserción inicial de Payload: Un nuevo libro es añadido con el payload 12345'; UPDATE books SET book_name = 'Hacked'; -- se inserta en ssn. El ; se usa para terminar el statement SQL actual.

    Second-Order SQL Injection

  2. Ejecución SQL Maliciosa: Después de eso cuando el admin o cualquier otro usuario visita la URL update.php y lo actualiza, el payload insertado rompe la estructura del comando SQL e inyecta un comando nuevo que actualiza todos los nombres de libros de la tabla books.

sql
UPDATE books SET book_name = 'Testing', author = 'Hacker' WHERE ssn = '12345'; Update books set book_name ="hacked"; --'; INSERT INTO logs (page) VALUES ('update.php');
  1. Comentar el resto: El doble guión --, es un símbolo de comentario de SQL. Cualquier cosa que siga a -- será ignorado por el servidor SQL, neutralizando efectivamente cualquier resto del statement SQL original que pudiera causar errores o revelar el ataque. Una vez se ejecuta el payload de arriba se cambian todos los nombres como se muestra.

    Second-Order SQL Injection