
CakePHP 5.4.2 — высокий — удалённый — прокси — trustedProxies доверяет X-Forwarded-* с любого REMOTE_ADDR
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · cakephp-trusted-proxies
Разбор: https://abraxaslabs.tech/research/cakephp-trusted-proxies
Класс: обход HTTPS-редиректа / подмена IP и Host Доступ: удалённый
CakePHP 5.4.2 (887b641) - Cake Software Foundation
HttpsEnforcerMiddleware с trustedProxies => ['10.0.0.1'] вызывает setTrustedProxies, который устанавливает trustProxy = true и никогда не сравнивает список с REMOTE_ADDR. После этого scheme(), host() и clientIp() доверяют переданным атакующим заголовкам X-Forwarded-Proto / X-Forwarded-For / X-Forwarded-Host / X-Real-IP.
Middleware по умолчанию имеет trustedProxies равным null и не включает это поведение. Уязвим документированный сценарий настройки балансировщика нагрузки. Неаутентифицированный HTTP-клиент, не являющийся указанным прокси, может обойти HTTPS-редирект и подменить IP клиента и Host.
| ID | CVE пока нет |
| Класс | обход HTTPS-редиректа / подмена IP и Host |
| Доступ | Удалённый (неаутентифицированный HTTP; приложение задало trustedProxies) |
| CWE | CWE-441, CWE-346 |
| CVSS | Высокий: 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N |
| Продукт | CakePHP |
| Затронуто | 5.4.2 (887b641de9f7aba06071f98f17edcbc573cbcf63) |
| Аутентификация | нет. Приложение задало trustedProxies в HttpsEnforcerMiddleware |
| Лицензия | GNU Affero GPL v3.0 |
| Стенд | только 127.0.0.1 |
Требуется приложение, включившее trustedProxies (типичное принудительное включение HTTPS за обратным прокси). Подключаться с IP из списка прокси не требуется.
| Привилегия | Метод / точка воздействия | Доказано на стенде или выведено |
|---|---|---|
| Обход HTTPS-редиректа / пути HSTS | GET / по HTTP с X-Forwarded-Proto: https | Доказано на стенде. 200, scheme=https, свидетельство в JSON |
Подмена clientIp() | X-Forwarded-For: 203.0.113.50 | Доказано на стенде. client_ip=203.0.113.50 |
Подмена host() | X-Forwarded-Host: spoof.invalid | Доказано на стенде. host=spoof.invalid |
Подмена через X-Real-IP | X-Real-IP: 198.51.100.9 | Доказано на стенде. client_ip=198.51.100.9 |
Обход IP-ACL / ограничения частоты, завязанных на clientIp() | Та же подмена | Выведено. Значение remote_addr по умолчанию в RateLimitMiddleware — не эта уязвимость |
| Негативный контроль | Те же forwarded-заголовки на /control (без trustedProxies) | Доказано на стенде. Всё равно 301 на https |
Закрыто по этому остатку: по умолчанию trustedProxies => null; сам REMOTE_ADDR на стенде остаётся IP моста Docker (192.168.208.1, а не указанный 10.0.0.1). Не RCE. Не уязвимость cookie-jar.
Я зафиксировал 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 вызывает это всякий раз, когда trustedProxies не равен null. Перечисленные IP-адреса позже используются как array_diff в цепочке XFF, а не как проверка подключающегося узла.
Уже зафиксированные ошибочные пути: трактовка middleware по умолчанию как этого остатка (это не так); называние x-forwarded-for в RateLimitMiddleware той же ошибкой (в 5.4.1 bakery уже перенёс это значение по умолчанию на remote_addr); утверждение, что сам REMOTE_ADDR был подменён. Театральность: reverse shell.
python3 cakephp-trusted-proxies-Abraxas-Labs.py
или
cd lab
./run.sh
Composer cakephp/cakephp 5.4.2 в PHP 8.3. Крошечное приложение: / использует trustedProxies => ['10.0.0.1']; /control — нет. Loopback HTTP на 127.0.0.1:19430.
/ без forwarded-заголовков -> 301 https./control с proto/for/host/real-ip -> 301 https./ с X-Forwarded-Proto: https -> 200, scheme https, trust_proxy=true, REMOTE_ADDR не равен 10.0.0.1./ с XFF + Host -> client_ip=203.0.113.50, host=spoof.invalid./ с 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
Доверять пересылаемым заголовкам только тогда, когда REMOTE_ADDR входит в список доверенных прокси (Symfony isFromTrustedProxy()). Пустой список не должен включать доверие.
887b641de9f7aba06071f98f17edcbc573cbcf63)src/Http/ServerRequest.php · src/Http/Middleware/HttpsEnforcerMiddleware.phpGNU Affero GPL v3.0. См. LICENSE. Только для лабораторной среды с loopback. Без гарантий.