miércoles, 17 de febrero de 2016

Inyección de comodines SQL en búsquedas de tipo LIKE

A continuación voy a hablar de una vulnerabilidad muy poco conocida y tradicionalmente considerada como de poco riesgo, aunque como vamos a ver en algunas situaciones puede tener un gran impacto.

Esta vulnerabilidad consiste en la posibilidad de inyectar un comodín (wildcard) en el campo de búsqueda del operador LIKE de una sentencia SQL.

OWASP menciona brevemente en sus guías este tipo de inyecciones.

En SQL tenemos 2 tipos de comodines:
  • % que equivale a cualquier cadena de cero o más caracteres.
  • _ que equivale a cualquier carácter único.

Una aplicación es vulnerable a este ataque cuando realiza una búsqueda de tipo LIKE con un parámetro recibido del usuario sin filtrar estos 2 comodines.

Por ejemplo si tenemos una aplicación con la siguiente URL:

Que muestra un texto extraído de una BBDD mediante una sentencia SQL como la siguiente:

En vez de usar la forma simple:

Aunque la variable $nombre esté saneada para evitar la inyección de SQL (por ejemplo filtrando el carácter comilla simple) sigue siendo posible la inyección de los comodines de búsqueda, de la siguiente forma:

En una aplicación de este tipo, el poder alterar la lógica de la búsqueda tal vez no sea crítico, pero ¿y si tenemos otra aplicación como la siguiente? (de la que no conocemos ningún nombre de usuario):

Podemos fácilmente hacer lo siguiente para obtener un listado de todos los usuarios disponibles:

Podemos automatizar el proceso mediante un pequeño script que nos vaya sacando los nombres de cada usuario carácter a carácter (a lo película juegos de guerra).

¿En qué situaciones puede ser peligrosa una vulnerabilidad de este tipo?:
  • En formularios de login. Me he encontrado varias veces esta vulnerabilidad en el campo “usuario” de alguno de estos formularios y menos habitualmente en el campo “contraseña”.
  • En formularios de recuperación de contraseñas. Puede permitirnos resetear la contraseña de terceros usuarios.
  • En campos que contienen identificadores de sesión o tokens. Nos podría permitir “robar” tokens o sesiones de otros usuarios.

Aunque parezca mentira esto funciona algunas veces:

La inyección del carácter % a veces puede ser problemática, porque suele estar filtrado para evitar ataques de encoding o precisamente porque es decodificado incorrectamente (en este caso podemos probar %25, %2525).

Hace tiempo me encontré una curiosa situación en una aplicación que autenticaba mediante un identificador de sesión que almacenaba en una base de datos y que extraía mediante una búsqueda vulnerable, de esta forma:


El servidor filtraba el carácter %, pero se permitía el carácter _ de forma que podíamos explotar la vulnerabilidad de la siguiente forma:


Si queríamos acceder a alguna sesión en concreto solo teníamos que hacer un barrido:


¿Porque algunos programadores son víctimas de un bug tan evidente?

Algunas veces supongo que será por despiste, pero también he detectado que algunos frameworks encapsulan las llamadas SQL de forma transparente para el programador y si internamente usan el operador LIKE, es posible que este ni siquiera lo sepa. 

Por ejemplo en Django la siguiente sentencia:

Equivale a:

Lo que puede derivar fácilmente en múltiples vulnerabilidades si el desarrollador no es cuidadoso.

O también este otro bug del mismo estilo en el módulo Propel de Symfony.