martes, 14 de julio de 2020

SQLi y “Cleans URLs”

Cada vez es más común ver URL menos sofisticadas, entendibles para el usuario, llamadas Search Engine Optimization Friendly URL (SEO-Friendly URL). Si recordamos un tiempo atrás, cuando alguien nos enviaba una URL prácticamente podíamos reconocer el nombre del dominio.

        https://myforo.com/path/doit&post=172356&comment=213

Ahora rara vez encontramos ese tipo de enlace con parámetros en la petición GET, sino que lo encontramos de una forma más entendible y bonita, incluso el propio enlace contiene el título de la página.

        https://mytsite.com/path/172356/213/my-post-title

Este cambio en las URL se debe a los motores de búsqueda y el posicionamiento de las páginas webs, un estudio demostró que cuanto más corta es la URL y más descriptiva del contenido del post es, Google te muestra en mejor posición. En el siguiente gráfico se puede observar esa línea de tendencia que están siguiendo casi todas las páginas webs.



En este artículo se explicará cómo detectar estas “Clean URL”, analizando el comportamiento de la página web frente a cambios de la URL. Para entender su funcionamiento primero deberemos comprender como están formadas.

Creación de “Clean URL”:


La función que se encarga de poner el título en el URL se denomina slug. Aquí un ejemplo de esta función en PHP, pero la podríamos encontrar también en ASP.NET.
<?php
function mySlug($str, $max=30)
{
        $out = iconv('UTF-8', 'ASCII//TRANSLIT', $str);
        $out = substr(preg_replace("/[^-\/+|\w ]/", '', $out), 0, $max);
        $out = strtolower(trim($out, '-'));
        $out = preg_replace("/[\/_| -]+/", '-', $out);
        return $out;
}
function checkSlug($str)
{
        return preg_match ("/^[a-z0-9\-]*$/", $str);
}
$slug =  mySlug("Descripción de mi post en español normal, pero que se codificará de forma SEO-Friendly para ser un texto amigable");
?>
Hasta ahora se ha explicado cómo se construye el texto amigable correspondiente al título del post, pero… ¿Cómo hacen para no utilizar ningún parámetro de tipo GET?

Apache tiene un módulo denominado mod_rewrite que permite crear reglas para modificar las URL introducidas por el usuario. Es decir, con la construcción de estas reglas y a partir del uso de Regex se conseguirá acortar la URL.

Veamos el ejemplo de Apache, una vez activado el módulo:
               
                    $ a2enmod rewrite

Añadiendo las siguientes reglas diseñadas para nuestro laboratorio en el .htaccess de la raíz del servidor apache (“/var/www/html/.htacess”), conseguiremos eliminar la extensión php y “traducir” los parámetros introducidos en la URL separados por “/” a parámetros de tipo GET.
RewriteRule ^(home|myforo)$ $1.php [NC,L]
RewriteRule ^(home|myforo)/$ $1.php [NC,L]
RewriteRule ^myforo/(.*)/(.*)/(.*)$  myforo.php?id=$1&comment=$2&title=$3 [NC,L]
RewriteRule ^myforo/(.*)/(.*)$  myforo.php?id=$1&comment=$2&title=notthistitle [NC,L]
Con lo que se conseguirá una transformación bastante evidente:

            http://localhost/myforo.php?id=1&comment=1&title=my-first-post
                http://localhost/myforo/1/1/my-first-post


Aun así, no será trivial diferenciar la URL de una URL convencional, es decir ficheros divididos en directorios como es el caso de “my-first-post” que se halla en el directorio “/var/www/html/myforo/1/1” o si se trata de una Clean URL.



Con lo que nos encontramos frente a la dificultad de determinar si es una Clean URL y en el caso que lo fuera, que partes de la URL forman el path, que partes forman los parámetros GET, que irán destinados a querys SQL y donde deberemos realizar inyecciones SQL, y que partes forman el “slug”, es decir el texto descriptivo del post.

Diferenciación de componentes de una “Clean URL” frente al comportamiento de la respuesta:

1. Slug – Descripción del post: Es la componente más evidente ya que sigue el formato SEO, es decir, palabras descriptivas separadas por guiones.

En el caso que no se obtenga de una forma evidente, suele ser el último componente de la URL. Si es eliminado o modificado se obtendrá una respuesta de redirección (302) a la URL introducida con su slug correspondiente.


Es un parámetro que no afecta, existe meramente para ayudar al usuario a comprender la temática del post y a los motores de búsqueda.

2. Parámetros GET: Los parámetros de tipo GET son los que irán asociadas a las querys a las bases de datos. Este es el parámetro que se deberá testear frente a inyecciones SQL.

Se podrá diferenciar de varias formas, si se modifica el parámetro GET por otro parámetro válido, se observará como obtenemos una redirección (302) al slug correcto.


En cambio, si introducimos un parámetro inexistente, en el caso que el error esté controlado, se recibirá un Not Found (404). Si la página web no tiene los errores bien controlados podríamos conseguir incluso un Internal Server Error (500).


3. Path: Esta última componente corresponde al nombre del fichero del servidor, normalmente se ha eliminado cualquier rastro de extensión, por lo que puede pasar por desapercibido.

En cualquier caso, si se eliminan todos los parámetros incluyendo el slug y se deja únicamente el path, se debería recibir una respuesta correcta (200).


En el momento que introducimos un path erroneo o inexistente, se recibirá un Not Found (404).


En el caso que modificando cualquier parámetro (inclyendo el slug) siempre encontremos un Not Found (404), no estaremos tratando sobre una “Clean URL”.

Explotación de SQLi en “Clean URL”:


Al tratarse de una modificación previa en servidor, es decir, lo que conforma, crea, modifica y parsea la “Clean URL” es un agente que se ubica entre el cliente o el motor de búsqueda y el servidor y al no haber ningún tipo de modificación a la hora de hacer la query ya que simplemente es un mero “traductor” entre el usuario y el servidor, se explotará de la misma forma que una URL tradicional.


Primero se intentará crear el error interno para confirmar, si de verdad en el backend hay una base de datos.


Una vez teniendo la query SQL solo habrá que crear el payload correcto para explotar la vulnerabilidad.
SELECT * FROM myforo WHERE id=2 AND comment=1
Payload: %20OR%201=1—
SELECT * FROM myforo WHERE id=2 OR 1=1— AND comment=1




Finalmente se podría explotar con una herramienta automática como sqlmap indicando con “*” el parámetro que se desea inyectar.


Mitigación:


La mitigación siempre es la misma, sanizar siempre la entrada del usuario, en este caso la entrada del usuario es vía la URL por lo que se deberá sanizar en el servidor.

A la hora de establecer las reglas en el mod_rewrite se puede utilizar una regex más restrictiva, es decir, que solo admita letras y números.
RewriteRule ^myforo/([a-zA-Z0-9-/+]+)/([a-zA-Z0-9-/+]+)$  myforo.php?id=$1&comment=$2&title=notthistitle [NC,L]

Referencias:


https://support.google.com/webmasters/answer/7451184?hl=en
https://backlinko.com/hub/seo/urls
https://www.mundotelematico.com/inyeccion-blind-sql-basada-en-sqlite/
https://www.exploit-db.com/docs/english/41397-injecting-sqlite-database-based-applications.pdf
https://httpd.apache.org/docs/current/mod/mod_rewrite.html#:~:text=The%20mod_rewrite%20module%20uses%20a,invoke%20an%20internal%20proxy%20fetch.
https://security.stackexchange.com/questions/5869/testing-clean-urls-with-sqlmap
https://poesiabinaria.net/2013/10/slugs-amigables-en-php-para-usar-en-urls/
https://blog.verslu.is/aspnet/aspnetcore/seo-friendly-urls-slug/
https://security.stackexchange.com/questions/5869/testing-clean-urls-with-sqlmap
https://security.stackexchange.com/questions/31320/sql-injection-how-to-inject-clean-rest-urls
https://mediatemple.net/community/products/dv/204643270/using-.htaccess-rewrite-rules


Autor: Mario Valiente
Dpto. Auditoría