Cláusula UNION en SQL Injection
Para una mejor experiencia y comprensión de la cláusula UNION en SQL Injection, recomendamos repasar la página anterior donde se explica en forma detallada las inyecciones SQL.
Table of Contents
ToggleIntroducción
La combinación de consultas junto con la cláusula UNION en SQL Injection es usada para comparar los resultados de varias consultas y combinarlos en un nuevo resultado.
Dado que se van a comparar varias consultas, es necesario que:
En cada resultado exista la misma cantidad de campos
Los campos a comparar tengan tipos de datos compatibles (no es necesario que tengan el mismo nombre).
La sintaxis para combinar dos consultas mediante la cláusula UNION es:
consulta-1 UNION consulta-2
La primera consulta que interviene se escribe sin el punto y coma (;) al final ya que la consulta completa está formada por aquellas que intervienen y, el operador UNION, finalizando después de la segunda consulta. Esto es así para todas las combinaciones de consultas.
Veamos un ejemplo donde tenemos dos tablas:
Supongamos que queremos tener una lista completa de animales, y tenemos las tablas “Leones” y “Tigres”. Entonces para saber el total de ambos haríamos lo siguiente:
SELECT * FROM Leones UNION SELECT * FROM Tigres ;
Ahora, supongamos que se necesita obtener una lista completa de todos los bebés nacidos en el año 2022 en EE.UU: bebés de sexo masculino nacidos en Whashintong DC y bebés de sexo femenino nacidos en New York. La sentencia SQL sería:
SELECT * FROM bebés-M WHERE state = ‘Whashington DC’ UNION SELECT * FROM bebés-F WHERE state = ‘New York’ ;
Ahora veamos un ejemplo con una misma tabla en nuestro kali:
Dato Importante:
Cuando usemos cláusula UNION en SQL Injection, se anulará automáticamente las filas duplicadas entre las tablas. Es decir, en el caso de querer mostrar las filas duplicadas, la cláusula que deberemos utilizar es UNION ALL.
Esta es una forma de verificar si existen filas duplicadas entre tablas. Por lo tanto, si al utilizar la cláusula UNION se obtiene la misma cantidad de filas resultantes que al utilizar la cláusula UNION ALL, esto mostraría que no existen registros duplicados entre las tablas consultadas.
Determinar el número de columnas devueltas por la consulta
Anteriormente vimos que sabiendo el código fuente de la consulta o, usando el operador ORDER BY, podíamos saber la cantidad de columnas que posee la base de datos en la cual estamos interactuando en un sitio web. Sin embargo, haciendo uso de UNION también podemos saber esto y más. En base a una consulta en un sitio web, debemos usar el UNION de la siguiente forma:
SELECT First_name, Surname from users where id = ‘’UNION select columna1, columna2 — –’ ;
Todo esto teniendo en cuenta que no sabemos el nombre de la columna de dicha base de datos.
Por ejemplo, veamos el siguiente ejemplo:
La única diferencia aquí es que hemos colocado ‘;’ ya que estamos en nuestra Shell de kali. Sin embargo, esto también lo podemos hacer colocando los campos “NULL”. Esto hace referencia a un valor vacío, pero NO nulo. A veces tendremos que usarlo ya que algunos sitios web no nos dejarán colocar números o letras.
Veamos estos ejemplos en nuestra máquia DVWA en nivel low:
Ahora usemos NULL en lugar de un número:
Como vemos, nos da como resultado dos valores “vacíos” pero NO nulos.
En el caso de querer saber la cantidad de columnas en un sitio web deberíamos intentar colocar valores hasta tener un mensaje de error o una pantalla en blanco como vimos anteriormente. Veamos esto en nuestra shell:
En el sitio web:
Encontrar una columna que contenga texto importante
Sabiendo lo anterior, podríamos empezar a usar la cláusula UNION en SQL Injection para extraer información. Por ejemplo, podríamos agregar database(), para saber el nombre de la base de datos utilizada en el sitio web, o también podríamos usar versión(), para saber la versión de dicho servicio.
Veamos a continuación:
Como vemos nos devuelve el nombre de la base de datos (dvwa) y la versión del servicio mysql (10.6.10-MariaDB-1+b1).
Incluso podemos saber el nombre del usuario logueado en el sistema usando user():
Como vemos, nos devuelve al usuario al administrador quien se encuentra logueado.
Ahora bien, en algunas web más vulnerables, incluso podemos probar inyectando código PHP probando con <?php system(‘whoami’);?> o también, incluir archivos locales del sistema con local_file(‘/path/file.txt’).
Sin embargo, puede pasar algunas veces, como vimos anteriormente, que solo podremos probar con valores NULL. Entonces pueden haber campos que solo admitan valores null mientras que otros admitan entradas con caracteres. Por ejemplo, en la imagen anterior vimos que colocando ‘test’ y user() nos devolvía ambos resultados, pero pueden haber situaciones en las que algunos campos no nos devuelvan nada y algunos si. Por tanto, deberíamos buscar los datos requeridos en base al campo que admita caracteres no null.
Recuperar datos de otras tablas
Anteriormente vimos cómo encontrar la cantidad de columnas y, en base a ello, la información que podíamos obtener. Sin embargo, ahora veremos consultas claves para obtener información acerca de aquellas columnas a las cuales no podíamos ingresar, como así también a otras bases de datos y sus respectivas columnas.
Vimos que en la máquina DVWA, en nivel low, la consulta era la siguiente:
SELECT first_name,Surname FROM users WHERE id = ‘$id’;
Por lo tanto, dicha consulta nos muestra la table “users”. En otras palabras, podríamos probar colocando columnas como “user” o “username” para saber el nombre de usuario, y lo mismo con la contraseña. Ahora bien, realizando ‘unioin select user,password from users — – ya podríamos obtener información sobre los usuarios y sus contraseñas.
Sin embargo, en la mayoría de los casos, no vamos a tener a nuestra disposición la consulta de dicho sitio web en nuestras manos. Por lo tanto, para implementar de forma correcta la cláusula UNION en SQL Injection, estaremos haciendo uso de ciertos métodos con el fin de obtener información más detallada. Veremos es a continuación:
Listar todas las bases de datos:
SELECT columna1,columna2 FROM tabla WHERE columnaX = ‘’union select null,scheman_name from information_schema.schemata — –’ ;
Por ejemplo:
Como podemos ver, en nuestra shell de kali nos aparece todas las bases de datos del sistema, incluso la base de datos dvwa que estamos usando a modo de ejemplo.
Cabe mencionar que la base de datos “information_schema” proporciona acceso de solo lectura a los detalles relacionados con las bases de datos y sus objetos (restricciones, tablas, procedimientos, vistas..) almacenados en el servidor. Las encontramos en Mysql, como también en SQL Server, y otras bases de datos suelen tener la misma u otra similar. Su uso suele ser para verificar tareas, automatizar procesos, y también comprobar lo que hay en el servidor y en la base de datos. Por lo tanto, las estaremos usando para encontrar la mayor información.
Ahora bien, veamos el mismo ejemplo pero aplicado a nuestra máquina DVWA:
Como vemos, hemos obtenido las bases de datos alojadas en nuestra máquina.
También podemos usar otras opciones en caso de tener problemas, o simplemente querer ver la respuesta en un formato más “amigable”. Por ejemplo, haciendo uso con group_concat como se muestra a continuación:
Podemos ver que nos devuelve todas las bases de datos separadas por “,”.
De igual modo, podemos hacer uso del operador LIMIT. Veamos los siguientes ejemplos:
De esta manera, podemos ir probando uno por uno hasta llegar a la última:
Recordemos que un sitio web NO debemos colocar ‘;’ al final de nuestra consulta, sino ‘— –‘, ‘—‘ o en algunos casos ‘#’
Listar todas las tablas:
En el caso de querer listar TODAS las columnas de las bases de datos existentes, podríamos usar la siguiente consulta:
SELECT columna1,columna2 FROM tabla WHERE columnaX = ‘’union select null,table_name from information_schema.tables — –’ ;
Veamos los siguientes ejemplos:
En nuestra máquina víctima veríamos lo siguiente:
Observemos que, si bien hemos tenido éxito con nuestra búsqueda, es mucha información la que se nos presenta. Recordemos que estamos teniendo como resultado todas las tablas de todas las bases de datos. Por tanto, no es muy recomendable usar este método ya que, podemos llegar a perder tiempo buscando aquello que deseamos encontrar. Entonces, en base a esto, podríamos usar la siguiente consulta:
SELECT columna1,columna2 FROM tabla WHERE columnaX = ‘’union select null,table_name from information_schema.tables where table_schema = ‘DataBase ’– –’ ;
Anteriormente vimos que teníamos una base de datos llamada ‘dvwa’. La cual, la podíamos ver desde nuestra Shell como desde nuestra máquina víctima. Por lo tanto, deberíamos tener el mismo resultado en ambas:
En nuestra Shell:
En nuestra máquina víctima:
No solo vemos que hemos tenido los mismos resultados, sino que este método es más práctico y cómodo de utilizar a la hora de buscar la información que deseamos.
Listar todas las columnas:
Una vez hemos tenido el nombre de la base de datos y sus tablas, el siguiente paso será saber las columnas que pertenecen a dicha tabla. En este caso nos interesa saber las columnas de la tabla ‘users’ vista anteriormente. Para esto, usaríamos la siguiente consulta:
SELECT columna1,columna2 FROM tabla WHERE columnaX = ‘’union select null,column_name from information_schema.columns where table_schema = ‘DataBase’ and table_name = ‘Table’ — –’ ;
Por lo tanto, si especificamos la tabla ‘users’, deberíamos tener como resultado todos los usuarios del sistema:
Como podemos ver, hemos obtenido todos los usuarios de la tabla ‘users’. A modo de ejemplo vemos a “first_name” y “last_name” e incluso a “user_id”, los cuales vimos al principio con la consulta que nos mostraba nuestra máquina víctima:
Por lo tanto, sabemos que la base de datos el “dvwa”, la tabla es “users” y los campos que nos interesan “user” y “password”. Una vez hemos llegado a este punto, podremos saber información confidencial, de la siguiente manera:
‘ unión select user,password from users — –
Como vemos, hemos obtenido el usuario y contraseña (cifradas con hash).
Tener en cuenta:
Recordemos que podemos hacer uso de group_concat() en caso de querer ver nuestra información más ‘amigable’, como así también en caso de que no nos funcione lo anterior. Por ejemplo:
‘union select null,group_concat(user,’:’,password) from users — –
De esta forma, utilizamos de una mejor manera la cláusula union en SQL injection.
En el caso de que tengamos problemas o, no nos reconozca los dos puntos ‘:’, podríamos colocarlo en hexadecimal. En este caso el carácter ‘:’ en hexadecimal es ‘3A’(Recordemos que siempre hay que colocarle ‘0x’ adelante). Esto podemos verlo a través del comando man ascii.
Otro ejemplo podría ser:
‘union select null, user||’:’||password from users — –
Con lo cual tendríamos como resultado al usuario y contraseña separados por ‘:’