
CakePHP 5.4.2 - Alta - Remota - Proxy - trustedProxies respeta X-Forwarded-* desde cualquier REMOTE_ADDR
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · cakephp-trusted-proxies
Clase: Bypass de redirección HTTPS / suplantación de IP-host Alcance: Remoto
CakePHP 5.4.2 (887b641) - Cake Software Foundation
HttpsEnforcerMiddleware con trustedProxies => ['10.0.0.1'] llama a setTrustedProxies, que establece trustProxy = true y nunca compara la lista con REMOTE_ADDR. Después de eso, scheme(), host() y clientIp() respetan los encabezados del atacante X-Forwarded-Proto / X-Forwarded-For / X-Forwarded-Host / X-Real-IP.
El middleware por defecto tiene trustedProxies en null y no habilita esto. La configuración documentada de balanceador de carga es el caso expuesto. Un cliente HTTP no autenticado que no es el proxy listado puede omitir la redirección HTTPS y suplantar la IP del cliente y el Host.
| ID | sin CVE todavía |
| Clase | Bypass de redirección HTTPS / suplantación de IP-host |
| Alcance | Remoto (HTTP no autenticado; la app configuró trustedProxies) |
| CWE | CWE-441, CWE-346 |
| CVSS | Alto: 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N |
| Producto | CakePHP |
| Afectado | 5.4.2 (887b641de9f7aba06071f98f17edcbc573cbcf63) |
| Auth | ninguna. La app configuró HttpsEnforcerMiddleware trustedProxies |
| Licencia | GNU Affero GPL v3.0 |
| Lab | solo 127.0.0.1 |
Requiere una app que haya habilitado trustedProxies (típico de la aplicación de HTTPS mediante proxy inverso). No necesita conectarse desde una IP de proxy listada.
| Privilegio | Método / sink | Probado en lab o inferido |
|---|---|---|
| Omitir la redirección HTTPS / ruta HSTS | GET / HTTP con X-Forwarded-Proto: https | Probado en lab. 200, scheme=https, testigo en JSON |
Suplantar clientIp() | X-Forwarded-For: 203.0.113.50 | Probado en lab. client_ip=203.0.113.50 |
Suplantar host() | X-Forwarded-Host: spoof.invalid | Probado en lab. host=spoof.invalid |
Suplantar mediante X-Real-IP | X-Real-IP: 198.51.100.9 | Probado en lab. client_ip=198.51.100.9 |
Omitir ACL de IP / límite de tasa basado en clientIp() | Misma suplantación | Inferido. El remote_addr por defecto de RateLimitMiddleware no es este bug |
| Control negativo | Mismos encabezados reenviados en /control (sin trustedProxies) | Probado en lab. Sigue siendo 301 a https |
Cerrado sobre este remanente: trustedProxies => null por defecto; REMOTE_ADDR en sí sigue siendo la IP del puente de Docker en el lab (192.168.208.1, no la 10.0.0.1 listada). No es RCE. No es un bug de cookie-jar.
Fijé cakephp/cakephp 5.4.2. ServerRequest::setTrustedProxies():
public function setTrustedProxies(array $proxies): void
{
$this->trustedProxies = $proxies;
$this->trustProxy = true;
$this->uri = $this->uri->withScheme($this->scheme());
}
HttpsEnforcerMiddleware llama a eso siempre que trustedProxies no sea null. Las IPs listadas se usan después como un array_diff sobre la cadena XFF, no como una comprobación del par que se conecta.
Caminos equivocados ya registrados: tratar el middleware por defecto como este remanente (no lo es); llamar al x-forwarded-for de RateLimitMiddleware el mismo bug (la panadería 5.4.1 ya movió ese valor por defecto a remote_addr); afirmar que REMOTE_ADDR en sí fue suplantado. Teatro: una reverse shell.
python3 cakephp-trusted-proxies-Abraxas-Labs.py
o
cd lab
./run.sh
Composer cakephp/cakephp 5.4.2 en PHP 8.3. App mínima: / usa trustedProxies => ['10.0.0.1']; /control no. HTTP en loopback en 127.0.0.1:19430.
/ sin encabezados reenviados -> 301 https./control con proto/for/host/real-ip -> 301 https./ con X-Forwarded-Proto: https -> 200, scheme https, trust_proxy=true, REMOTE_ADDR no es 10.0.0.1./ con XFF + Host -> client_ip=203.0.113.50, host=spoof.invalid./ con X-Real-IP -> client_ip=198.51.100.9.SUCCESS cakephp-trusted-proxies pin=5.4.2 how=app remote-addr=192.168.208.1 listed-proxy=10.0.0.1 proto-bypass=200 control-redirect=301 client-ip=203.0.113.50 host=spoof.invalid x-real-ip=198.51.100.9 CAKEPHP-TRUSTED-PROXIES-WITNESS
Solo respetar los encabezados reenviados cuando REMOTE_ADDR esté en la lista de proxies de confianza (Symfony isFromTrustedProxy()). Una lista vacía no debe habilitar la confianza.
887b641de9f7aba06071f98f17edcbc573cbcf63)src/Http/ServerRequest.php · src/Http/Middleware/HttpsEnforcerMiddleware.phpGNU Affero GPL v3.0. Ver LICENSE. Solo lab en loopback. Sin garantía.