
Безопасное обнаружение обхода аутентификации Veeam Service Provider Console CVE-2026-58073
Безопасный детектор без аутентификации для уязвимостей KB4893 в Veeam Service Provider Console (опубликовано 2026-08-04). Он отвечает на один вопрос по каждой цели, до любой аутентификации или TLS: присутствуют ли исправления KB4893 на этой консоли?
Основная пара — это цепочка. CVE-2026-58073 (CVSS 9.5) позволяет неаутентифицированному сетевому пиру имитировать подключённого агента управления и получить реальный сертификат этого агента, поскольку квитирование агента определяет авторизацию по GUID, который пир записал в свой собственный сертификат. CVE-2026-58072 (CVSS 9.0) — это произвольная запись файла, доступная после получения идентичности агента. В связке это неаутентифицированное удалённое выполнение кода на консоли, которая управляет резервными копиями каждого арендатора. То же уведомление также исправляет CVE-2026-58071 (CVSS 8.2, проксируемый API устройства как Portal Administrator) и CVE-2026-58067 (CVSS 8.7, неаутентифицированный DoS через истощение памяти). CVE-2026-58073 и CVE-2026-58072 были сообщены в Veeam через HackerOne; уведомление не называет автора сообщения.
Этот скрипт не пытается выполнить имитацию, запросить сертификат или записать файл. Он читает рекламируемое поколение протокола маршрутизатора и ничего больше.
Да. Детектор предназначен для использования в производстве и при оценке:
Connector, называющее приёмник, который не будет существовать. Никакой TLS-сеанс не
устанавливается, сертификат не предоставляется, и никогда не вызывается.SaveFilesChannelHostProxy.m_multiplexers. Приёмник не регистрируется, канал или мультиплексор не создаётся,
запись агента не затрагивается. Квитирование типа Receiver зарегистрировало бы имя; этот инструмент
никогда его не отправляет.ConnectionHub.log, каждая с именем приёмника bf-probe-<uuid4>, чтобы защитник мог отличить сканирование
от атаки. Точные строки приведены ниже.VULNERABLE только после того, как она докажет,
что является VSPC ConnectionHub (см. ниже), поэтому тихий TCP-сервис не может быть ошибочно принят за
незапатченную консоль.На каждую цель инструмент открывает два TCP-соединения и отправляет одно квитирование ConnectionHub на
каждом, называя приёмник bf-probe-<uuid4>, который не будет существовать.
При транспорте по умолчанию --transport auto цель, чей транспорт не соответствует её порту, стоит одного
дополнительного соединения: зонд с неправильным транспортом отклоняется во время квитирования, до чтения
имени приёмника, и затем правильный транспорт используется для обоих реальных зондов. Зафиксируйте
--transport direct или --transport gateway, чтобы ограничиться ровно двумя соединениями — это стоит
сделать, если вы указали количество соединений в запросе на изменение.
Изменение состояния на сервере: нет. Путь кода Connector выполняет поиск по словарю в
ChannelHostProxy.m_multiplexers, не находит совпадения и возвращает ошибку. Приёмник не регистрируется,
мультиплексор или канал не создаётся, TLS-сеанс не устанавливается, запись агента не затрагивается. Этот
инструмент никогда не отправляет квитирование типа Receiver — именно оно зарегистрировало бы имя.
Записи журнала записываются в
%ProgramData%\Veeam\Veeam Availability Console\Log\Server\ConnectionHub.log. Дословно с живого
ConnectionHub 9.2.1.33875, с обрезанными временными метками и JSON области действия:
зонд 1 (версия 6), и запатченные, и незапатченные сборки:
[INFO] ChannelHostProxy: Accept connection begin {"RemoteEndPoint":"<ip>:<port>","Line":"1"}
[INFO] ChannelHostProxy: Accept connection end {"RemoteEndPoint":"<ip>:<port>","Line":"2",...}
[WARN] ChannelHostProxy: Cannot connect transmitter. Requested receiver not found
(receiver name:bf-probe-<uuid>) {"RemoteEndPoint":"<ip>:<port>","Line":"3",...}
зонд 2 (версия 7), только запатченные сборки:
те же три строки
зонд 2 (версия 7), незапатченные сборки:
[INFO] ChannelHostProxy: Accept connection begin
[WARN] ChannelHostProxy: Handshake failed. Reason:Unsupported client version "7"
[INFO] ChannelHostProxy: Accept connection end
Два соединения, шесть строк, никаких других записей и никакого изменения состояния — подтверждено на живом хосте.
Литеральная строка bf-probe- в ConnectionHub.log идентифицирует трафик этого инструмента, поэтому
защитник может его атрибутировать, а команда сканирования — доказать, что она отправила. Измените
RECEIVER_PREFIX в исходном коде, если вам нужен другой маркер.
Маршрутизатор агентов управления ConnectionHub читает квитирование клиента до любой аутентификации или TLS,
и Request.Read проверяет рекламируемую клиентом версию протокола на соответствие жёстко заданному диапазону.
Исправление расширило этот диапазон в той же сборке, которая исправила CVE:
| Сборка | Проверка | Принимает |
|---|---|---|
<= 9.2.1.33875 (уязвимая) | (uint)(versionByte - 3) <= 3 | 3, 4, 5, 6 |
>= 9.3.0.35057 (запатченная) | (uint)(versionByte - 3) <= 4 | 3, 4, 5, 6, 7 |
Таким образом, квитирование с рекламой версии 7 — это чистый бинарный дискриминатор. Детектор отправляет два зонда на цель в этом порядке не случайно (обнаружение транспорта может добавить третий — см. ниже):
| Зонд | Рекламирует | Назначение |
|---|---|---|
| 1 | версия 6 | Должен вернуть Requested receiver not found, доказывая, что цель действительно является VSPC ConnectionHub |
| 2 | версия 7 | Ответ означает PATCHED; тишина означает VULNERABLE |
Без шлюза первого этапа тишина в зонде 2 также соответствует любому тихому TCP-сервису в интернете, и брандмауэры сообщались бы как уязвимые консоли Veeam.
Он работает по обоим путям, которые использует агент управления:
| Транспорт | Порт | Доступность |
|---|---|---|
| Напрямую к ConnectionHub | 9999 | обычно внутренний |
| Через шлюз Veeam Cloud Connect | 6180 | интернет-ориентированный по замыслу |
Путь через шлюз требует пролога ретрансляции, которого не должно быть на прямом пути, поэтому зонд 1
дополнительно выполняет обнаружение транспорта. При транспорте по умолчанию --transport auto он пробует
один транспорт, и если шлюз отпечатка не проходит, пробует другой. Тот, который проходит, фиксируется,
и зонд 2 использует его повторно — смешанный файл целей не требует аннотации для каждого хоста.
Фиксация критически важна. Если бы зонд 2 мог повторить попытку на другом транспорте, тишина больше не была
бы связана с проверкой версии, а только с «один из двух байтовых путей не ответил» — именно так создаётся
ложное VULNERABLE.
Какой транспорт пробуется первым, определяется портом, и это не косметика — два несоответствия завершаются с очень разной скоростью:
| Несоответствие | Как это читает удалённая сторона | Стоимость |
|---|---|---|
| Пролог ретрансляции → прямой хаб | int16 метаданных hostType 44 / versionByte 0, не проходит проверку диапазона Request.Read | закрывается за один цикл обмена |
| Прямое квитирование → шлюз | int32 длина кадра 1,012,729,346 | шлюз ждёт байты, которые никогда не приходят; сжигает полный таймаут |
Поэтому auto начинает с сервиса, которому принадлежит порт: шлюз первым на 6180, прямой — везде
остальное. Это сохраняет обычный случай на одной попытке и убирает дорогое несоответствие с быстрого пути.
Зонд, которому вообще не удаётся открыть TCP, завершается без попытки второго транспорта, поэтому мёртвые
хосты в широком сканировании стоят одного таймаута, а не двух.
VULNERABLE означает «исправления KB4893 отсутствуют», а не «это 9.2.1.33875». Сборки старше
9.2.1 используют ту же проверку версии, поэтому они должны сообщать протокол 6 и также сообщаться как
уязвимые (выведено из кода, а не измерено — см. Ограничения), но инструмент не может отличить 9.2.1 от
9.1 или 8.1. Подтвердите точную сборку в интерфейсе консоли, если она вам нужна.
# один хост (по умолчанию TCP/9999)
./cve_2026_58073_check.py vspc.example.com
# явный порт, несколько хостов
./cve_2026_58073_check.py vspc.example.com:9999 10.0.0.5
# сканирование списка, одна цель на строку (комментарии '#' допускаются), компактный вывод
./cve_2026_58073_check.py -f targets.txt --brief
# машиночитаемый вывод для конвейеров
./cve_2026_58073_check.py -f targets.txt --json > results.json
# шлюз Veeam Cloud Connect — транспорт ретрансляции определяется автоматически
./cve_2026_58073_check.py cc-gw.example.com:6180
# зафиксировать транспорт, чтобы пропустить обнаружение (порт тогда по умолчанию 6180)
./cve_2026_58073_check.py --transport gateway cc-gw.example.com
# проверить кодеки провода без доступа к сети
./cve_2026_58073_check.py --self-test
| Флаг | Описание |
|---|---|
targets | Один или несколько HOST[:PORT] (порт по умолчанию 9999, или 6180 с --transport gateway) |
-f, --targets-file FILE | Читать цели из файла (одна на строку; комментарии #) |
--transport {auto,direct,gateway} | Как достичь ConnectionHub. auto (по умолчанию) определяет его для каждой цели; gateway добавляет пролог ретрансляции Cloud Connect и устанавливает порт по умолчанию 6180 |
-p, --port PORT | Переопределить порт по умолчанию |
--timeout SECS | Таймаут на зонд (по умолчанию: 8) |
--workers N | Одновременные цели (по умолчанию: 16); вывод остаётся в порядке ввода |
-b, --brief | Одна выровненная строка на цель — идеально для сканирования многих хостов |
--json | Выдавать структурированный JSON, включая каждый отправленный зонд на цель |
--no-color | Отключить цветной вывод (также учитывает NO_COLOR и не-TTY) |
--self-test | Проверить кодеки провода .NET и выйти; без доступа к сети |
Незапатченная консоль (вывод по умолчанию из двух строк). Маркер [!] и VULNERABLE отображаются
красным на TTY:
$ ./cve_2026_58073_check.py vspc.example.com
[!] vspc.example.com:9999: VULNERABLE [protocol-7-rejected]
ConnectionHub rejects protocol 7 but accepts 6, so the KB4893 fixes are absent (<= 9.2.1.33875)
Запатченная консоль:
$ ./cve_2026_58073_check.py patched.example.com
[+] patched.example.com:9999: PATCHED [protocol-7-accepted]
ConnectionHub accepts protocol 7, so the KB4893 fixes are present (>= 9.3.0.35057)
Цель через шлюз с автоматически определённым транспортом ретрансляции. Суффикс (gateway) называет
транспорт, по которому был вынесен вердикт:
$ ./cve_2026_58073_check.py cc-gw.example.com:6180
[!] cc-gw.example.com:6180 (gateway): VULNERABLE [protocol-7-rejected]
ConnectionHub rejects protocol 7 but accepts 6, so the KB4893 fixes are absent (<= 9.2.1.33875)
Сканирование инфраструктуры, одна выровненная строка на хост (--brief). Код выхода 1, если любой
хост VULNERABLE, иначе 0 — удобно в скриптах:
$ ./cve_2026_58073_check.py -f targets.txt --brief; echo "exit: $?"
VULNERABLE vspc.example.com:9999 protocol-7-rejected
PATCHED patched.example.com:9999 protocol-7-accepted
UNAFFECTED fileserver.example.com:9999 not-vspc
ERROR unused.example.com:9999 unreachable
exit: 1
Машиночитаемый вывод для конвейеров (--json). Каждый зонд включён для каждой цели, поэтому вывод
можно заново вывести из доказательств, а не принимать на веру. transport — это тот, по которому был
вынесен вердикт, и каждый зонд несёт использованный транспорт — поэтому для автоматически определённой цели
будет показана и отклонённая попытка:
$ ./cve_2026_58073_check.py vspc.example.com --json
[
{
"target": "vspc.example.com:9999",
"host": "vspc.example.com",
"port": 9999,
"transport": "direct",
"verdict": "VULNERABLE",
"reason": "protocol-7-rejected",
"detail": "ConnectionHub rejects protocol 7 but accepts 6, so the KB4893 fixes are absent (<= 9.2.1.33875)",
"protocol_version": 6,
"affected_cves": [
"CVE-2026-58073",
"CVE-2026-58072",
"CVE-2026-58071",
"CVE-2026-58067"
],
"probes": [
{
"version_byte": 6,
"transport": "direct",
"connected": true,
"responded": true,
"status": "Error",
"message": "Cannot connect transmitter. Requested receiver not found (receiver name:bf-probe-b7c40be0-e2e8-41dc-9fc3-cbbd7345954a)",
"error": ""
},
{
"version_byte": 7,
"transport": "direct",
"connected": true,
"responded": false,
"status": "",
"message": "",
"error": ""
}
]
}
]
| Вердикт | Тег причины | Значение |
|---|---|---|
VULNERABLE | protocol-7-rejected | Подтверждённый VSPC ConnectionHub, который принимает протокол 6 и отклоняет 7. Исправления KB4893 отсутствуют (<= 9.2.1.33875). |
PATCHED | protocol-7-accepted | Подтверждённый VSPC ConnectionHub, который принимает протокол 7. Исправления KB4893 присутствуют (>= 9.3.0.35057). |
UNAFFECTED | not-vspc | Принял TCP, но не ответил на допустимое квитирование ConnectionHub ни на одном испробованном транспорте, поэтому это не VSPC ConnectionHub. |
INCONCLUSIVE | unexpected-reply | Ответил на зонд отпечатка чем-то иным, кроме Requested receiver not found. |
INCONCLUSIVE | inconclusive-discriminator | Прошёл шлюз отпечатка, затем ответил на зонд версии 7 способом, который не является ни проходом, ни провалом — или второе соединение полностью не удалось. Повторите попытку. |
ERROR | unreachable | Не удалось подключиться, или шлюз Cloud Connect отказал в прологе ретрансляции на первом испробованном транспорте (что при auto означает любую цель на порту 6180). |
| Код | Значение |
|---|---|
0 | Ни одна цель не была VULNERABLE |
1 | По крайней мере одна цель VULNERABLE |
2 | Ошибка использования (неверные аргументы / нечитаемый файл целей) |
--transport auto; зафиксируйте --transport direct, чтобы полностью
исключить непроверенный путь из сканирования.VULNERABLE говорит о состоянии патчей, а не о том, эксплуатировал ли
кто-то консоль. Эксплуатация оставляет свои собственные следы в журналах консоли как на запатченных, так
и на незапатченных сборках; ищите их отдельно.Обновитесь до Veeam Service Provider Console 9.3.0.35057 или новее (KB4893). Все четыре проблемы исправлены в одной сборке, и обратного портирования для 9.2.x нет, поэтому устранение — это обновление версии, а не горячий фикс.
Две вещи обновление не делает. Оно не ограничивает, кто может достичь TCP/9999, который должен отвечать только подсетям, где живут ваши агенты управления. И оно не отзывает сертификат агента, уже выданный консолью, включая выданный атакующему, пока она была незапатченной. Если вы найдёте доказательства эксплуатации, откройте обращение в службу поддержки Veeam за рекомендациями по скомпрометированным сертификатам агентов: их ротация не является документированной процедурой, и сертификаты, которыми вы можете управлять на портале, — это не тот CA, который подписывает сертификаты агентов.
Этот код распространяется по лицензии MIT.
Использование этого инструмента для атак на цели без предварительного взаимного согласия незаконно. Ответственность за соблюдение всех применимых местных, государственных и федеральных законов лежит на конечном пользователе. Разработчики не несут ответственности и не отвечают за любое неправильное использование или ущерб, причинённый этой программой.