Як одночасно атакувати дані користувача та кошти для переказу за допомогою одного підлогу скрипта?Автор статті, джерело: Slow Mist Tech
Контекст
Недавно безпекові фахівці SlowMist під час регулярного аналізу інформації про загрози зафіксували атаку, пов’язану з отруєнням сценаріїв, що пов’язані з системою клієнтської підтримки Udesk. Команда отримала два зразки JavaScript: udeskApi.2026-10-16.cached.js та deeps.js, і провела їх аналіз, щоб встановити, як зловмисний код проникає на сторінки через сценарії клієнтської підтримки, а також як впливає на дані користувачів та операції з бізнесом.
Перевірка зразка поступово розкрила два типи ризиків: зловмисний сценарій одночасно збирає дані сеансу та чутливу інформацію, надану користувачем на веб-сторінці, і згідно з правилами сайту змінює адресу поповнення та копіює вміст. Перший випадок може дозволити зловмиснику використовувати сеанс входу або взяти під контроль обліковий запис, тоді як другий може призвести до того, що користувач перекаже кошти на замінену отримувачем адресу. Ми розпочали з точки завантаження сценарію служби підтримки, прослідкували логіку читання даних, відправлення через мережу та зміни сторінки, щоб відновити спосіб реалізації та умови запуску цих двох типів дій.
MistEye відповідь
MistEye — це власна розробка SlowMist система виявлення загроз та динамічного моніторингу безпеки Web3, яка поєднує функції безпекового моніторингу та агрегації інформації, надаючи користувачам оперативне попередження про ризики та захист активів.
MistEye вже в першу чергу синхронізував ризики через канали інформування та сповіщення клієнтів.

Зловмисний завантажувач та механізм завантаження віддалених навантажень
Після відкриття udeskApi.2026-10-16.cached.js можна побачити код функцій кнопки служби підтримки, iframe чату, відстеження відвідувачів та передачі повідомлень. Продовжуючи перевірку кінця файлу, після основного коду є окрема функція: вона розшифровує два рядки за допомогою _ud(), створює елементи та вставляє їх у head поточного документа.
Цей фрагмент не містить імен тегів та віддалених URL-адрес. Якщо шукати лише текстові домени, точка завантаження може бути пропущена. Проаналізувавши реалізацію _ud(), ми виявили, що вона бере по два шістнадцяткові символи, а потім перетворює їх на символи; після розгортання констант ціль завантаження стає очевидною.
736372697074 розкодовано як script, інша константа розкодована як https[:]//udeskqlobal[.]com/deeps.js. Доменне ім’я зі словом qlobal, що починається з літери q, має зберігати це написання під час пошуку. Завантажувач встановлює сценарій як асинхронний, а потім вставляє його на сторінку; коли досягається ця позиція, а політика браузера та мережа дозволяють, віддалений код може ввійти в поточний документ.
Завантаження, що відповідає цьому URL, — це deeps.js. Акцент дослідження змістився з SDK служби підтримки на саме завантаження. Сторонні класичні сценарії виконуються в контексті вбудованого документа, і дані, до яких вони мають доступ, залежать від сторінки або iframe, на якій вони запущені. Вікно чату служби підтримки використовує iframe і не ізольовує автоматично сценарії, завантажені на головній сторінці.
Механізм збору даних із веб-сайту та сфера впливу
deeps.js спочатку читає window.location.hostname і генерує конфігурацію C за правилами трьох сайтів. Щоб визначити, які сторінки будуть збиратися, цієї конфігурації недостатньо: вона обмежує весь скрипт чи лише певний модуль — потрібно продовжити відстеження місця виходу.
Перевіряючи за потоком керування, ми бачимо, що читання файлів Cookie та веб-сховища, відправлення зйомки запуску, а також хуки форм і запитів автентифікації розташовані перед if (!C) return;. Нижче наведено оператори відправлення зйомки та кінцевий XHR-хук у порядку їхнього розташування у вихідному коді; коментарі позначають пропущений код, що відповідає форматованому вигляду D:L100, D:L151–L166.
Місце виходу з визначення впливу: навіть якщо hostname не співпадає з правилами трьох сайтів, сценарій спочатку входить у шлях збору даних та встановлює хуки, а потім виходить з модуля адрес. При перевірці відкритих сторінок не слід обмежуватися пошуком лише за цими трьома конфігураціями сайтів.
Під час запуску завантаження читає cookies, localStorage та sessionStorage, доступні на поточній веб-сторінці. Ці місця можуть зберігати дані про стан входу, профіль користувача та бізнес-дані; якщо вони містять ще дійсні та повторно використовувані токени входу, зловмисник може використати їх для підробки сеансу користувача. Скрипт також надсилає URL-адресу верхнього рівня сторінки та origin поточного документа, щоб ці дані були надіслані разом із джерелом сторінки.
Процес збирання даних має виявлення помилок по кожному елементу. Якщо скрипт не зможе прочитати верхній URL з іншого джерела, він замінює його на x і продовжує обробку інших полів; два типи зберігання веб-сторінок серіалізуються у JSON. Діапазон куків обмежений вмістом, доступним через document.cookie; HttpOnly кукі не включаються.
Скрипт також зберігає входи для даних, які будуть надіслані пізніше. Коли користувач надсилає форму, він перебирає input, select і textarea, копіює непорожній вміст і продовжує оригінальний процес надсилання. Поля, які фактично заповнюються на сторінці, такі як ім’я користувача, пароль, код підтвердження тощо, можуть потрапити в додатковий шлях надсилання даних, і їх витік може бути використаний для входу в обліковий запис або його захоплення.
Цей шлях реалізований шляхом обгортання HTMLFormElement.prototype.submit та прослуховування подій submit на етапі захоплення. Для сторінок, які надсилають дані безпосередньо через інтерфейс, скрипт також обгортає fetch і XHR: коли запит містить тіло та URL містить ключові слова, такі як login|signin|auth|register|signup|password, копіюється відповідний вміст з збереженням оригінального виклику запиту. У гілці fetch додатково вимагається, щоб URL був рядком, а тіло походило з опцій запиту; коли об’єкти, такі як FormData, безпосередньо серіалізуються в JSON, зібрані дані можуть не містити реальних полів.
Механізм витоку даних та резервний канал
Вищезазначений вхід для збору даних у кінцевому підсумку викликає одну й ту саму функцію _send(). Продовжуючи аналіз цієї функції, можна побачити, що фіксований отримувач — https[:]//udeskqlobal[.]com/c.php. У момент запуску знімка поля s, o, c, l, ss використовуються для зберігання відповідно адреси сторінки, поточного джерела, читабельних файлів cookie та двох типів веб-сховищ; подальші запити форм та автентифікації відправляються при їхньому виклику.
Функція витягує параметри після знака запитання з URL і додає їх у тіло асинхронного POST-запиту, встановлюючи Content-Type: application/x-www-form-urlencoded. Нижче повністю збережено функцію відправлення (D:L45–L60):

Шлях відправлення також містить резервний запит зображення: при помилці XHR або синхронній помилці під час відправлення скрипт створює об’єкт Image, присвоює URL з параметрами властивості src і намагається повторно передати дані за допомогою GET. URL обрізається до перших 8 000 символів JavaScript, тому довші дані можуть бути неповними.
При розумінні цього шляху необхідно розрізняти «відправлення запиту» та «читання відповіді». Скрипт не читає відповідь c.php; міжджерельний POST-запит, що відповідає умовам простого запиту, може бути відправлений першим, а читання відповіді обмежується браузером, тому помилки CORS можуть виникати одночасно з відправленням запиту. При перевірці журналів слід одночасно перевіряти тіло POST та параметри GET зображення, а політики виходу — окремо connect-src та img-src. Звичайна форма, що викликає навігацію документа, також може впливати на можливість завершення асинхронного запиту.
На цьому етапі стало зрозуміло, куди відправляються дані сеансу веб-сторінки та наступні надіслані дані. Однак після перевірки виходу з сайту завантаження зберігає ще одну групу операцій: визначення формату адреси, зміна тексту на сторінці та перехоплення шляху копіювання. Цей код додає нові вказівки щодо бізнесу поповнення.
Заміна адреси поповнення та механізм захоплення буфера обміну
Після if (!C) return; скрипт переходить до модуля адреси. Три початкових правила hostname тепер мають чітке призначення: вони відповідають mgbx[.]com, bikingex[.] та bitxex[.]io, щоб вибирати селектори елементів адреси та кнопки копіювання для різних сторінок.
Ці регулярні вирази не мають анкорів на початку та в кінці, тому вони відповідають ширшому діапазону, ніж точне порівняння імені домену. Правила сторінки також перевіряють повний location.href, і ключові слова, такі як deposit, recharge, assets, у параметрах запиту або фрагменті також враховуються при визначенні. Після виявлення збігів у форматі сторінки, елемента чи адреси, сценарій сканує кожні 200 мілісекунд і замінює виявлені адреси поповнення на значення з конфігурації. Якщо користувач виконає дійсний переказ за заміненою адресою, отримувач зміниться на цю адресу.
Три відділення сайту використовують шість спільних параметрів, позначених у коді як BTC, EVM, TRON, Solana, LTC і DOGE. Ідентифікація адрес здійснюється лише за формою символів та порядком співпадіння, без перевірки вибраної користувачем мережі чи контрольної суми адреси, що може призводити до помилкової ідентифікації звичайних ідентифікаторів бізнесу.
Продовжуйте перевіряти код, пов’язаний із копіюванням, і ви побачите, що зразок одночасно впливає на відображення сторінки та вміст буфера обміну. Таким чином, навіть якщо користувач порівнює адресу сторінки з результатом копіювання, він може отримати однакове спотворене значення. Три шляхи:
- Обгортка API буфера обміну. navigator.clipboard.writeText спочатку викликає R() для заміни параметрів, а потім передає їх оригінальному методу. Цей шлях обмежений лише конфігурацією hostname, не перевіряє умови сторінки поповнення та не залежить від сканування DOM для виявлення елементів.
- Замінити кнопку копіювання. Скрипт клонує збіжну кнопку, встановлює новий слухач кліку та замінює початковий вузол. Новий слухач блокує дію за замовчуванням і поширення події, намагаючись скопіювати адресу, збережену у спільній змінній _cur.
- Перехоплення події copy. Коли _cur не порожній і виконується правило сторінки, слухач на document замінює скопійований вміст на _cur, не перевіряючи, чи виділений користувачем текст є адресою.
При цьому API буфера обміну та слухач copy розташовані поруч у вихідному коді (D:L260–L275), але умови їхнього запуску різні:
_cur зберігає останню фактично замінену адресу. Коли на екрані відображається кілька адрес, нова заміна перезаписує попередню записану адресу; кілька кнопок можуть копіювати одне й те саме значення. Якщо на початку сторінки вже відображається конфігураційна адреса, сканування не ініціалізує _cur, і нові слухачі подій не записують вміст; клоновані збережені атрибути вбудованих подій HTML все ще можуть брати участь у обробці подій.
У процесі аналізу було виявлено ще одну реалізаційну недолік, що впливає на визначення поведінки: сценарій намагається прочитати дескриптор власного властивості textContent з Element.prototype, тоді як стандартне визначення атрибута знаходиться в Node.prototype. У стандартних прототипних відношеннях подальший доступ до .set викличе виняток. Після невдачі цієї гілки catch приховує виняток; подальший аналіз коду до і після цього показує, що опитування вже зареєстроване, і подальші хуки копіювання все одно будуть встановлені відповідно до їхніх умов. Помилка в одній гілці не призводить до зупинки модуля перехоплення адреси.
Підсумок
Після відстеження завантажувача в кінці сценарію служби підтримки ми визначили мету атаки: збирання даних, які можна використати для підробки сеансу або входу в обліковий запис, а також заміна адрес отримання платежів у сторінках поповнення та операціях копіювання на значення з конфігурації. Перше не обмежене конфігурацією трьох сайтів, друге вмикається залежно від сайту та конкретного шляху копіювання, і під час розслідування необхідно охопити різні сценарії витоку.
Бізнес, який ще завантажує відповідні сценарії, повинен припинити їх розповсюдження, видалити витікні облікові дані та перевірити цілі поповнення через надійний бекенд та записи транзакцій.
Рекомендації
- Забезпечте безпеку та припиніть розповсюдження заражених ресурсів. Якщо виробництво все ще завантажує відповідні сценарії, негайно заблокуйте їх після збереження фактичної відповіді, ланцюжка ініціювання запиту, інформації про кеш та часу збору; відновіть з надійної версії, перевіреної незалежно, і перевірте конфігурацію хостингу сайту, CDN, збірки та управління тегами.
- Пошук завантаження та записів експлуатації. Об’єднаний запит для зловмисних доменів, двох шляхів та хешів файлів; записи експлуатації також перевіряють тіло POST та параметри GET. При розгляді стиснених скриптів також шукаються шістнадцяткові URL-адреси в завантажувачах, щоб уникнути пропуску зашифрованих даних.
- Завершіть завантаження зараженого документа та видаліть скомпрометовані облікові дані. Повністю закрийте відповідні сторінки або документи WebView, щоб уникнути повторного завантаження старих ресурсів. Залежно від реального масштабу витоку, скасуйте сесії, змініть токени та паролі з чистого середовища; видалення тегів script не скасовує вже встановлені хуки та таймери.
- Самостійно перевірте адресу поповнення та транзакцію. Для сторінки, що виконує завантаження, перевірте оригінальну адресу поповнення, відповідну транзакцію та фактичну ціль переказу через надійні джерела, оцінивши вплив на основі записів транзакцій.
- Перевірка сценаріїв та обмеження експорту даних. У поєднанні з налаштуваннями бізнес-процесів, перевірте політики connect-src, img-src тощо, щоб обмежити завантаження сценаріїв та передачу даних для udeskqlobal[.]com.
IOC
Домен
udeskqlobal[.]com
URL
https[:]//udeskqlobal[.]com/deeps[.]js
https[:]//udeskqlobal[.]com/c[.]php
Адреса гаманця
BTC: bc1qhzppfj69ywp22swj50jwcfxdamg3ym245srng9
EVM: 0x9B6EcD0023a28E1391c5124eCe578A9751A337b2
TRON: TH4L5YAhhxtC8qALbZKbPZZgausbGi25nF
Solana: AFmCUe3nNbjTaC585CcdA3vvC9iWVR8YunooFKpaQx2Z
LTC: ltc1qwz0zp39ywl34kahvn9lyk7j5x63wsy9tcxhm3w
DOGE: DAoy2w8uvFtZ92q87s9qKEoHbWgV7mVThj
Шкідливий файл
filename: udeskApi.2026-10-16.cached.js
SHA256: 45b4e8f160d8d5177819f6c1dc67acc7abbdc65eeaffc909e668799dc778bcf6
filename: deeps.js
SHA256: 57c1441c4f5bb3260981a2df64f9ff35f117abde0d8667c8c66a047880074c59
Про MistEye
MistEye — це власна веб-3 платформа для інтелекту про загрози та динамічного моніторингу безпеки, розроблена SlowMist, яка через API надає можливості виявлення шкідливої діяльності та попередження про ризики ланцюга поставок у екосистемі відкритих пакетів.
Всі зловмисні пакунки та IOC, пов’язані з цією акцією, інтегровані в систему виявлення загроз MistEye. Розробники можуть за допомогою API автоматично перевіряти залежності проекту, швидко визначити, чи збігаються вони з відомими зловмисними пакунками, та отримати рекомендації щодо дій.


