На пентесте корпоративной сети финансовой организации я наткнулся на Squid 5.7 с открытым FTP-гейтвеем на периметре. Прокси стоял с 2018 года, обновлялся когда звёзды сходились, а FTP-поддержка была включена по умолчанию - "на всякий случай". Через полтора часа после fingerprinting я уже вытаскивал из heap-памяти прокси фрагменты Authorization-заголовков чужих HTTP-запросов. Один фрагмент содержал Base64-encoded кредсы доменного пользователя.
Это CVE-2026-47729, она же Squidbleed - out-of-bounds read класса CWE-125, которая жила в коде Squid с 18 января 1997 года. Двадцать девять лет. Один пропущенный NUL-check в C-коде.
Бизнес-логика атаки: зачем атакующему FTP-парсер прокси-сервера
Прежде чем лезть в hex-дампы - зачем атакующему возиться с FTP-парсером в 2026 году? Squid Proxy стоит в shared-окружениях, через которые идёт трафик десятков и сотен пользователей одновременно. Корпоративные сети, университеты, гостиничный Wi-Fi, бортовые системы авиакомпаний. По данным Calif.io, исследователи нашли Squid в бортовом Wi-Fi самолёта - версия была десятилетней давности и, разумеется, уязвима.Атакующий с легитимным доступом к такому прокси - любой сотрудник, студент или пассажир - может заставить Squid подключиться к подконтрольному FTP-серверу. FTP-парсер допускает heap buffer overread и возвращает фрагменты чужой памяти: пароли в заголовках Authorization, session tokens, cookie, API-ключи.
По MITRE ATT&CK это Exploitation for Credential Access (T1212): эксплуатация уязвимости для получения учётных данных. Если прокси доступен из внешней сети - применим Exploit Public-Facing Application (T1190). На выходе - украденные кредсы для lateral movement. Один HTTP Basic Auth заголовок доменного пользователя конвертируется в полноценный доступ к внутренней инфраструктуре.
Red Hat оценивает CVE-2026-47729 как Moderate, CVSS v3 base score 6.5, CWE-125 (out-of-bounds read). Импакт исключительно на конфиденциальность - ни integrity, ни availability не затронуты. Но оценка 6.5 обманчива: в shared-прокси с сотней пользователей одна утечка Authorization-заголовка стоит больше, чем RCE на изолированном хосте без сетевого доступа.
Squidbleed - не RCE. Несмотря на то, что в поисковых запросах мелькает "Squid Proxy RCE уязвимость", CVE-2026-47729 не даёт выполнения кода на сервере. Но information disclosure в прокси, через который идёт трафик всей организации, - прямой путь к credential access и последующей компрометации.
Техническая суть: как strchr ломает 29 лет кода Squid
Squid умеет работать FTP-гейтвеем: клиент запрашивает
ftp://-URL через прокси, Squid подключается к FTP-серверу, выполняет LIST, парсит ответ и рендерит HTML-листинг. Проблема в том, что формат FTP-листинга никогда не был стандартизирован. Даже DJB (Daniel J. Bernstein) называл его "hard to parse with even moderate reliability" - а когда DJB говорит, что что-то сложно, значит, это действительно ад.В 1997 году в Squid добавили код совместимости с NetWare FTP-серверами. NetWare ставил четыре пробела между таймстампом и именем файла, тогда как остальные серверы использовали один. Коммит
bb97dd37a от 18 января 1997 года внёс логику пропуска пробелов - и заложил уязвимость, которая пережила три десятилетия релизов, аудитов и рефакторингов.Суть на уровне C-кода. Парсер разбирает строку FTP-листинга, выделяет поля (тип, права, владелец, размер, дата, время) и устанавливает указатель
copyFrom на позицию после таймстампа. Дальше - пропуск пробелов для NetWare:
C:
// w_space = " \t\n\r"
// Уязвимый паттерн (все версии до 7.6)
while (strchr(w_space, *copyFrom))
++copyFrom;
// Исправленный паттерн (Squid >= 7.6)
while (*copyFrom && strchr(w_space, *copyFrom))
++copyFrom;
d [R----F--] supervisor 512 Jan 16 18:53), - то *copyFrom указывает на NUL-терминатор строки. И здесь включается нюанс C11 №7.24.5.2, который мало кто из разработчиков держит в голове: strchr считает NUL-терминатор частью строки и возвращает указатель на него, а не NULL.Результат: цикл
while(strchr(w_space, *copyFrom)) не прерывается. ++copyFrom уезжает за пределы буфера. xstrdup(copyFrom) копирует всё, что лежит в соседней heap-памяти, и отдаёт клиенту как "имя файла" в HTML-листинге. На ASAN-трассе Calif.io зафиксировали чтение 4065 байт за пределами 4096-байтного региона.Исправление - два символа: проверка
*copyFrom перед вызовом strchr. Патч в src/clients/FtpGateway.cc, смержен в Squid 7.6. Сравнение с Heartbleed (CVE-2014-0160) уместно: тот же класс - buffer over-read, та же механика - чтение за пределами буфера, то же последствие - sensitive memory disclosure.Механика утечки: почему в heap-буфере чужие HTTP-запросы
Heap overread - половина истории. Вторая половина: почему в соседней памяти лежат именно чужие HTTP-запросы, а не случайный мусор.Squid управляет памятью через пулы буферов фиксированного размера с freelist-механизмом. Пулы
MEM_4K_BUF, MEM_2K_BUF и другие работают как стек: освобождённый буфер не возвращается системному аллокатору и не зануляется. Кладётся в freelist, следующая аллокация того же размера забирает его с прежним содержимым.Буфер для парсинга FTP-листинга выделяется из пула
MEM_4K_BUF (4096 байт). В Squid 7.x константа CLIENT_REQ_BUF_SZ равна 4096, и входящие HTTP-запросы клиентов аллоцируются через memAllocBuf из того же пула. Цепочка событий:- Пользователь-жертва отправляет HTTP-запрос с заголовком
Authorization: Basic dXNlcjpwYXNzd29yZA==через прокси - Squid читает запрос в буфер из
MEM_4K_BUF, обрабатывает, отпускает буфер обратно в freelist - Атакующий запрашивает
ftp://evil-ftp-server/через тот же прокси - Squid берёт буфер из freelist - тот самый, с данными жертвы - для парсинга FTP-листинга
- Короткая строка FTP-листинга перезаписывает только первые несколько десятков байт. Остальные ~4000 байт содержат данные предыдущего HTTP-запроса жертвы
- Heap overread через
strchrотдаёт эти ~4000 байт атакующему как «имя файла»
memAllocString в отдельный пул "4KB Strings". Но Squid копирует исходящий запрос в MemBuf перед форвардингом upstream-серверу. По умолчанию используется MEM_2K_BUF, однако запросы больше 2 КБ промотируются в MEM_4K_BUF. После освобождения этого буфера атакующий может занять его через spray FTP-запросов.Цепочка атаки: от fingerprinting до credential extraction
Требования к окружению
Работает если: Squid < 7.6 (или дистрибутивный пакет без бэкпорта); FTP-гейтвей включен (по умолчанию - да); порт 21 вSafe_ports ACL (по умолчанию - да); атакующий - авторизованный клиент прокси; прокси может установить TCP-соединение на порт 21 к FTP-серверу атакующего.Не работает если: FTP отключен в ACL; egress-файрвол блокирует TCP/21; Squid ≥ 7.6 или установлен дистрибутивный бэкпорт; прокси single-user (утекают собственные данные атакующего - бессмысленно).
Для воспроизведения в лабе: две VM (Squid + атакующий), минимум 2 ГБ RAM, Debian 12 с
apt install squid (поставит 5.7), FTP-сервер с кастомизируемым листингом (pyftpdlib или vsftpd с подменой баннера).Место в цепочке атаки
Recon (Shodan/Censys - поиск Squid на периметре) -> Проверка доступа (авторизация на прокси) -> Проверка FTP reachability (может ли прокси достучаться до нашего FTP) -> Эксплуатация CVE-2026-47729 -> Extraction чувствительных данных -> Lateral movement (с украденными кредами) или token hijacking.Fingerprinting уязвимых инстансов Squid Proxy
В Shodan запрос"squid" port:3128 или "squid" port:8080 возвращает тысячи результатов. Версию Squid часто выдаёт заголовок Server в HTTP-ответе или HTML-страница ошибки - ищите строку вида squid/5.7 или squid/6.12.Следующий шаг - проверка FTP-гейтвея. Через прокси отправляете запрос на произвольный публичный FTP:
curl -x http://target-proxy:3128 ftp://ftp.example.com/. Если в ответе HTML-листинг директории - гейтвей активен. Если 403 Forbidden или ERR_ACCESS_DENIED - FTP заблокирован через ACL, этим вектором не зайти.Убедитесь, что прокси может установить исходящее TCP-соединение на порт 21 к вашему FTP-серверу. Если egress-файрвол фильтрует исходящие на 21/tcp - нужен pivot или альтернативный путь.
Нюанс с версионированием: не полагайтесь только на
squid -v или баннер. Дистрибутивы бэкпортируют патчи без смены мажорной версии. Пакет squid 5.9-0ubuntu0.22.04.7 на Ubuntu 22.04 уже содержит фикс CVE-2026-47729, хотя squid -v покажет 5.9. Проверяйте через dpkg -l squid или rpm -qa squid и сверяйте с advisory дистрибутива.Эксплуатация Squidbleed: практический PoC
Атакующий поднимает FTP-сервер, который в баннере содержит строку "NetWare" (для активацииflags.skip_whitespace в парсере) и отдаёт листинг с crafted-строкой - без имени файла после таймстампа. Когда Squid парсит эту строку, указатель copyFrom попадает на NUL, цикл пропуска пробелов уезжает за границу буфера, и xstrdup копирует содержимое соседней heap-памяти.Calif.io опубликовали видео-PoC: извлечение заголовка
Authorization со страницы логина веб-приложения у другого пользователя того же прокси. На выходе во вкладке "имя файла" в HTML-листинге - фрагмент чужого HTTP-запроса. Просто вместо report.xlsx там лежит GET /api/v2/users HTTP/1.1\r\nAuthorization: Basic....Для повышения надёжности применяется spray: множественные FTP-запросы увеличивают вероятность того, что freelist выдаст буфер с "интересными" данными. На загруженном прокси с десятками активных клиентов вероятность попадания высока. На малонагруженном - придётся ждать или координировать тайминг.
Ограничения техники и предусловия
| Фактор | Влияние на эксплуатацию |
|---|---|
| HTTPS через CONNECT-туннель | Не затронут - трафик opaque, Squid не видит содержимое |
| TLS-терминация (bump/splice) | Затронут - Squid расшифровывает трафик, данные в памяти открытым текстом |
| Egress firewall блокирует TCP/21 | Эксплуатация невозможна без pivot |
| Single-user прокси | Утечка только собственных данных атакующего |
| FTP отключен в squid.conf ACL | Эксплуатация невозможна |
| Squid >= 7.6 или дистрибутивный бэкпорт | Уязвимость закрыта |
| Squid 5.x/6.x (до 7.x) | Эксплуатация сложнее: для попадания в MEM_4K_BUF нужны HTTP-запросы > 2 КБ |
| Нет NetWare-маркера в FTP-баннере | На ветке без skip_whitespace overread тоже возможен, но с другой механикой |
Главное ограничение: обычный HTTPS-трафик через
CONNECT-туннель не утекает. В средах, где 100% трафика - HTTPS, реальный импакт минимален. Но в корпоративных сетях с legacy HTTP-приложениями, внутренними сервисами без TLS и proxy-аутентификацией через Basic Auth - утечка более чем реальна. А таких сетей, поверьте, хватает.Детект и митигация CVE-2026-47729
Обнаружение эксплуатации
Вaccess.log Squid фиксирует FTP-запросы. Аномалии, которые должны триггерить расследование:- Всплеск
ftp://-запросов от одного клиентского IP - FTP-запросы к внешним IP-адресам, не входящим в whitelist корпоративных FTP-серверов
- FTP-запросы с нетипичными путями или к несуществующим хостам
grep "ftp://" /var/log/squid/access.log | awk '{print $3, $7}' | sort | uniq -c | sort -rn | head -20 - покажет топ-20 клиентов по количеству FTP-запросов с целевыми URL. Если кто-то отправил 500 FTP-запросов к внешнему IP за час - это повод копать дальше.На уровне сети: мониторинг egress-трафика на TCP/21 от IP-адреса Squid-сервера. В Zeek-логах - фильтрация
conn.log по id.resp_p == 21 с привязкой к source IP прокси.Патч и дистрибутивные бэкпорты
По данным GitHub advisory GHSA-8c37-pxjq-qwrg, уязвимость закрыта в Squid 7.6. Небольшой цирк: в публичном обсуждении была путаница между 7.6 и 7.7 - мейнтейнер Amos Jeffries сначала указал 7.6, потом поправил на 7.7, после чего Salvatore Bonaccorso из Debian подтвердил, что патч-коммит присутствует в 7.6. Ориентируйтесь на official GitHub advisory и advisory вашего дистрибутива.| Дистрибутив | Пакет | Статус |
|---|---|---|
| Debian trixie | squid 6.13-2+deb13u2 | Исправлено (DSA-6360-1) |
| Debian forky | squid 7.6-1 | Исправлено |
| Ubuntu 22.04 LTS | 5.9-0ubuntu0.22.04.7 | Исправлено |
| Ubuntu 24.04 LTS | 6.14-0ubuntu0.24.04.4 | Исправлено |
| RHEL 6, 10 | squid | Fix deferred |
| Amazon Linux 2, 2023 | squid | Pending |
Обратите внимание на RHEL: fix deferred для всех перечисленных версий. Если вы на RHEL - единственный вариант прямо сейчас - митигация через конфигурацию.
Параллельно с CVE-2026-47729 закрывается CVE-2026-50012 - heap-based buffer overflow (CWE-122, CVSS 5.5) в функции cache digest. Она требует компиляции Squid с флагом
--enable-cache-digests и доступа от доверенного пира, но если вы обновляете Squid - закрываете обе уязвимости одним действием.Немедленная митигация
Если обновление невозможно прямо сейчас - блокируйте FTP через ACL:
Код:
acl FTP proto FTP
http_access deny FTP
squid.conf перед широкими http_access allow правилами. После редактирования: squid -k parse для проверки синтаксиса, squid -k reconfigure для применения без перезапуска сервиса.Дополнительно: заблокируйте egress TCP/21 на файрволе. Chrome и Firefox давно не поддерживают FTP - для большинства организаций отключение FTP-гейтвея пройдёт незаметно.
Чеклист для передачи сисадмину
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Squidbleed - хороший пример того, как legacy-функциональность создаёт attack surface, о котором никто не вспоминает. FTP-гейтвей в Squid включен по умолчанию, порт 21 в
Safe_ports - по умолчанию, зануление freed-буферов - не реализовано. Три дефолта, которые вместе превращают прокси в источник утечки данных.Я встречаю Squid на каждом третьем внутреннем пентесте корпоративной сети, и в большинстве случаев администраторы не знают, что их прокси умеет ходить по FTP. Этот класс проблем - legacy-парсеры в C с арифметикой указателей - никуда не денется, пока жив код, написанный до появления ASAN и fuzzing-инфраструктуры.
Интересная деталь: CVE-2026-47729 нашёл не человек, а AI-модель Claude Mythos Preview, которой скормили FTP state machine Squid. Модель вычислила quirk
strchr с NUL-терминатором почти мгновенно, сославшись на точный параграф C11-стандарта. Немногие ревьюеры-люди поймали бы это за 29 лет - и не поймали.Если вы занимаетесь аудитом сетевой инфраструктуры и ещё не добавили проверку Squid FTP gateway в свой чеклист - самое время. Если хочешь разобраться в подобных network-level уязвимостях глубже, от fingerprinting до построения полной цепочки - на Codeby есть курс по сетевой безопасности, где подобные сценарии разбирают на лабораторных стендах.
Последнее редактирование модератором: