Статья CVE-2026-47729 Squidbleed: разбор Heartbleed-подобной уязвимости в Squid Proxy — от strchr до session tokens

Сетевой модуль прокси-сервера на антистатическом коврике с гравировкой CVE-2026-47729 SQUIDBLEED на алюминиевой панели. Порты RJ45 светятся голубым, на тёмной поверхности отражается фрагмент hex-да...


На пентесте корпоративной сети финансовой организации я наткнулся на 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​

1784020461637.webp

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;
Если FTP-листинг заканчивается сразу после таймстампа - без имени файла (строка вида 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 из того же пула. Цепочка событий:
  1. Пользователь-жертва отправляет HTTP-запрос с заголовком Authorization: Basic dXNlcjpwYXNzd29yZA== через прокси
  2. Squid читает запрос в буфер из MEM_4K_BUF, обрабатывает, отпускает буфер обратно в freelist
  3. Атакующий запрашивает ftp://evil-ftp-server/ через тот же прокси
  4. Squid берёт буфер из freelist - тот самый, с данными жертвы - для парсинга FTP-листинга
  5. Короткая строка FTP-листинга перезаписывает только первые несколько десятков байт. Остальные ~4000 байт содержат данные предыдущего HTTP-запроса жертвы
  6. Heap overread через strchr отдаёт эти ~4000 байт атакующему как «имя файла»
Для Squid до 7.x (например, 5.7, который Debian распространяет в стабильном релизе) механика сложнее. Входящие HTTP-запросы аллоцируются через 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​

1784020486106.webp

Обнаружение эксплуатации​

В 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 trixiesquid 6.13-2+deb13u2Исправлено (DSA-6360-1)
Debian forkysquid 7.6-1Исправлено
Ubuntu 22.04 LTS5.9-0ubuntu0.22.04.7Исправлено
Ubuntu 24.04 LTS6.14-0ubuntu0.24.04.4Исправлено
RHEL 6, 10squidFix deferred
Amazon Linux 2, 2023squidPending

Обратите внимание на 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 есть курс по сетевой безопасности, где подобные сценарии разбирают на лабораторных стендах.
 
Последнее редактирование модератором:
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🧭 Навигатор · ИБ 2026
Не знаешь, какой трек твой?
5 направлений ИБ, реальные зарплаты и точка входа для каждого — в одном треде.
JuniorSenior+
100K → 600K+ ₽ /мес
Открыть навигатор →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab