惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Engineering at Meta
Engineering at Meta
人人都是产品经理
人人都是产品经理
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
量子位
腾讯CDC
The Cloudflare Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
云风的 BLOG
云风的 BLOG
Vercel News
Vercel News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
The Hacker News
The Hacker News
T
The Exploit Database - CXSecurity.com
B
Blog
S
SegmentFault 最新的问题
P
Privacy & Cybersecurity Law Blog
T
Threatpost
博客园 - 聂微东
T
Tailwind CSS Blog
The Last Watchdog
The Last Watchdog
C
Check Point Blog
N
Netflix TechBlog - Medium
D
DataBreaches.Net
爱范儿
爱范儿
IT之家
IT之家
S
Secure Thoughts
M
MIT News - Artificial intelligence
NISL@THU
NISL@THU
C
Cisco Blogs
TaoSecurity Blog
TaoSecurity Blog
有赞技术团队
有赞技术团队
A
Arctic Wolf
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
P
Proofpoint News Feed
Spread Privacy
Spread Privacy
Schneier on Security
Schneier on Security
Simon Willison's Weblog
Simon Willison's Weblog
G
GRAHAM CLULEY
雷峰网
雷峰网
Project Zero
Project Zero
博客园 - Franky
H
Heimdal Security Blog
A
About on SuperTechFans
Security Latest
Security Latest
Webroot Blog
Webroot Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Hugging Face - Blog
Hugging Face - Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Мне прислали фишинг под MAX. Я разобрал ссылку и нашёл уязвимость в их API
sansmaster · 2026-05-01 · via Все публикации подряд на Хабре

«Мне тут такое фото отправили… не ты на снимках?»

Сообщение пришло поздно вечером, в обычной переписке, от знакомого, который пишет редко. К тексту приложена короткая ссылка — clk1.me/rD7P5E. Несколько секунд я смотрел на экран, прокручивая в голове два варианта.

Первый — что ему действительно скинули какое-то фото, на котором ему почудился я, и он, не разбираясь, переслал. Так бывает, особенно если человек сам не из тех, кто фильтрует входящие.

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

В пользу второго говорило сразу несколько мелочей. Сообщение было не его обычным стилем — он многоточия не ставит. Время странное — три ночи. И главное: он за два года ни разу не присылал мне ссылок без подписи, какой-нибудь «глянь как круто», «оцени». А тут — голая короткая URL, и вопрос, который, если вдуматься, специально провоцирует ткнуть. «Не ты ли на снимках» — это же мгновенный hook, ты не сможешь этого не открыть, только чтобы развеять сомнение.

Я набрал его в другом мессенджере, спросил, отправлял ли что-то такое. Он был офлайн. Так я остался один на один со ссылкой и вечером, который внезапно освободился.

Открывать на основном устройстве — нет, разумеется. Но что внутри — стало любопытно. Так начинается история, в которой одна короткая ссылка раскручивается в инфраструктуру из 179 фишинговых доменов; оператор за пять дней мигрирует через четырёх хостеров; фишинг-кит оказывается не банальным сборщиком паролей, а MITM-прокси к настоящему API мессенджера MAX; и сам MAX, получив подробный отчёт об уязвимости, молчит уже неделю.

Поехали.

Что внутри коробки

В первой комнате тёмного дома по сценарию должен лежать знакомый интерфейс. Я взял ссылку и положил её в app.any.run — это интерактивная песочница, бесплатная, без регистрации. Они открывают URL в виртуалке у себя и отдают мне видеозапись того, что показывалось, плюс полный лог HTTP-запросов, DNS-резолвов, скриншоты на каждом шаге. Удобная вещь, особенно когда не хочешь пускать что-то через себя. Бесплатные отчёты у них публичные — постоянная ссылка, доступная любому.

Цепочка простая:

clk1.me/rD7P5E   →   HTTP 302   →   maxwel.lol

Сразу скажу про clk1.me, чтобы не оставлять подвешенным: это легитимный сервис коротких ссылок. Свои terms of use, политика приватности, поддержка двадцати языков, отдельный канал жалоб complaint@clk1.me. Никакого отношения к фишеру у самого сервиса нет, как нет вины у bit.ly за то, что им тоже пользуются мошенники. Просто фишер — один из их пользователей. Им я потом написал отдельным письмом, ссылку они должны были удалить по своим правилам.

А вот maxwel.lol — это уже их домен. Открывается копия экрана входа в MAX: «Пользователь поделился с вами фото / Войдите в аккаунт, чтобы посмотреть изображение / Продолжить». Кнопка ведёт на форму ввода телефона. На первый взгляд — стандартный credential harvester.

На первый взгляд.

Кто такой maxwel.lol

Любая работа с фишинговым доменом начинается с трёх вопросов: кто его зарегистрировал, где он хостится, кто DNS. Я открыл who.is, потом ipinfo.io, потом VirusTotal — и записал в блокнот:

Domain        maxwel.lol
Created       25.04.2026
Registrar     Global Domain Group LLC (.lol — Identity Digital)
A             212.109.195.59
NS            ns1.this-is-face.dev
              ns2.this-is-face.dev
SOA contact   support.cloudns.net
TLS           Let's Encrypt
VirusTotal    0/91 — никто не флагнул

Восемь строк, и из каждой что-то понятно.

Домену двое суток. Антивирусные краулеры физически не успели его увидеть — отсюда чистый VirusTotal. Это типично для бизнес-фишеров: свежие домены под каждый прогон трафика именно потому, что они какое-то время невидимы для блокировок.

NS-сервера — собственные, в зоне .dev, под именем this-is-face.dev. Не Cloudflare, не дефолтные регистратора. Кто-то завёл свою DNS-инфраструктуру.

SOA — support.cloudns.net, болгарский DNS-провайдер ClouDNS. То есть зоны обслуживаются у них. Запомним.

IP 212.109.195.59 — Москва, ЦОД в Химках, AS29182, JSC IOT. Российский хостинг.

И вот тут стало интересно.

Сто семьдесят девять

На странице IP в VirusTotal есть вкладка Relations, а в ней — Passive DNS Replication. Это список всех доменов, которые когда-либо разрешались в этот IP. Грубо говоря, кто за последний год прятался за этим IP.

Их там было сто семьдесят девять.

Имена я смотрел минут двадцать, и постепенно картина становилась всё гаже:

max-photo.shop          max-photo.one           max-photo.online
maxpic.lol              max-phitog.lol          maxonm.lol
photomaxcheck.lol       maxfod.cc               maxphotolifes.cc
auth-id8281.cfd         openfile.cfd            open-file.shop
kraskirukids.lol        krasivyrisunok.click    krasotkagolosovanie.click
golosovanie-za-talant.lol      konkurs-golos.lol     vote-russia.sbs
2gisgolosovanie.today          ok-odnokllassniki.ru  votemax.online
rustore.this-is-face.dev       telegram-message.app
foxyvideos.lol          standoffchit.lol        carscanner.lol
news7273923.lol         news9423782.lol         maxinstos.ru
... и ещё 140+

Тематики стандартные для русскоязычного фишинга: «вам прислали фото в чате», «проголосуйте за моего ребёнка в конкурсе», «премиум-подписка», «голосование в 2GIS», «обновление RuStore», «авторизация Одноклассников», «победитель конкурса детских рисунков», «пробив человека по фото из Telegram». Под каждую тему — отдельный домен. Регистрации в дешёвых зонах: .lol, .cfd, .shop, .click, .pics, .top, .one, .sbs, .cc, .life, .digital, .online, .app. Около тридцати разных TLD.

Это не атака конкретно на меня. Это конвейер на сотни тысяч получателей в день, по парсенным и слитым базам номеров. Тебя никто не «заказывал» — твой номер просто оказался в чьей-то старой выгрузке (Сбер, СДЭК, Яндекс.Еда, ВТБ — любая из последних утечек). Друг с большой вероятностью ничего не отправлял — его аккаунт под угоном, и теперь от его имени бот шлёт приманку по списку контактов. Кто-то уже клюнул, кто-то клюнет завтра.

И нашёлся ещё один любопытный экспонат — rustore.this-is-face.dev. То есть оператор работает не только под MAX. Он параллельно держит фишинг под RuStore — российский магазин приложений, в котором сейчас публикуют гражданские сервисы. Через MAX уводят сессию мессенджера; через RuStore, видимо, пытаются устанавливать малварь под видом обновлений приложений. Размах серьёзный.

Картинка целиком

Я зашёл на VirusTotal по самому домену this-is-face.dev. Зарегистрирован он у регистратора Dynadot LLC (зона .dev принадлежит Google Registry), создан примерно месяц назад. Раньше сидел за Cloudflare, в марте 2026 переехал на собственный VPS, в апреле — ещё на один.

И самое важное — у него были сабдомены:

admin.this-is-face.dev      ← админ-панель кита
api.this-is-face.dev        ← API бэкенда
rustore.this-is-face.dev    ← RuStore-фишинг
dev.this-is-face.dev        ← дев-стенд
ns1.this-is-face.dev        ← NS-сервер 1
ns2.this-is-face.dev        ← NS-сервер 2
+ UUID-сабдомены типа 3a2add4c-5701-490c-8583-299675a06a53.this-is-face.dev

Поверх этого вырисовалась архитектура:

admin.this-is-face.dev          ← оператор сидит здесь, в админ-панели
api.this-is-face.dev            ← бэкенд кита, принимает данные с фейков
                │
                ▼
ns1/ns2.this-is-face.dev        ← собственные NS на ClouDNS (Болгария)
                │
                ▼
~179 фишинговых доменов          ← все указывают в один IP
                │
                ▼
212.109.195.59                  ← хостинг с фишинг-страницами

И ключевое: 179 доменов меняют IP одной командой в админ-панели. Оператор обновляет A-записи в зонах через ClouDNS — за минуты весь трафик уходит на новый сервер. Хостер отрубил клиента? За час оператор арендует новый VPS у любого провайдера в любой стране и переводит туда всё. Хостинг — переменная, стираемая. NS-сервера и C2-домен — постоянные. На этом и держится вся конструкция.

Это известная схема, и называется она bulletproof phishing infrastructure. F6 (бывший Group-IB) описывал её на примере панелей Teletron, Social Engineering, Wphisher — ровно те же признаки. Группа арендует или сама пишет «кит» (готовое веб-приложение для штамповки фейков), регистрирует пакет доменов, заводит свои NS, привязывает к одному IP, и через панель управляет всей фабрикой.

В этот момент я понял две вещи. Первая — это организованная коммерческая группа, не школьник. Вторая — у меня есть выходные.

Первая жалоба

Я отправил письмо хостеру abuse@webdc.ru, описав, что у него на одном IP размещены 179 фишинговых доменов одной кампании. Параллельно отписался регистратору Dynadot (через их форму), DNS-провайдеру ClouDNS, регистратору .lol (Identity Digital), и в F6 / Group-IB CERT (cert@cert-gib.ru) — у них есть прямые каналы к российским правоохранителям и к Google Safe Browsing.

К утру следующего дня 212.109.195.59 отвечал ERR_CONNECTION_TIMED_OUT. Все 179 доменов кампании, включая maxwel.lol, лежали с тайм-аутом. Хостер вырубил клиента. Я наивно обрадовался.

Через шесть часов открыл ещё раз. Все домены снова работали. DNS теперь указывал на 79.143.176.86 — Contabo GmbH, Германия. Оператор, как ни в чём не бывало, перевёл всех 179 на новый VPS. Потратил, наверное, минут двадцать.

Это и было то самое доказательство, что хостинг-абьюзы не работают. Снимаешь одну дверь — оператор открывает следующую. Реально его остановит только отзыв this-is-face.dev у Dynadot или отключение зон у ClouDNS.

Я снова отписался — теперь уже в abuse@contabo.de. Но было ясно, что цикл может повториться сколько угодно раз, и ускорить процесс через хостеров — невозможно. Тогда я сел смотреть, что внутри самого фишинг-кита.

Тут начинается странное

В DevTools (Chrome → F12 → Sources, ничего экзотического) я открыл код страницы maxwel.lol. Один inline-скрипт, ~6.5 КБ, не обфусцирован — обычный JavaScript, читается напрямую.

Ни одного внешнего URL. Никаких упоминаний Telegram, никаких mailto, никаких сторонних API. Чистый код, работающий только с собственным бэкендом:

fetch('?action=' + a, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(payload)
});

a — это phone, code, password, ping. Эндпоинты на собственном домене, никаких выносов наружу. Это значит, что в клиентском коде нет ничего, что выдаёт оператора. Контакты, Telegram-бот для уведомлений о новых жертвах, управляющая панель — всё на серверном бэкенде, наружу не торчит. Грамотно. Любой нормальный фишер так и делает.

Уже это говорит, что группа не школьная. Профессиональный кит.

И чтобы убедиться окончательно, что у них на серверной стороне — я отправил curl’ом тестовый POST-запрос на их /api/send-code с заведомо некорректным номером:

POST https://open-file.shop/api/send-code HTTP/1.1
Content-Type: application/json

{"phone":"+10000000000"}

(open-file.shop — это уже один из следующих по счёту доменов кампании; у них всех один и тот же кит, можно стучаться в любой)

Сервер ответил вот так:

{
  "error": "connect: error.phone.wrong: Не нашли этот номер, проверьте цифры",
  "ok": false
}

Я смотрел на этот ответ секунд десять.

Дело в том, что текст ошибки и формат — это дословно ответ настоящего API мессенджера MAX. Локализованное русское сообщение, код ошибки error.phone.wrong с двойной точкой, структура {error, ok} — это всё их формат. Вообще их. Кит не имитирует ответ. Он, чёрт возьми, проксирует мой запрос в реальный API MAX и возвращает мне то, что вернул бы сам MAX.

Это не сборщик паролей. Это MITM-прокси, работающий в реальном времени.

Как это работает

На минуту потребовалось переварить.

Картина оказалась такая. Жертва открывает фишинг и вводит свой номер. Кит на серверной стороне делает примерно следующее:

1. Жертва на open-file.shop вводит +7-XXX-XX-XX-XXX.
   Браузер шлёт POST /api/send-code на бэкенд кита.

2. Бэкенд кита тут же открывает соединение к НАСТОЯЩЕМУ API
   мессенджера MAX и отправляет туда тот же самый запрос
   send-code от своего серверного клиента.

3. MAX принимает запрос как легитимный (а почему он должен
   его не принять?), отправляет НАСТОЯЩИЙ SMS-код на телефон
   жертвы и возвращает бэкенду кита идентификатор сессии
   (waitToken).

4. Жертва видит у себя в SMS реальный код от MAX. Никаких
   признаков обмана: отправитель тот же, формат тот же, всё
   как при обычном входе. Жертва доверчиво вводит код в форму
   на фишинговой странице.

5. Бэкенд кита передаёт код в MAX через POST /api/sign-in
   с тем самым waitToken. MAX возвращает токен авторизованной
   сессии.

6. Атакующий получает токен. Внутри её аккаунта. Может
   читать всю переписку, рассылать сообщения от её имени,
   через интеграцию MAX ↔ Госуслуги — заходить в её ЛК
   на госуслугах.

В свежих версиях кита (а кит дописывают, версии я видел разные) появился /api/sign-in-2fa — для пользователей, у которых включён облачный пароль. Жертва вводит свой пароль на фишинге, кит проксирует его в MAX, получает в ответ авторизованную сессию. Двухфакторка не спасает. Просто потому, что она проксируется тем же способом, что и SMS.

Поведение жертвы выглядит идеально-нормальным с её стороны. Она не видит ни одного признака обмана:

— SMS приходит от штатного номера/отправителя MAX — код в SMS — настоящий, действующий — ответ сайта на ввод кода молниеносный, как в реальном приложении — форма выглядит как настоящая — ничего не дёргается, не перестраивается, не «странно тормозит»

Объяснить жертве, что это была атака — почти невозможно. Если она дошла до конца, она войдёт в свой собственный аккаунт MAX и не заметит, что параллельно в этот аккаунт уже зашёл кто-то другой.

Где здесь дыра

Уязвимость не в коде клиентского приложения MAX. И не в Android/iOS-сборках. Она — в политике публичного auth-API. И конкретно в том, что:

— нет проверки Origin / Referer на /api/send-code. Любой третий сайт может вызвать «отправь SMS на этот номер» от своего origin’а, и бэкенд это спокойно сделает — нет первичного SDK-токена. У Telegram эта проблема закрыта много лет назад через api_id/api_hash в MTProto: API не отвечает без валидного токена приложения. У MAX подобного нет, любой неаутентифицированный сервер может звать send-code — нет привязки выпущенной SMS-сессии к идентичности устройства, инициировавшего ввод (TLS JA3/JA4 fingerprint, device id, web-cookie). Поэтому код, выпущенный по запросу одного клиента, может быть «погашен» другим — нет серверного rate-limit’а по характеру источника. Бэкенд кита делает сотни запросов в день на разные номера с одного IP — паттерн, который любая anomaly-detection ловит за минуту — нет push-подтверждения в активные сессии пользователя при попытке нового входа. У Telegram, WhatsApp, Signal — есть. У MAX — нет

Любой одной из этих контрмер достаточно, чтобы класс атаки прекратил работать. У MAX нет ни одной.

CVSS v3.1 я насчитал 8.8 (Critical): AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N. Сетевая атака, низкая сложность, не требует учётки атакующего, нужен один клик жертвы — и у атакующего полный доступ к её аккаунту.

С учётом того, что MAX с 2026 интегрирован с Госуслугами через ЕСИА — это не просто угон мессенджера. Это потенциальный вход в личный кабинет Госуслуг и оформление кредитов, доверенностей, переоформление имущества от имени жертвы. Угон MAX = угон Госуслуг. Это не моё преувеличение — это прямой вывод из их же документации по интеграциям.

Кошки-мышки

Пока я готовил отчёт об уязвимости для MAX, оператор продолжал работу.

Хронология за пять дней:

Дата

IP

Хостер

Состояние

25–27.04

212.109.195.59

JSC IOT (Москва)

положили

28.04

79.143.176.86

Contabo (Германия)

положили

29.04 утром

5.8.53.90 → 5.8.51.6

PIN-DC (СПб)

положили

29.04 вечером → сейчас

85.239.144.215

DEDIK Services (Германия)

работает

Четыре хостера. Пять дней. Один и тот же оператор. Каждый раз на новый IP уходит «боевой» burner-домен (сейчас это open-file.shop), а остальные 178 он оставляет «лежать» на мёртвых IP. Это его оптимизация: подсветившиеся в антифишинг-фильтрах домены он не перевозит на свежий чистый хостинг — они бы его сразу спалили. Перевозит только один свежий, с которого сейчас идёт трафик. Остальные — пул на регенерацию, когда нынешний burner сгорит.

И ещё один штрих, который меня впечатлил. Кит начал отдавать уникальные пути для каждого посетителя. Когда ты заходишь на https://open-file.shop/, тебя редиректит на https://open-file.shop/ahz87nhpu, при следующем заходе будет https://open-file.shop/yt13n0jeh. То есть сама фишинговая форма доступна по случайной строке, выдаваемой при первом обращении. Это защита от URL-based blacklists: Google Safe Browsing работает по точному URL, а не по домену, и такие пути его обходят. Каждая жертва получает свой собственный путь к одной и той же форме.

Уровень оператора — средне-зрелая коммерческая группа. По описаниям F6 это уровень «тимы» — 5-15 человек, есть кодер, топпер (опытный «угонщик»), трафик-менеджер, обналыч. Доход топпера — от 600 тысяч до 2.5 миллионов рублей в месяц. То есть мы говорим про серьёзный криминальный бизнес.

И они знают, что делают. Когда я отправлял жалобу регистратору — они зачищали admin., api., rustore. сабдомены в NXDOMAIN, чтобы убрать следы. Когда падал хостер — они переезжали за час. Когда антифишинг-фильтры начали ловить URL https://maxwel.lol/ — они начали генерить динамические пути.

Вырубить их хостерскими жалобами нельзя в принципе. Они для того и арендуют свои NS на ClouDNS, чтобы мигрировать через любой хостер мира. Закрыть кампанию можно или через регистратора C2 (Dynadot должен отозвать this-is-face.dev), или через DNS-провайдера (ClouDNS должен отключить им сервис), или через MAX (они должны починить API). Всё остальное — игра в догонялки.

Письмо в MAX

К пятому дню у меня собрался полный пакет: разбор архитектуры атаки, воспроизводимый PoC (одна curl-команда), анализ корневой причины, конкретные рекомендации (Origin-валидация, SDK-токен, привязка сессии к device-fingerprint, push-подтверждение, rate-limit), CVSS 8.8, IOC по 179 доменам и истории миграций.

Я оформил это в стандартный отчёт coordinated vulnerability disclosure (cover page, executive summary, severity, technical details, PoC, impact, recommendations, IOC, disclosure timeline, contact). Стандартная структура CERT/CC, как принято в индустрии. Указал 90-дневное окно до публичного раскрытия — общая практика.

Отправил в support@max.ru, копии на возможные адреса безопасности (security@, abuse@).

Прошла неделя. Ни одного ответа. Ни автоматического, ни от человека. Через неделю активно эксплуатируемая уязвимость с CVSS 8.8, доходящая до угона Госуслуг — не вызвала у них ни одного шевеления.

И, что самое скверное, эта уязвимость касается не только текущей конкретной группы. Любая другая группа, посмотрев на этот текст, может развернуть свой кит за два дня. У них для этого даже не нужен талантливый кодер — просто Node.js-обёртка над несколькими POST’ами в API MAX. Это не сложно. Это, в общем-то, почти тривиально.

Что в итоге

На момент публикации этой статьи:

— главный домен this-is-face.dev у Dynadot жив, заявка в работе — DNS-сервис на ClouDNS работает, реакции нет — open-file.shop на DEDIK Services — открывается, жертв собирает — регистраторы по моим жалобам отозвали примерно 15 второстепенных доменов из 179 (часть ушла в NXDOMAIN) — уязвимость в MAX-API — открыта; официального ответа от VK не получено

Я не уверен, что эта статья заставит VK что-то сделать. Но я уверен, что замалчивание не работает. Именно поэтому она тут.

Что делать тебе, если получишь похожую ссылку

Не открывай на основном устройстве и не вводи никаких данных. Если открыл и ввёл — сразу:

— смени пароль на MAX и включи облачный пароль (двухфакторку), хотя в данной атаке она тоже бы не спасла на этапе ввода, она нужна потом для ограничения активных сессий — завершить все сессии MAX кроме текущей — на Госуслугах включить «Безопасный вход» и ограничить сторонние подключения через ЕСИА — проверь свои контакты на похожие сообщения — если у тебя кто-то в контактах увёл аккаунт, эта же приманка пойдёт по твоим знакомым уже от его имени

И сообщи о ссылке:

— в Google Safe Browsing: https://safebrowsing.google.com/safebrowsing/report_phish/ — в Microsoft SmartScreen: https://www.microsoft.com/en-us/wdsi/support/report-unsafe-site — в PhishTank, Netcraft, AbuseIPDB — у clk1.me — на complaint@clk1.me, они оперативно удаляют конкретные shortlink’и — хостеру по IP (определяется через ipinfo.io) — регистратору домена (через WHOIS на who.is) — в F6 / Group-IB CERT: cert@cert-gib.ru

Параллельно — заявление в МВД через Госуслуги, статья 159.6 УК. Без этого регистраторы биллинговые данные клиента не выдадут, но в массиве заявлений твоё письмо станет ещё одним подтверждением.

IOC для тех, кто мониторит threat intel

C2 / NS:

this-is-face.dev          Dynadot, IANA 472
ns1.this-is-face.dev      45.83.248.12   AS203391 ClouDNS (BG)
ns2.this-is-face.dev      45.83.249.12   AS203391 ClouDNS (BG)
admin.this-is-face.dev    NXDOMAIN (оператор скрыл)
api.this-is-face.dev      NXDOMAIN
rustore.this-is-face.dev  NXDOMAIN

Хостинг (история и текущий):

212.109.195.59   AS29182   JSC IOT (RU)        taken down
79.143.176.86    AS51167   Contabo (DE)        taken down
5.8.53.90        AS34665   PIN-DC (RU)         taken down
5.8.51.6         AS34665   PIN-DC (RU)         moved
85.239.144.215   AS207043  DEDIK Services (DE) ACTIVE

Эндпоинты бэкенда кита:

POST /api/send-code      приём номера, проксирование в MAX
POST /api/resend-code    повторная отправка
POST /api/sign-in        приём SMS-кода, получение авторизованной сессии MAX
POST /api/sign-in-2fa    приём облачного пароля
header _xh: <hex>        anti-replay HMAC, генерируется в JS

Сигнатура фишинг-страницы:

title:  "MAX – быстрое и легкое приложение для общения и решения повседневных задач"
body:   "Пользователь поделился с вами фото / Войдите в аккаунт"
        либо "Пользователь кто-то поделился с вами фото"
flow:   телефон → SMS-код → cloud password
url:    https://<domain>/<random8-10>     dynamic per-visitor path

Сигнатуры для server-side детекции на стороне самой MAX (если кто-то из MAX security всё-таки прочитал):

- Запросы /api/send-code без Origin или с Origin не из whitelist'а MAX
- Один TLS JA3-fingerprint инициирует /api/send-code на десятки разных
  номеров за минуту
- Геораспределение вводимых номеров не коррелирует с одним IP-источником
- User-Agent: типовой Chrome/Firefox без характерных для веб-MAX заголовков

Полный список 179 доменов — в комментариях по запросу выложу gist’ом, в основной текст не положил, чтобы не утопить.

Инструменты

Что использовалось из публичного и бесплатного. Никаких регистраций, никаких реферальных ссылок, никакой коммерческой заинтересованности.

any.run — интерактивная песочница, бесплатный публичный режим. С него началась цепочка. — VirusTotal — детекты, passive DNS, связи между IP и доменами. Это та самая база с 179 связанными доменами. — who.is, ipinfo.io, whois.com — WHOIS, DNS, IP-метаданные. — dns.google/resolve — DNS-over-HTTPS, удобно вызывать прямо из консоли браузера через fetch(). — Browser DevTools — Network tab, Console, Sources. Всё, что я сделал с кодом кита, делается через document.scripts[i].textContent. — curl — для прямого тестирования эндпоинтов кита, вне браузера и его CORS-ограничений. — abuseipdb.com, safebrowsing.google.com, phishtank.com — куда сообщать.

Никаких сложных reverse-engineering инструментов не понадобилось. Кит не обфусцирован, бэкенд возвращает понятные ошибки, инфраструктура у оператора прозрачная для passive DNS. Я не Шерлок Холмс, и DevTools у меня обычный.

Вместо постскриптума

Знакомый, кстати, потом ответил. Аккаунт у него действительно увели, ссылку рассылали с него ботом по контактам всю ночь. Он в этом не виноват, я ему не предъявил ничего. Просто молча дал ему этот текст почитать.

Написать эту статью я начал в субботу вечером с одной ссылкой и любопытством. Закончил в среду утром с пакетом отправленных жалоб в Dynadot, ClouDNS, четырём хостерам, в Identity Digital, в F6 CERT, и с подробным отчётом в support@max.ru. Ситуация на сейчас — фишинг работает на четвёртом по счёту хостинге, MAX молчит.

Если кто-то из VK security всё же прочитает: контактный канал — личка на Хабре, готов ко всему — телефонный созвон, передача полного списка 179 доменов, выгрузка кода кита, координация с CERT-партнёрами. Полный отчёт с CVSS, PoC и рекомендациями уже у вас в support@max.ru. Coordinated disclosure window — стандартный 90 дней.

Если ты дочитал до сюда — спасибо. Если у тебя есть свои находки по этой группе — кидай в комментарии, добьём вместе.


Отдельное спасибо команде any.run за публичный бесплатный анализ, без которого я не стал бы тыкать ссылку. И F6 за исследование «Подноготная угона», которое дало мне правильный фрейм для понимания того, что я разбираю.