DataSunrise previene SQLI
En este artículo, te demostramos cómo DataSunrise previene las inyecciones SQL, que es uno de los instrumentos más populares de los hackers para violar aplicaciones web. Para mostrarte exactamente qué sucede cuando DataSunrise intercepta una consulta maliciosa, realizamos un test de penetración con un software dedicado.
Sqlmap
Aunque existen muchas aplicaciones diversas dedicadas a realizar evaluaciones automáticas de vulnerabilidad, utilizamos la utilidad Sqlmap en nuestro experimento actual. Este programa gratuito y de código abierto está escrito en lenguaje Python y es fácil de usar gracias a su interfaz de línea de comandos.
Según la descripción oficial, Sqlmap puede utilizar las siguientes técnicas de inyección SQL para pruebas de penetración:
Inyección ciega basada en booleanos
Sqlmap agrega al parámetro vulnerable en la consulta HTTP una cláusula SQL sintácticamente válida, que contiene una subconsulta SELECT o cualquier otra declaración SQL utilizada para recuperar la salida de la base de datos. Luego, Sqlmap compara cada respuesta HTTP con la solicitud original y obtiene la salida de la declaración inyectada, carácter por carácter.
Inyección ciega basada en tiempo
Sqlmap agrega al parámetro vulnerable una declaración sintácticamente válida que contiene una consulta que causa un retraso en el servidor de la base de datos por un cierto número de segundos. Luego la utilidad realiza una comparación entre el tiempo de respuesta original y el tiempo gastado en la respuesta de la consulta inyectada y luego infiere la salida de la declaración inyectada carácter por carácter.
Inyección basada en errores
Sqlmap agrega al parámetro vulnerable en la solicitud HTTP una cadena de declaración sintácticamente inválida que causa un mensaje de error específico de la base de datos. Luego, Sqlmap analiza la respuesta HTTP tratando de encontrar mensajes de error que contengan el código SQL inyectado y la salida de la subconsulta. Este método de inyección SQL solo funciona si el sistema de gestión de bases de datos (DBMS) está configurado para mostrar mensajes de error del servidor.
Inyección basada en consultas UNION
Sqlmap agrega al parámetro vulnerable en la solicitud HTTP una declaración SQL sintácticamente válida que comienza con UNION ALL SELECT. Este método es útil cuando la página de la aplicación web utiliza un bucle FOR o similar para pasar la salida de la declaración SELECT, por lo que cada línea de salida de la consulta se imprime en el contenido de la página. Sqlmap también es capaz de explotar vulnerabilidades de inyección SQL “parcial” basada en UNION. Estas vulnerabilidades ocurren cuando no se usa el ciclo FOR y solo se muestra la primera entrada de la salida de la consulta.
Inyección basada en consultas apiladas (piggybacking)
Si la aplicación web de destino soporta consultas apiladas, Sqlmap agrega al parámetro vulnerable en la consulta HTTP un carácter de punto y coma ( ; ) seguido de la declaración SQL a ser inyectada. Esta técnica se usa para realizar la inyección de declaraciones SQL distintas de SELECT (como declaraciones de definición de datos o manipulación de datos). Potencialmente, este método puede usarse para obtener acceso de lectura/escritura al sistema de archivos y ejecución de comandos del sistema operativo, dependiendo del servidor de bases de datos (DBMS) y los privilegios del usuario de la sesión.
Como puedes ver, Sqlmap es una herramienta poderosa capaz no solo de revelar vulnerabilidades, sino también de explotarlas con diversas técnicas de inyección SQL. Aquí tienes más sobre métodos de detección de inyección SQL.
Preparaciones para el testing
Para realizar nuestra demostración, necesitamos alguna aplicación de “prueba” susceptible a inyecciones SQL, así que utilizamos un servidor web simple escrito en Python. Este servidor está diseñado para mostrar información de la base de datos definida por los parámetros en la cadena de URL. Guardamos el código del servidor web en el archivo webserv_inj.py:
import re import urllib.request from http.server import BaseHTTPRequestHandler, HTTPServer from urllib.parse import urlparse import pyodbc global dbconnection global dbcursor class InjectedServer(BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.send_header("Content-type", "text/html charset=windows-1251") self.end_headers() o = urlparse(self.path) params = urllib.request.unquote(o.query) m = re.search("id=(?P[^;]+);name=(?P [^;]+)", params) id = m.group("id") name = m.group("name") dbconnection = pyodbc.connect( "Driver=PostgreSQL ODBC Driver(ANSI);Server=localhost;Port=54321;Database=test_db;Uid=postgres;Pwd=admin;UseServerSidePrepare=1") dbcursor = dbconnection.cursor() queryStr = "select * from injected_table where id = " + id + " and name = '" + name + "' order by id" dbcursor.execute(queryStr) result = dbcursor.fetchall() for row in result: self.wfile.write(bytes(str(row[0]), "utf-8")) self.wfile.write(bytes(str(row[1]), "utf-8")) self.wfile.write(bytes(str(row[2]), "utf-8")) myServer = HTTPServer(("127.0.0.1", 6589), InjectedServer) try: myServer.serve_forever() except KeyboardInterrupt: pass myServer.server_close()
Intentaremos vulnerar nuestro servidor web autodiseñado y obtener algunos datos de una base de datos PostgreSQL. Utilizamos el siguiente código para crear una nueva tabla de base de datos (“injected_table”) y llenarla con dos entradas:
CREATE TABLE injected_table ( id integer, name character varying(200), surname character varying(200) ) INSERT INTO injected_table VALUES (1, Bob, Martin); INSERT INTO injected_table VALUES (2, Denis, Morgan);
Así se ve la nueva tabla en PGAdmin
Luego iniciamos nuestro servidor ejecutando el siguiente comando a través del símbolo del sistema de Windows:
python webserv_inj.py
Para asegurarnos de que todo funciona como se espera, enviamos la siguiente consulta al servidor web a través del navegador:
http://127.0.0.1:6589/?id=2;name=Denis
Como resultado, el servidor web muestra la entrada de la tabla “injected_table” con ID=2 y Nombre=Denis
Probando el servidor web con Sqlmap
Ahora es el momento de verificar si nuestro servidor web puede ser objeto de una inyección SQL.
Primero, iniciamos el procedimiento de prueba de Sqlmap a través del símbolo del sistema:
python.exe sqlmap.py -u http://127.0.0.1:6589/?id=2;name=Denis
Cuando el proceso de prueba finaliza, veamos el archivo de registro de Sqlmap (se creó automáticamente y se guardó dentro de la carpeta “output”).
sqlmap identified the following injection point(s) with a total of 50 HTTP(s) requests: --- Parameter: id (GET) Type: boolean-based blind Title: AND boolean-based blind - WHERE or HAVING clause Payload: id=2;name=Denis' AND 8150=8150 AND 'lsHq'='lsHq Type: AND/OR time-based blind Title: PostgreSQL > 8.1 AND time-based blind Payload: id=2;name=Denis' AND 9061=(SELECT 9061 FROM PG_SLEEP(5)) AND 'TLxE'='TLxE Type: UNION query Title: Generic UNION query (NULL) - 3 columns Payload: id=2;name=Denis' UNION ALL SELECT NULL,NULL,(CHR(113)|| CHR(112)||CHR(120)||CHR(120)||CHR(113))||(CHR(88)||CHR(109)||CHR(66)||CHR(103)||CHR(114)|| CHR(69)||CHR(83)||CHR(119)||CHR(113)||CHR(98)||CHR(110)||CHR(73)||CHR(90)||CHR(83)|| CHR(90)||CHR(121)||CHR(113)||CHR(102)||CHR(85)||CHR(117)||CHR(107)||CHR(72)||CHR(78)|| CHR(101)||CHR(79)||CHR(90)||CHR(112)||CHR(120)||CHR(74)||CHR(106)||CHR(114)||CHR(105)|| CHR(85)||CHR(84)||CHR(71)||CHR(104)||CHR(71)||CHR(89)||CHR(75)||CHR(111))||(CHR(113)|| CHR(22)||CHR(107)||CHR(122)||CHR(113))-- - --- back-end DBMS: PostgreSQL
Según lo muestra el registro, Sqlmap identificó con éxito la versión del DBMS (PostgreSQL) y determinó que el parámetro “ID” es vulnerable a la inyección SQL. Además, Sqlmap nos propuso tres variantes de declaraciones SQL que pueden ser utilizadas para realizar la inyección SQL (cadenas de “Payload”).
Configuraciones de reglas de seguridad de DataSunrise (sección de inyecciones SQL)
Y ahora verificaremos qué tan efectivamente DataSunrise puede proteger el servidor web vulnerable (y la base de datos de PostgreSQL asociada) contra inyecciones SQL.
Creé una regla de Seguridad de “inyección SQL” (consulta la guía del usuario de DataSunrise para más detalles) y eliminé los archivos que Sqlmap creó durante la primera prueba.
Ahora corremos el procedimiento de prueba de Sqlmap nuevamente (como se describió anteriormente) y cuando termina, verificamos el registro de la utilidad (nota que Sqlmap no pudo crear un archivo de registro, así que estamos usando su registro de línea de comandos).
Según el registro, Sqlmap determinó que todos los parámetros probados no son vulnerables a la inyección SQL, incluido el parámetro “ID” que fue marcado anteriormente como inyectable.
Conclusión
Nuestro experimento prueba que el firewall de DataSunrise es altamente efectivo para prevenir inyecciones SQL. No obstante, para la mejor protección posible contra las amenazas más complejas, es necesario tomar medidas protectoras extendidas como las siguientes:
- Seguir las mejores prácticas de la industria para desarrollar aplicaciones web resistentes a inyecciones SQL
- Realizar ataques simulados de hackers en tus bases de datos y aplicaciones web para revelar posibles vulnerabilidades (los llamados “tests de penetración”)
- Realizar auditorías continuas de la base de datos para detección de brechas y fugas de datos
- Seguir las recomendaciones y guías del desarrollador sobre el uso seguro de bases de datos y software asociado.
DataSunrise soporta todas las bases de datos y almacenes de datos principales como Oracle, Exadata, IBM DB2, IBM Netezza, MySQL, MariaDB, Greenplum, Amazon Aurora, Amazon Redshift, Microsoft SQL Server, Azure SQL, Teradata y más. Te invitamos a descargar una prueba gratuita si deseas instalarlo en tus instalaciones. En caso de que seas un usuario en la nube y ejecutes tu base de datos en Amazon AWS o Microsoft Azure puedes obtenerlo desde el marketplace de AWS o el marketplace de Azure.