
Описание и код для CVE-2025-11492, CVE-2025-11493 - RCE в ConnctWise Automate RMM через атаку злоумышленника посередине
В ходе пентеста я обнаружил несколько уязвимостей в агенте ConnectWise Automate для удалённого мониторинга и управления (RMM). ConnectWise используется многими поставщиками управляемых услуг (MSP) для управления и мониторинга клиентских устройств. Эти уязвимости позволяли удалённо выполнять код, если злоумышленник мог организовать атаку типа «злоумышленник посередине» (Adversary-in-the-Middle, AiTM), или могли быть использованы для локального повышения привилегий и скрытого закрепления, если злоумышленник получал возможность выполнять код или физический доступ к устройству, на котором работает агент ConnectWise Automate.
Уязвимости были сообщены ConnectWise 20 августа 2025 года. ConnectWise присвоила идентификаторы CVE и выпустила патч в версии 2025.9 16 октября 2025 года.
Бюллетень ConnectWise:
Идентификаторы CVE:
2025.9 и публикует бюллетень безопасности и CVE.Я ценю быструю реакцию ConnectWise, их совместный подход к устранению уязвимостей и готовность участвовать в обсуждении наилучших способов классификации и устранения.
Классификация этих уязвимостей оказалась интересной задачей. Хотя переход на HTTPS решает практически все сценарии, описанные в этом отчёте, было очевидно, что изначально это был дизайнерский выбор (поддержка HTTP) для повышения надёжности связи агента с сервером. Схема шифрования, видимо, частично учитывала / пыталась смягчить риск AiTM, но применялась непоследовательно. Исследование этого включало попытки классифицировать, является ли слабостью сам HTTP или отсутствие шифрования поверх HTTP, а также защита от повторного воспроизведения, проверка плагинов и т.д. — всё это были отдельные уязвимости. В какой-то момент ConnectWise рассматривала 5+ отдельных CVE для разных аспектов уязвимостей.
Кроме того, масштаб и вектор атаки менялись в зависимости от того, рассматривалась ли уязвимость с точки зрения AiTM (например, Wi-Fi в кофейне) или с точки зрения LPE / физического доступа. Альтернативный подход — рассматривать каждый сценарий как отдельную уязвимость, например, AiTM RCE, LPE, захват постоянного доступа и т.д.
Ещё один вывод: даже в 2025 году мы всё ещё испытываем трудности с эффективной передачей файлов :D (почтовая безопасность не любила, когда я отправлял .dll-файлы или .zip-архивы с ними).
Этот отчёт публикуется после выпуска ConnectWise патча и раскрытия CVE, а также с их согласием, что такое раскрытие не наносит вреда их пользователям. Более того, я считаю, что публичное раскрытие этих уязвимостей и мер по их смягчению поможет другим вендорам и специалистам по безопасности лучше понять и снизить риски как в ConnectWise Automate, так и в других RMM-системах.
Содержание предназначено только для законных, авторизованных целей исследования безопасности и обучения. Несанкционированное использование этой информации для компрометации систем, сетей или данных незаконно и неэтично. Содержание предоставляется «как есть» без каких-либо гарантий. Автор(ы) отказываются от любой ответственности за ущерб, возникший в результате использования или неправильного использования этой информации.
Если вы используете этот код или информацию для дальнейших исследований, практикуйте ответственное раскрытие, сообщая о любых обнаруженных уязвимостях соответствующим вендорам.
Помимо отчёта ниже, этот репозиторий содержит PoC-код для демонстрации уязвимостей. См. automate_server/README.md для получения информации о реализации поддельного сервера и инструкциях по использованию.
Этот код также может быть использован для проведения дальнейших (этичных) исследований безопасности ConnectWise Automate.
Следующий отчёт (или его версия, близкая к оригиналу) и PoC-код на Python из этого репозитория были предоставлены ConnectWise вместе с рекомендованными мерами смягчения.
Удалённый раздел мер смягчения содержит более подробную информацию об изменениях, которые могут быть внесены в агент Automate для его усиления несколькими способами против этих уязвимостей.
Поскольку некоторые из этих изменений всё ещё рассматриваются ConnectWise, этот раздел был удалён из данного публичного раскрытия.
Агент ConnectWise Automate для удалённого мониторинга и управления (RMM) (протестирован на последней версии на август 2025 года, строка версии 250.252) уязвим для удалённого выполнения кода по сети в определённых конфигурациях. Если агент настроен на использование незашифрованного HTTP-транспорта (в качестве основного или резервного) для своего Server Address и злоумышленник может выполнить атаку типа «злоумышленник посередине» (AiTM), то он может удалённо выполнить код от имени SYSTEM. Такая конфигурация наблюдалась в реальных условиях у нескольких поставщиков управляемых услуг (MSP).
Эксплуатация также возможна, если злоумышленник получает физический доступ к устройству без прав администратора или может иным образом подключить устройство к контролируемой злоумышленником сети (т.е. уязвимость может использоваться как локальное повышение привилегий). Хотя Automate использует систему шифрования для шифрования и проверки большинства RMM-команд, его система плагинов не имеет адекватной защиты и остаётся подверженной удалённому выполнению кода.
Реализуя собственный сервер, имитирующий управляющий сервер Automate, можно принудить агент Automate загрузить и выполнить вредоносный плагин.
Скомпрометированный агент также может служить привлекательной формой закрепления. Используя RCE для извлечения симметричных ключей шифрования агента, собственный сервер может отправлять произвольные команды агенту по стандартному каналу RMM. В сценарии AiTM это позволяет злоумышленнику выполнять произвольные RMM-команды, включая извлечение файлов, дамп учётных данных, выполнение команд и изменение конфигурации. Злоумышленник также может изменить Server Address RMM на свой собственный сервер, обеспечивая скрытое закрепление даже после завершения AiTM. В качестве альтернативы, RCE может быть использован для непосредственного выполнения системных команд.
Server Address, включающий конечную точку http://. Уязвимые конфигурации наблюдались у двух разных MSP (фактические домены и IP-адреса MSP заменены):
https://automate.msp-one.com|http://automate.msp-one.comhttps://msp.msp-two.com|http://msp.msp-two.com|http://12.346.6.78http:// используется как резервная, если соединение https:// не удаётся, но злоумышленник может смоделировать это, блокируя https.Агент Automate может быть настроен на использование URL http:// в качестве адреса сервера. Эта конфигурация, вероятно, устанавливается скриптом/пакетом установщика, но может быть проверена по ключу реестра HKLM\SOFTWARE\LabTech\Service\Server Address.

Использование как HTTPS, так и HTTP конечных точек, разделённых вертикальной чертой |, гарантирует, что в теории, если соединение HTTPS столкнётся с проблемой, агент Automate переключится на HTTP-соединение.
Если злоумышленник получает доступ «злоумышленник посередине» (AiTM) к сетевому трафику между агентом Automate и сервером, он может намеренно нарушить соединение HTTPS, заставляя его переключиться на HTTP. Это позволяет злоумышленнику перехватывать, отслеживать и изменять трафик, которым обмениваются агент и сервер. Затем злоумышленник может выполнить обратное проксирование трафика на https://automate.msp-one.com, что приведёт к «нормальной работе» агента, но с возможностью прослушивания данных. Кроме того, он может вставлять или изменять ответы или даже настроить полностью поддельный сервер Automate, отвечающий на запросы агента Automate.
Это было достигнуто путём настройки «вредоносной» точки доступа Wi-Fi (hostapd, dnsmasq, IP-пересылка + NAT) и использования правил iptables для перенаправления трафика и скрипта mitmproxy для обратного прокси.

Другие, более чувствительные данные, включая запущенные программы, полную конфигурацию сети и пути к документам, иногда наблюдались в ответах агента Automate.
iptables -t nat -A PREROUTING -i wlx90916440139a -p tcp --dport 80 -j REDIRECT --to-port 8080 iptables -A FORWARD -i wlx90916440139a -p tcp --dport 443 -j DROP
#### mitmproxy script:```python
# run with AiTMweb --mode transparent@8080 -s automate_AiTM.py
def request(flow: http.HTTPFlow):
if flow.request.pretty_host == 'automate.msp-one.com':
flow.request.url = 'https://automate.msp-one.com' + flow.request.path
ZTNA решения могут немного усложнить этот перехват, но они были надёжно обойдены с помощью дополнительных скриптов mitmproxy, которые условно обнаруживают и блокируют ZTNA, что приводит к возврату к HTTP без туннелирования.
Агент Automate использует собственный протокол поверх HTTP для связи с сервером.
RMM-агент на устройстве периодически отправляет HTTP(S) запросы к конечной точке сервера /LabTech/agent.aspx. Соответствующие типы запросов:
Обратите внимание, что непоследовательный регистр букв в путях — не опечатка; именно так агент Automate отправляет эти запросы. Все пути к конечным точкам для ясности заключены в обратные кавычки.
/LabTech/Agent.aspx?DEPS и получает XML-ответ, содержащий список файлов зависимостей, их номера версий и контрольные суммы./LabTech/Agent.Aspx?DepCheck=1&DependancyId=<id> и получает обфусцированный бинарный файл, содержащий зависимость, замаскированную под изображение (предположительно, обфускация предназначена для предотвращения блокировки загрузки контент-фильтрами)./LabTech/agent.aspx?<id>?c<CMD id>&<arg count> и получает специально упакованный ответ, содержащий данные, специфичные для команды.InitialCommandRetrieve), возврата результатов команд и выполнения чата.Конфиденциальные "удалённые команды" часто шифруются с использованием схемы шифрования на основе DES3 с собственным выводом ключа из предустановленного системного пароля и пароля компьютера. Без правильных паролей злоумышленник не может просматривать/внедрять/изменять легитимные команды, отправляемые агенту; однако ответы на команды не шифруются, и, как было замечено, часто содержат конфиденциальные данные в открытом виде, включая открытые файлы, пути, имена пользователей, установленные программы и т.д.
Проверка зависимостей (/LabTech/Agent.aspx?DEPS) и загрузка (/LabTech/Agent.Aspx?DepCheck=1&DependancyId=<id>) не шифруются и не подписываются, что означает, что злоумышленник может изменить ответ, включив в него вредоносные зависимости, которые будут загружены и загружены RMM-агентом. Если проверка зависимостей подделана с указанием другой контрольной суммы, RMM-агент выполнит повторную загрузку несовпадающего файла зависимости и загрузит его (при условии, что вновь загруженный файл соответствует поддельной контрольной сумме). Плагины представляют собой сборки .NET, реализующие определённый интерфейс, и агент Automate загружает любую сборку .NET, соответствующую ожидаемому интерфейсу плагина, а затем вызывает интерфейс плагина, что приводит к выполнению кода.
Существует второй уровень проверки загруженных зависимостей плагинов, когда агент отправляет команду cmdGetPlugins и также проверяет соответствие контрольной суммы, но эта команда не использует схему шифрования.
С помощью dnSpy удалось внедрить вредоносный код в легитимный ScreenConnectRemotePlugin.dll, используемый агентом. Был создан собственный сервер Automate с функциональностью команд DEPS, DepCheck и cmdGetPlugins. Поддельный сервер реплицировал ожидаемые плагины и зависимости, но изменил хэш для ScreenConnectRemotePlugin.dll на вычисленный хэш для вредоносно изменённого плагина. Поддельный сервер также предоставлял вредоносно изменённый ScreenConnectRemotePlugin.dll в ответ на запрос DepCheck (в обфусцированном формате поддельного изображения) и реализовывал cmdGetPlugins также с изменённым хэшем. Наконец, скрипт mitmproxy был обновлён, чтобы направлять агента Automate на поддельный сервер вместо легитимного (HTTPS).
При подключении вредоносный плагин загружается и загружается агентом. Внедрённый код извлекает "системный" и "компьютерный" пароли и отправляет их на поддельный сервер. Пароли system и computer хранятся в реестре, но декодируются сильно обфусцированной библиотекой на C# и нативном коде. Вместо извлечения значений реестра модифицированный плагин использует рефлексию для получения декодированных значений, что позволяет избежать усилий по обратному инжинирингу обфускации. Альтернативно, можно извлечь всё содержимое ключа реестра HKLM\SOFTWARE\LabTech\Service и использовать его с копией RMM-агента в контролируемой среде для извлечения паролей во время выполнения с помощью отладчика .NET.


В качестве альтернативы плагин можно использовать для непосредственного выполнения команд на уровне системы; однако извлечение секретов позволило использовать сам RMM-агент в качестве канала управления и контроля, что сделало постоянный канал незамеченным для EDR. Сохранение доступа может быть достигнуто путём обновления Server Address на сервер, контролируемый злоумышленником, который при необходимости может перенаправлять команды на легитимный сервер, чтобы устройство не отображалось как пропавшее. Дополнительную информацию см. в разделе 3. Захват управления RMM.
Ожидается, что даже если в конфигурации по умолчанию нет установленных плагинов, можно было бы скомпилировать пустой плагин (соответствующий интерфейсам C#, требуемым для плагинов) и вставить его в ответы DEPS и cmdGetPlugins для достижения того же эффекта.
Кроме того, было замечено, что сервер может возвращать "удалённую команду" под названием UpdatePlugins, которая запускает обновление плагина агентом. Поскольку команды не содержат защиты от повторного воспроизведения, если злоумышленник может наблюдать команду, отправляемую легитимным сервером, он может воспроизвести её для любых других агентов, чтобы запустить обновление. Это позволяет использовать уязвимость RCE в дополнительных сценариях, увеличивая влияние данной уязвимости.
Также было замечено, что самообновление не шифруется и не подписывается. Демонстрация удалённого выполнения кода через самообновление не проводилась, но считается, что оно также уязвимо. Вредоносное изменение самообновления было бы сложнее выполнить скрытно и несёт больший риск сломать агент Automate; однако, вероятно, аналогичный подход с внедрением кода .NET в исполняемые файлы/DLL сработает. Процесс самообновления не исследовался далее, так как RCE через плагины было достаточно и признано более надёжным.
Также возможно, что эксплуатация процесса самообновления могла бы стать жизнеспособным решением для ограничения «эксплуатируемо только при перезагрузке» (например, если можно внедрить или воспроизвести ответ, чтобы запустить самообновление).
Используя подход из раздела 2.1 для извлечения системного пароля и пароля компьютера, стало возможным создавать произвольные полезные нагрузки и ответы на "удалённые команды". Вместо полного обратного инжиниринга и повторной реализации схемы вывода ключа можно было просто импортировать LabTechCommonBase.dll и использовать Utilities.LabTechHash.ComputeHash для генерации ключа DES3 из "пароля компьютера". Используя вычисленный ключ DES и жёстко заданный IV, извлечённый из DLL, затем стало возможным отвечать агентам RMM произвольными командами.```python
# IV extracted from decompiled LabTechSecurity.cs:
# this._initializationVector = new byte[] { 240, 3, 45, 29, 0, 76, 173, 59 };
iv = [240, 3, 45, 29, 0, 76, 173, 59]
# Helper functions for pythonnet, clr_loader, clr to load LabTechCommonBase.dll into python
labtech_net.setup_paths_and_references(str((Path(__file__).parent.parent / 'LTSvc').resolve()))
from LabTechCommonBase import Utilities
labtech_hash = Utilities.LabTechHash()
labtech_hash.ComputeHash(computer_password.encode('ascii')) # Use the exfiltrated computer password
byts = bytes(labtech_hash.GetDigestBytes())
cipher = DES3.new(byts, DES3.MODE_CBC, bytes(iv))
padded_data = pad(data.encode('utf-8'), DES3.block_size)
encrypted_data = cipher.encrypt(padded_data)
return base64.b64encode(encrypted_data).decode('utf-8')
Обработчики для различных типов «Agent Command» были реализованы в поддельном сервере Automate, что позволяет ему отправлять «Remote Commands» обратно агенту. Эти команды могут использоваться для выполнения произвольного кода на устройстве, например, для загрузки и выполнения полезной нагрузки или установки сетевых туннелей на устройство (например, настройка SOCKS-прокси, который можно использовать для перемещения через доступ ZTNA устройства).
Для немедленной очистки от версии 2.1 сервер может отправить зашифрованную команду `UpdatePlugins` и предоставить исходный легитимный плагин, чтобы перезаписать вредоносно изменённый плагин. Злоумышленник всё ещё может взаимодействовать с агентом (при условии, что пароли были извлечены) и может сохранять постоянство, обновив `Server Address` на сервер, контролируемый злоумышленником.

Произвольное выполнение команд также было продемонстрировано с помощью команды `Execute` для запуска ping, которая была успешно выполнена на устройстве в контексте администратора. Это может быть предоставлено как команда `InitialCommandRetrieve` или возвращено в ответ на другие «agent commands»/проверки.```python
# Extract the RemoteCommandIDs enum from LabTechCommonBase.Constants using pythonnet
REMOTE_CMD_IDS = get_RemoteCommandIDs()
REMOTE_CMD_IDS_r = {str(v): k for k, v in REMOTE_CMD_IDS.items()}
# `register_cmd_handler` registers a command handler for the `/LabTech/agent.aspx?c<id>` endpoint.
# The string 'InitialCommandRetrieve' is mapped back to ID `36`.
# The full set of "Agent Command" and their IDs can be extracted from `LabTechCommonBase.Constants.modEnums.AgentCommandIDs`
@register_cmd_handler('InitialCommandRetrieve')
async def initial_command_retrieve(_req: dict) -> str:
cmd = '*!*'.join([
'202706506',
str(REMOTE_CMD_IDS_r['Execute']),
'!!!'.join([
'CMD.exe',
'/c ping -t -l 1337 192.168.20.2'
])
])
encrypted_cmd = encrypt(cmd)
return '|||'.join([
len_b64_gzip( # Simple helper to return '{len(data)}-{base64(gzip(data))}'
encrypted_cmd
),
# Generate common [latest-version, FILETIME(), queued command(s), MD5 hashes] encoding string expected in "agent command" responses
make_p2(),
])

Использование -l 1337 указывает ping использовать размер полезной нагрузки 1337 байт, что затем видно на втором скриншоте (1337 байт полезной нагрузки + 42 байта заголовка = 1379 байт всего) как «канарейка».
Раздел удалён из публичного раскрытия.