GhostMail: как письмо о стажировке украло всю почту за 90 дней — а ведь жертва просто открыла сообщение

GhostMail: как письмо о стажировке украло всю почту за 90 дней — а ведь жертва просто открыла сообщение

Кликнул на сообщение — потерял все пароли, токены 2FA и три месяца переписки.

image

Фишинговые атаки на веб-почту обычно строятся по знакомой схеме: вложение, ссылка, макрос, загрузчик. В новой кампании против украинского госучреждения злоумышленники обошлись вообще без всего перечисленного. Вредоносный код спрятали прямо в HTML-теле письма, а запуск начинался в тот момент, когда жертва просто открывала сообщение в уязвимой версии Zimbra.

Атаку обнаружили специалисты Seqrite Labs. Получателем судьбоносного письма стал сотрудник Государственного гидрографического агентства, которое отвечает за навигационное, морское и гидрографическое обеспечение судоходства и относится к критической инфраструктуре.

Приманка выглядела буднично и потому особенно опасно. Письмо, написанное на украинском языке, маскировалось под фишинг с запросом о стажировке. Отправитель представлялся студентом четвертого курса Национальной академии внутренних дел и вежливо спрашивал, нет ли у адресата подходящих контактов или вакансий. В конце добавлялось извинение на случай, если сообщение попало не по адресу. Такой прием давно известен в фишинге: безобидный тон снижает настороженность и заставляет воспринимать письмо как обычную рабочую переписку.

На первый взгляд в письме не было ничего тревожного. Исследователи не нашли вредоносных вложений, внешних ссылок или офисных документов с макросами. Вся цепочка атаки находилась внутри HTML-разметки одного сообщения. Код прятался в скрытом блоке div со стилем display:none и представлял собой крупный фрагмент JavaScript в кодировке Base64. Дополнительно применялся обход фильтрации через конструкцию с CSS-директивой @import, встроенной в имена тегов и атрибутов. Для простых средств проверки такой фрагмент выглядел как сломанная разметка, но браузер в итоге собирал его в исполняемый сценарий.

Технически атака опиралась на уязвимость XSS в Zimbra Collaboration Suite. Проблема связана с недостаточной очисткой HTML-содержимого, в том числе при обработке специально подготовленных конструкций с @import и другими векторами внедрения сценариев. Уязвимость уже исправили в ZCS 10.0.18 и 10.1.13 еще в ноябре 2025 года, но атака показала, что не все инсталляции обновились вовремя. Важная деталь: срабатывание требовало, чтобы жертва открыла письмо именно в классическом веб-интерфейсе Zimbra, где вредоносная разметка выполнялась в контексте активной сессии.

После открытия письма сценарий запускался в браузере почти незаметно для пользователя. Первая стадия представляла собой загрузчик на JavaScript. Он проверял, не был ли вредоносный модуль уже внедрен в страницу, затем декодировал полезную нагрузку через atob(), выполнял операцию XOR с ключом twichcba5e и подгружал финальный код в верхний документ страницы. Такой прием давал вредоносному модулю доступ к кукам, localStorage и правам того же источника, что и у самой веб-почты. Проще говоря, сценарий получал почти те же возможности, что и открытая у жертвы Zimbra-сессия.

Вторая стадия уже работала как полноценный браузерный стилер. Код запускался прямо в памяти браузера и собирал учетные данные, SOAP-токены сессии, резервные коды двухфакторной аутентификации, содержимое ящика, вложения, куки и другую чувствительную информацию. Для каждой жертвы создавался отдельный 12-символьный идентификатор, который использовался во всех запросах к командному серверу. В качестве центра управления исследователи указали домен zimbrasoft[.]com[.]ua. Если какой-либо этап завершался ошибкой, вредоносный код отправлял на сервер сообщение с названием стадии, текстом ошибки и трассировкой, чтобы оператор сразу видел, где именно цепочка дала сбой.

Отдельный интерес представляет работа с внутренним API Zimbra. Вредоносный код использовал SOAP-запросы к адресу /service/soap/, то есть к штатному интерфейсу самой почтовой системы. Для подтверждения запросов он подставлял украденный токен защиты от межсайтовой подделки запросов, который Zimbra в классическом интерфейсе хранит в localStorage в открытом виде. Благодаря этому обращения выглядели как нормальная активность пользователя внутри веб-почты. Если один из SOAP-запросов отклонялся, обертка просто возвращала null и позволяла остальным операциям продолжаться параллельно.

Вывод данных был организован сразу по двум каналам: через HTTPS и через DNS. Для передачи по DNS значения кодировались по схеме RFC 4648 Base32, разбивались на куски по 60 символов и превращались в имена поддоменов. Такой путь полезен злоумышленникам в сетях, где обычный веб-трафик фильтруется строже, а DNS-запросы проходят свободнее. Более крупные объекты, например полные конфигурационные дампы, сериализовались как двоичные данные и отправлялись по HTTPS на путь /v/d с заголовком X-Filename. Для коротких сообщений, маяков и служебных событий использовался путь /v/p. В результате один и тот же фрагмент мог уходить сразу двумя путями: DNS помогал в ограниченных сетях, HTTPS сохранял полные данные, если канал был доступен.

Вредоносный код запускал сразу девять параллельных задач через Promise.all. Такой подход нужен, чтобы успеть собрать максимум, даже если пользователь быстро закроет вкладку. Одна функция отправляла стартовый маяк на сервер управления. Другая собирала почтовые адреса и данные учетных записей, сначала пытаясь вытащить их из встроенных переменных страницы, а затем запрашивая через GetIdentitiesRequest. Отдельный модуль снимал отпечаток клиентской среды и через GetInfoRequest запрашивал полный набор параметров сервера и учетной записи, включая версию Zimbra, квоту ящика, настройки и имя узла. Итог сохранялся как JSON-файл с аналитикой.

Одна из самых опасных функций вытаскивала резервные коды двухфакторной аутентификации через GetScratchCodesRequest. Такие коды предназначены для экстренного входа, когда у пользователя нет второго фактора под рукой. Если злоумышленник получает их, смена пароля уже не всегда спасает: часть защитных барьеров можно обойти и позже. Каждый код отправлялся отдельно через DNS.

Еще один модуль создавал пароль приложения через CreateAppSpecificPasswordRequest. Zimbra позволяет выпускать отдельные пароли для внешних клиентов и сервисов. В исследуемом образце новый постоянный пароль создавался под именем ZimbraWeb. Проблема в том, что такой секрет часто переживает обычную смену основного пароля. Для атакующего это удобный способ закрепиться в ящике надолго и заходить позже по IMAP или API, даже если жертва уже заметила неладное.

Также вредоносный код собирал данные о подключенных мобильных устройствах через GetDeviceStatusRequest из пространства имен urn:zimbraSync. Ответ включал идентификаторы устройств, типы, состояние синхронизации и другие полезные детали. Для злоумышленников это не просто техническая справка, а профиль жертвы и задел для дальнейших атак уже на мобильный контур. Кроме того, через GetOAuthConsumersRequest сценарий выгружал список сторонних OAuth-приложений, имеющих доступ к ящику. Так оператор получал картину внешних сервисов, связанных с учетной записью, и понимал, через какие платформы еще можно двигаться дальше.

Отдельная техника нацеливалась уже не на Zimbra, а на браузер. В страницу незаметно внедрялись два скрытых поля формы с атрибутами autocomplete="username" и autocomplete="current-password". Затем код ждал пять секунд, чтобы менеджер браузера успел автозаполнить значения. После этого содержимое считывалось, отправлялось на сервер и внедренные элементы удалялись. Для этого шага даже не нужен токен Zimbra, потому что атака работает на уровне браузера и полагается на привычку менеджеров паролей автоматически подставлять сохраненные данные.

Еще один модуль тихо включал IMAP через ModifyPrefsRequest, выставляя настройку zimbraPrefImapEnabled в TRUE. Смысл здесь предельно прагматичный: после создания пароля приложения злоумышленнику нужен удаленный протокол, через который можно читать почту в обычном клиенте и продолжать слежение за ящиком без веб-интерфейса. Включение IMAP превращало разовую компрометацию во вполне устойчивый доступ.

Самая тяжелая и, вероятно, самая ценная часть атаки связана с архивной выгрузкой переписки за 90 дней. Модуль sendArchives перебирал дни от 0 до 89 и для каждого дня скачивал всю нежелательную не помеченную как спам почту через встроенную точку экспорта Zimbra /home/~/?fmt=tgz. Каждый суточный архив сразу отправлялся на сервер. Для современных браузеров применялась потоковая передача через ReadableStream без буферизации в памяти. Для старых использовался буферизованный режим с ограничением в 500 МБ. При этом в localStorage сохранялись контрольные ключи вида zd_comp_YYYY-MM-DD, чтобы при повторном открытии вкладки уже выгруженные дни не передавались заново. На один день отводился тайм-аут в 24 часа, то есть вкладка могла висеть и качать архивы очень долго, пока пользователь ее не закроет.

Исследователи пишут, что домен командного сервера создали 20 января 2026 года, буквально незадолго до рассылки. В инфраструктуре уже заметили по меньшей мере два сгенерированных домена: js-l1wt597cimk[.]i[.]zimbrasoft[.]com[.]ua и js-26tik3egye4[.]i[.]zimbrasoft[.]com[.]ua. Письмо пришло 22 января 2026 года, а по данным заголовков было отправлено через инфраструктуру, связанную с Национальной академией внутренних дел. Исследователи предполагают, что учетная запись отправителя, скорее всего, уже была скомпрометирована. Дополнительный штрих: на момент первоначального обнаружения образец не имел срабатываний на VirusTotal.

В отчете отдельно упоминаются ранее задокументированные операции APT28, APT29 и TA473 против Zimbra и других веб-почтовых платформ в Восточной Европе. При этом атака GhostMail ближе всего сопоставляется с активностью APT28. Seqrite Labs указывает на пересечения с Operation RoundPress и с вредоносной логикой SpyPress.ZIMBRA, где тоже использовались SOAP-запросы к API Zimbra и выгрузка содержимого ящика. О находке уже сообщили CERT-UA.

История GhostMail хорошо показывает, как меняется сама логика почтовых атак. Злоумышленникам уже не всегда нужен исполняемый файл на диске, макрос в документе или отдельный загрузчик. Если веб-почта уязвима, весь набор действий можно выполнить прямо в браузере, внутри активной сессии пользователя, используя штатные возможности платформы против нее самой. Для защитников отсюда следуют вполне конкретные выводы: обновлять Zimbra без задержек, жестко фильтровать HTML-содержимое в веб-почте и внимательно отслеживать аномальные SOAP-запросы, неожиданные включения IMAP, создание паролей приложений и массовый экспорт почтовых архивов.