Inyecciones SQL basadas en booleanos
Última actualización
Última actualización
¡Hola Hacker! Bienvenid@ a un nuevo artículo.
En este nuevo artículo de la serie de Inyecciones SQL, toca hablar como indica el título de las inyecciones SQL basadas en booleanos o también llamadas condicionales.
La inyección SQL basada en booleanos es una técnica utilizada en los ataques de inyección SQL para obtener información confidencial o manipular una base de datos. A diferencia de otros tipos de inyección SQL, que se basan en errores de sintaxis o de lógica, la inyección SQL basada en booleanos aprovecha las respuestas booleanas (verdadero/falso) de las consultas SQL para extraer información paso a paso.
A continuación, podemos ver el proceso básico de una inyección SQL basada en booleanos:
Identificar el punto de inyección: El primer paso es identificar un punto de entrada en una aplicación web donde se puedan introducir parámetros en una consulta SQL. Esto puede ser a través de formularios, URL o cualquier otro método de interacción con la base de datos.
Probar la inyección: Una vez identificado el punto de inyección, se deben realizar pruebas para determinar si la aplicación es vulnerable a la inyección SQL basada en booleanos. Por lo general, se utilizan consultas SQL maliciosas como ' OR 1=1 --
para verificar si la aplicación devuelve un resultado esperado o si muestra algún comportamiento anómalo.
Enumerar la base de datos: Una vez confirmada la vulnerabilidad, se procede a extraer información de la base de datos utilizando técnicas de fuerza bruta o basadas en booleanos. La técnica basada en booleanos implica realizar una serie de consultas condicionales con valores verdaderos (1=1) y falsos (1=0) para determinar la veracidad de ciertas afirmaciones sobre la estructura y los datos de la base de datos.
Obtener información sensible: Utilizando consultas condicionales, se pueden extraer gradualmente detalles sensibles, como nombres de tablas, nombres de columnas y datos confidenciales almacenados en la base de datos. Esto se logra mediante el análisis de las respuestas booleanas de la aplicación a las consultas SQL manipuladas.
Como podemos ver, el proceso es similar a las demás inyecciones SQL, solo que la forma de probar y realizar la enumeración varia.
Para demostrar esta inyección SQL, utilizaremos el sciript posts.php
el cual toma el parámetro search
por GET y realiza una búsqueda de todos los artículos que contengan esa palabra como parte del título.
Creamos el script dentro de la carpeta app de nuestro laboratorio.
En este caso, si no pasamos ningun parámetro nos devuelve todos los posts.
En el recuadro negro podemos ver en todo momento la consulta SQL generada.
Si pasamos el parámetro search
con el valor de running
devuelve el siguiente resultado:
Si pasamos por ejemplo el valor de daily
devuelve lo siguiente:
Ahora que tenemos claro como funciona el script, comenzemos con la explotación de la inyección SQL.
Algunas veces no tenemos la salida de errores de consulta, como si teniamos en el artículo de inyecciones basadas en uniones, por lo que estamos a ciegas. En este caso, podemos hacer uso de las inyecciones basadas en booleanos.
Esta consulta de ejecuta en SQL de la siguiente forma:
Devolviendo en este caso todos los artículos.
Para obtener las Bases de Datos utilizando este tipo de inyecciones SQL, es un poco más trabajoso que usando consultas basadas en uniones, pero podemos lograrlo.
Lo haremos utilizando la siguiente consulta.
Para poder entender de donde salen cada una de las partes que componen la consulta SQL y no abrumarnos, la dividiremos en secciones.
Para la explicación de esta consulta, usare la consola de MYSQL.
Como sabemos:
information_schema Base de datos que almacena información de la esctructura de todas las base de datos
schemata Tabla que almacena las base de datos existentes
schema_name Campo que almacena el nombre de la base de datos
Obtenemos todas las bases de datos
La cláusula GROUP_CONCAT
de MySQL se usa para concatenar valores de varias filas en un solo valor. Es útil cuando queremos combinar valores relacionados en una sola cadena.
La función SUBSTRING(GROUP_CONCAT(schema_name), 1, 1)
extrae el primer carácter del resultado devuelto por GROUP_CONCAT
en este caso la letra i
que corresponde al primer caracter de la base de datos information_schema
.
Utilizamos la función ASCII
porque permite obtener el valor ASCII de un carácter específico en una cadena. Este enfoque es útil en ataques de inyección SQL tipo Blind para extraer datos de forma lenta pero efectiva.
Para consultar el valor ascii de un caracter podemos hacerlo con el siguiente comando:
Por ultimo, solo queda evaluar el resultado comparando el valor devuelto por la función ASCII
y el valor a comparar, en este caso la letra i
valor ascii 105
.
Ahora que tenemos claras cada una de las partes que componen nuestra consulta, podemos entender mejor la inyección SQL.
Cómo vemos, lo que hace es buscar un post que contenga en el título la palabra test
, como no existe ninguno, se ejecuta nuestra consulta SQL la cual da como resultado verdadero, devolviendo de esta manera todos los artículos.
Podemos probar esto ingresando como valor un valor ascii de 102
correspondiente a la letra h
, vemos que efectivamente no devuelve ningun resultado.
Como habras notado, realizar este proceso de forma manual se vuelve un poco tedioso, por lo que podemos montarnos un pequeño script en Python que nos devuelva todas las bases de datos.
Ejecutamos el script:
Observamos que logramos obtener todas las bases de datos de forma exitosa.
Antes de continuar para obtener las tablas, expliquemos el script anterior.
Importación de los modulos
requests
: Realiza solicitudes HTTP para interactuar con la aplicación web.
time
: Introduce retardos para simular un proceso progresivo.
pwn
: Una biblioteca de explotación que incluye utilidades para formatear salidas (log.progress
).
URL Objetivo
Especifica la URL del endpoint vulnerable que será atacado.
Función Principal
Esta función realiza la inyección SQL para extraer información.
log.progress
: Crea una barra de progreso para informar al usuario.
p1.status
: Muestra el estado actual ("Obteniendo las bases de datos").
time.sleep(2)
: Añade un retraso de 2 segundos antes de comenzar.
Preparación para extraer datos
p2
: Otra barra de progreso para mostrar los datos extraídos.
extracted_info
: Variable donde se almacenarán los resultados obtenidos de la inyección SQL.
Bucle principal para extraer caracteres
Primer bucle (for position in range(1, 150):
):
Itera por las posiciones de los caracteres en los nombres concatenados de las bases de datos.
Suponemos que el resultado puede tener hasta 150 caracteres (este número puede variar dependiendo de las necesidades).
Segundo bucle (for character in range(33, 127):
):
Itera por los valores ASCII imprimibles (33 a 126) para determinar cada carácter.
Construcción de la URL inyectada:
La inyección SQL es:
GROUP_CONCAT(schema_name)
: Obtiene todos los nombres de bases de datos en una sola cadena.
SUBSTRING(..., position, 1)
: Extrae un carácter en la posición position
.
ASCII(...)
: Convierte el carácter extraído a su valor ASCII.
... = {character}
: Compara el valor ASCII del carácter con el actual del bucle.
Solicitud HTTP:
Envía la URL inyectada usando requests.get(sqli_url)
.
Validación del resultado:
Si la respuesta contiene la palabra clave 'Running'
, indica que la condición booleana fue verdadera.
Se guarda el carácter correspondiente en extracted_info
y se actualiza la barra de progreso.
Salida del bucle:
Cuando se encuentra un carácter válido, se rompe el segundo bucle y se pasa a la siguiente posición.
Una vez completados los bucles, extracted_info
contendrá los nombres de las bases de datos extraídos.
Para obtener las tablas en este caso de la base de datos app_db
utilizaremos un proceso similar.
Obviamente este script podemos hacerle muchas mejoras, como por ejemplo que el parámetro de la base de datos sea dinámico y realizar algun que otro control. Pero para fines practicos es mejor mantenerlo lo más sencillo posible.
Ejecutamos el script:
Para obtener las columnas en este caso de la tabla users
lo haremos de una manera similar, utilizando la tabla information_schema.columns
.
Ejecutamos el script:
De esta forma logramos obtener las columnas de la tabla users
.
Por ultimo, nos queda obtener los datos de la tabla.
Pero esto será un trabajo más sencillo, ya que conocemos el nombre de la base de datos, la tabla y las columnas.
Ejecutamos el script:
De esta manera, logramos obtener los usuarios.
Así concluimos este artículo.
Como demostramos a lo largo de este artículo, las inyecciones SQL basadas en booleanos explotan las respuestas de la base de datos a consultas con condiciones lógicas (como AND
y OR
) para determinar si ciertas condiciones son verdaderas o falsas. Este ataque permite al atacante obtener información de la base de datos sin exponerla directamente, manipulando la consulta para que se evalúe como verdadera o falsa.
Para prevenir este tipo de ataques, es clave:
Validación de entradas: Usar consultas parametrizadas.
Principio de menor privilegio: Restringir los permisos de acceso.
Monitoreo de consultas: Detectar patrones anómalos en las consultas.
Espero que estés disfrutando de esta serie de artículos y que la información te sea útil. Si te ha gustado, te animo a compartirla con otros para que más personas puedan beneficiarse.
Si encuentras algún error o tienes sugerencias para mejorar, no dudes en hacérmelo saber. Estoy siempre abierto a tus comentarios.
¡Gracias por leer!
¡Happy Hacking!