SQL Injection en la Practica: Explotar, Detectar y Mitigar en Lab Controlado
Demostracion tecnica de SQLi con sqlmap en entorno propio, enfocada en deteccion defensiva y fixes parametrizados que realmente sostienen trafico en produccion.
SQL Injection cumplio 27 anos en 2026 y sigue en el top 3 de OWASP. No porque los atacantes se hayan vuelto mas listos, sino porque ORMs mal usados, queries dinamicas en dashboards internos y endpoints GraphQL con resolvers ingenuos siguen concatenando strings. En el lab que montamos aqui partimos de una instancia DVWA en Docker, MySQL 8.0 con binlog activo y un proxy Burp Suite 2025.6 capturando cada request. El objetivo no es impresionar con un dump de la tabla users: es entrenar el ojo para reconocer las senales de instrumentacion defensiva que detienen a sqlmap antes del segundo payload. Si aun no tienes tu entorno aislado, vale repasar Pentest Web desde Cero: Montando un Lab Seguro con DVWA, Juice Shop y Burp Suite antes de seguir.
El primer experimento usa el endpoint vulnerable de SQLi por GET de DVWA en nivel low. Ejecutamos sqlmap -u 'http://lab.local/vulnerabilities/sqli/?id=1&Submit=Submit' --cookie='PHPSESSID=...; security=low' --batch --technique=BEUST --level=3 --risk=2. En 4 segundos sqlmap identifica injection boolean-based blind en el parametro id, en 11 segundos enumera la base dvwa y sus 2 tablas. Fijate en los payloads enviados: 1 AND 4523=4523, 1 AND 1=2 UNION SELECT NULL,NULL. Esos literales numericos repetitivos son oro para reglas de deteccion en WAF y SIEM. Anota el user-agent default sqlmap/1.8.x y la ausencia de Accept-Encoding, porque vamos a convertir esto en senal mas adelante.
Antes de escalar a tecnicas time-based abrimos otra pestana y activamos query logging en MySQL con SET GLOBAL general_log = 'ON'. Cada payload de sqlmap aparece en /var/log/mysql/general.log con timestamp en microsegundos. Comparando 30 segundos de trafico legitimo (generado con locust simulando 50 usuarios) contra 30 segundos de sqlmap, la entropia de las queries explota: el coeficiente de variacion del tamano de query pasa de 0.12 a 1.8. Ese delta solo ya alimenta una regla Sigma decente. Conviene combinarlo con lo que cubrimos en Threat Hunting con Sigma y Elastic: Del Indicador a la Regla de Deteccion para empaquetarlo como deteccion reutilizable en Elastic.
Ahora la parte que separa al script kiddie del pentester: explotar second-order SQLi. Insertamos via formulario de registro un nombre de usuario igual a admin'-- con comillas escapadas por el prepared statement de registro. El problema vive en el endpoint de busqueda interna que reutiliza ese valor en una query dinamica sin reparametrizar. Resultado: bypass de autenticacion en una ruta que ni aparecia en el scan inicial de sqlmap, porque el payload solo se dispara en otro contexto. Ese patron es el mismo que suele perforar APIs GraphQL con resolvers compartiendo builders, como detallamos en Pentest de APIs REST y GraphQL: Checklist Tecnico para Bug Bounty Legal. sqlmap no detecta esto solo, por eso revision manual de codigo sigue pagando en bug bounty.
La mitigacion real arranca con prepared statements parametrizados, pero no termina ahi. En nuestro lab Java/Spring sustituimos la string interpolada por NamedParameterJdbcTemplate, validamos input con Bean Validation (jakarta.validation 3.1) y agregamos un allowlist de columnas permitidas en ORDER BY (porque PreparedStatement no parametriza identificadores). En PHP, PDO con PDO::ATTR_EMULATE_PREPARES=false es obligatorio en MySQL para evitar el clasico bypass de comillas multibyte. Capas siguientes: least privilege en el usuario de la aplicacion (GRANT SELECT, INSERT, UPDATE apenas) y un WAF como ModSecurity con CRS 4.4 en modo blocking para parametros numericos. El hardening del servidor sigue el mismo principio cubierto en Hardening de Linux Server: CIS Benchmark Aplicado sin Romper Produccion: reducir superficie antes de confiar en deteccion.
Para cerrar el ciclo defensivo enchufamos general_log en Filebeat, lo enviamos a un Elastic 8.16 y creamos tres detecciones: pico de errores de sintaxis SQL por arriba de 5 por minuto por IP, queries con UNION SELECT NULL en secuencia, y tiempo de ejecucion de query por arriba de 3 desviaciones estandar sobre el baseline horario. En pruebas contra sqlmap con --random-agent y --delay=2, las tres reglas dispararon en menos de 90 segundos. Tambien agregamos honeytokens: columnas fake como credit_card_test con strings rastreables. Si algun dia ese valor aparece en un paste site, sabemos exactamente que endpoint filtro. Ese loop de feedback red y blue refleja lo que defendemos en Purple Team en la Practica: Construyendo Ciclo de Feedback Red vs Blue.
Takeaway practico: monta el lab, corre sqlmap una vez para sentir el ritmo de los payloads y gasta el 80 por ciento del tiempo restante construyendo deteccion y fixes. SQLi no es problema de creatividad del atacante, es problema de query dinamica que nadie reviso. Pega en tu calendario una revision trimestral de todas las queries que aceptan input externo, parametriza todo lo que sea valor y usa allowlist para todo lo que sea identificador. El dia que puedas probar que tu aplicacion mata sqlmap en menos de 2 minutos con bloqueo automatico, ganaste.