Tutorial de Inyeccion de SQL

Hola a todos!

El dia de hoy me gustaria compartir con ustedes una pequeña nota acerca de como funciona una inyeccion de SQL.

Generalmente este tipo de vulnerabilidad afecta a aplicaciones web, sin embargo no esta limitada a solo web, sino a cualquier aplicacion que tenga transacciones con una base de datos. Tambien es una de las vulnerabilidades mas comunes encontradas dentro de sistemas, y esta dentro del Top 10 de OWASP. Es recomendable tener fundamentos en programacion web (php, asp, jsp, etc) y bases de datos/SQL para poder entender esta entrada.

Comencemos con este ejemplo, La siguiente imagen denota una aplicacion web que esta conectada a una base de datos para obtener una consistencia en sus datos, como muchas aplicacion web existen el dia de hoy.

En este ejemplo, el servidor web MXWEBDEV01 tiene una conexion con el servidor de base de datos MXSQLDEV01. vamos tambien asumir que esta conexion esta hecha en PHP y el sistema gestor de bases de datos es MariaDB (tan solo para mantener simple este ejemplo). Entonces el codigo para la conexion del servidor web hacia la base de datos seria algo parecido a los siguiente:

  
  $baseDeDatos = "Registros";
  $usuario = "applicacion_web";
  $contrasena = "Contr@sena_Sup3r_Segur4_2023";
  $servidor = "MXSQLDEV01"
  
  $conexion = new mysqli($servidor, $usuario, $contrasena, $baseDeDatos);
  

En donde el para contruir el objeto MySQLi tenemos el nombre de la base de datos, el usuario y constrena para el sistema gestor (MariaDB) y el nombre del servidor (aqui asumimos que la existencia de un servidor DNS que puede traduccir IP a nombre de dominio). Asi mismo para poder realizar trasacciones tipo CRUD (Create, Read, Update and Delete; o Crear, Leer, Actualizar y Borrar), el servidor web tiene que ejectuar comandos en SQL para poder interactuar con la base de datos. En aplicaciones vulnerables y con poca sanizitacion provista por desarrolladores, generalmente se encuentran instrucciones de codigo similares a la siguiente:

  
  $sql = "SELECT id, nombre, descripcion FROM inventario"
  		. "WHERE nombre LIKE '%" . $_GET['nombre'] . "%'";
  $resultado = $conexion->query($sql);
  

En el codigo anterior encontramos un comando SQL dentro del la variables $sql, este comando se utiliza para leer el contenido de la tabla inventario, se utiliza tambien la clausula WHERE para filtrar el contenido de la tabla inventario dada la entrada provista por el usuario dentro la variable nombre en el arreglo predeterminado $_GET. Este arreglo es utilizado por los desarrolladores PHP para acceder variables alojadas en el URL (Uniform Resource Locator o el localizador uniforme de recursos), por ejemplo si el usuario usa el URL http://mxwebdev01/?nombre=cafe la variable nombre tendria el valor de cafe el URL, a su vez el codigo PHP utilizaria este valor para ejecutar el comando SQL.

Ahora, lo que hace vulnerable esta parte del codigo es que es posible inyectar codigo SQL trivial dentro de la variable nombre, dado a que no existe ningun mecanismo para sanitizar esta variable; simplemente concatena el codigo SQL con la entrada del usuario. Asi pues, si un atacante usara el valor %' OR 1=1 # entonces dejaria que el filtro fuera inutil dado que el comando SQL ejecutaria de la siguiente manera:

  SELECT id, nombre, descripcion FROM inventario 
  	WHERE nombre LIKE '%%' OR 1=1 #
  

Tipos de Inyeccion de SQL

Una vez que identificamos una vulnerabilidad de inyeccion de SQL, tambien podemos identificar el tipo inyeccion, al momento de escribir esta nota existen 3 tipos de inyeccion: basadas en union, basadas en error e inyeccion ciega.

Inyeccion de SQL basada en Union

Las inyecciones basadas en union, como su nombre lo menciona, se encuentran cuando un parametro es vulnerable y afecta un comando SQL que tiene un SELECT. Recordemos que en SQL podemos unir varias tablas obtener resultados como una union, interseccion, inversos, etc. Lo que vuelve interesante a esta vulnerabilidad es que es posible leer datos, y ejecutar funciones, que no estaban previstas por los desarrolladores.

Regresemos a nuestro ejemplo anterior, donde tenemos un parametro vulnerable a inyeccion SQL, y esta es del tipo basda en union. Entonces nosotros podemos inyectar el siguiente parametro para obtener el nombre del usuario y la version del sistema gestor de base de datos: %' UNION ALL 0, user(), @@version #, entonces el comando SQL se veria de la siguiente manera:

 
  SELECT id, nombre, descripcion FROM inventario 
  	WHERE nombre LIKE '%%' 
  	UNION ALL 0, user(), @@version #
  

Un atacante podria inyectar ese codigo SQL en el URL para poder explotar la vulnerabilidad. Entonces URL quedaria de la siguiente manera (los caracteres especiales como '#', '@', espacio en blanco y parentesis estan codificados en URL): http://mxwebdev01/?nombre=%25%27%20UNION%20ALL%200,%20user%28%29,%20%40%40version%20%23

Inyeccion de SQL basada en Error

Las inyecciones basadas en error se refieren a cuando el resultado de nuestra inyeccion lo podemos inferir del resultado que nos provee la aplicacion web. Es decir, si por ejemplo encontramos una forma para autenticar un usuario (basicamente una forma para hacer login), es muy probable que el unico resultado que podamos ver de la trasaccion entre el servidor web y la base de datos, sea un mensaje de autenticacion fallida, o acceso a otra pagina con una autenticacion satisfactoria. Existen algunos casos donde la aplicacion web esta en mode depuracion (o debug mode), y podemos ver el Error Stack de PHP cuando existe algun error al tratar de interactuar con la base de datos (Esto generalmente se presente en ambientes de desarollo o integracion, antes de sacar software a produccion).

Entonces la manera de comprobar una vulnerabilidad de inyeccion de SQL basada en error, seria que al momento de inyectar codigo, el servidor web se comporte de manera diferente a la esperada, ya sea respondiendo con un codigo 500 en HTTP o con error de ejecuccion de PHP.

Analizemos el siguiente codigo.

  $sql = "SELECT id FROM usuarios "
    . "WHERE usuario='" . $_POST["usuario"] . "' "
    . "AND contrasena='" . $_POST["contrasena"] . "'";
  $resultado = $conexion->query($sql);
  if ($resultado->num_rows > 0) {
  	return TRUE;
  }
  return FALSE;
  

El codigo anterior toma la entrada del usuario para autenticarlo, su nombre de usuario y contrasena son tomados del arreglo predeterminado de PHP $_POST, seguidamente y de una manera vulnerable estos son tomados y concatenados al comando SQL que sera ejecutado dentro del gestor de base de datos. Si existe al menos una combinacion de usuario y contrasena que el usario provio al sistema, entonces esta parte del codigo regresara el valor boleano verdadero, de ser contrario y no encontrar ningun registro, entonces regresara un falso. Si un atacante entonces proviera como contrasena el comando SQL ' OR 1=1 #, entonces segun nuestra matematicas discretas, si hacemos un OR con un verdadero (1=1 es siempre verdadero), el resultado siempre sera verdadero. Entonces el comando SQL seria terminaria asi:

  SELECT id FROM usuarios
    WHERE usuario='' 
    AND contrasena='' OR 1=1 #
  

Asi pues, el atancante prodria autenticarse sin siquiera tener un usuario ni contrasena, con tan solo explotar esta la vulnerabilidad.

Inyeccion de SQL Ciega

Tambien conocida como inyeccion SQL basada en tiempo. En algunos casos, cuando estamos intendado descubrir una vulnerabilidad de inyeccion de SQL, la aplicacion aparentemente no se comporta de ninguna manera diferente durante nuestras pruevas iniciales. Pero si aun asi sospechamos de la existencia de una vulnerabilidad, entonces podemos intentar inyeccion SQL basada en tiempo. Podemos usar el comando SQL SLEEP para detener la ejecucion de la aplicacion por determinados segundos. Si el sistem en efecto se detiene por la misma cantidad de tiempo, entonces podemos confirmar la vulnerabilidad.

Un Ejemplo

Aqui tenemos un escenario donde econtramos una vulnerabilidad de inyeccion SQL, y por que pueden llegar a tener un riesgo alto.

Tenemos un servidor web en la direccion ip 192.168.56.102 en el puerto TCP 80, mientas que nuestro ordenador Linux tiene una direccion IP de 192.168.56.101. Si abrimos el navegador (en mi caso Mozilla Firefox), descubrimos un sitio web donde podemos ver un inventario con la funcionalidad de filtrar contenido:

Con esta herramienta podemos filtrar el invnetario, por ejemplo por monitor.

Para verificar la vulnerabilidad del parametro nombre, tan solo necesitamos ingresar una apostrofe/comilla ('). En la siguiente imagen, podemos darnos cuenta que he abierto las herramientas de desarrollar de Firefox, en la pestana de Network (Red) vemos tambien que el servidor respondio con un codigo 500, lo cual confirma la posible existencia de un error dentro del codigo del servidor web.

Es aqui donde las cosas se vuelven interesantes, podemos intentar un ataque de inyeccion de SQL basado en union. Vamos a inyectar el siguiente codigo para leer la version del servidor de MySQL.

  %' UNION ALL SELECT 0, '', @@version #
  

Evidentemente nuestro ataque funciono, podemos ver que la version del servidor de MySQL es 8.0.34 dentro un servidor Ubuntu 22.04 Linux. Ahora podemos escalar nuestro ataque para descubrir los usuarios y hashes de sus contrasenas. Recordemos que toda esta informacion se encuentra alojada dentro de la base de datos mysql tabla user. Entonces nuesto siguiente payload a inyectar seria el siguiente:

  %' UNION ALL SELECT 0, user, authentication_string FROM mysql.user #
  

Comunmente dentro una prueba de Pentesting, intentariamos crakear las contrasenas mediante un ataque de bruteforce. O quiza, con la ayuda de esta vulnerabilidad, intentar escribir al sistema de archivos un archivo tipo PHP y obtener un webshell, puesto que nuestro objetivo siempre es encontrar Ejecucion Remota de Codigo (RCE - Remote Code Execution). Dado que este articulo ya es demasiado grande, lo discutiremos despues en otro articulo.

Conclusion

En este articulo nos enfocamos en describir como funciona una vulnerabilidad de inyeccion de SQL. Si eres desarrollador web, es recomendable siempre sanitizar cualquier entrada provista por el usuario.

Porfavor siguenos en Youtube, eso me ayuda a crear mas contenido!! https://youtube.com/@tottixchannel9306?si=A01BMXYTrKYbtM-j. Hasta la proxima!

Comentarios

Entradas más populares de este blog

Tutorial para Instalar Visual Studio 2019 (Community Edition) en Windows.

Tutorial de Burpsuite