А вы давно заглядывали внутрь ваших зависимостей?

в 13:14, , рубрики: cybersecurity, github, Malware, node-ipc, open source, информационная безопасность, кибербезопасность, Программирование, реверс-инжиниринг, репозиторий, уязвимость

Задумывались ли вы о том, что находится внутри зависимостей, которые так или иначе подтягиваются в ваш код? Взять чужую библиотеку сейчас — норма жизни, но чем это обернется с точки зрения безопасности?

А вы давно заглядывали внутрь ваших зависимостей? - 1

Последние истории с node‑ipc и CTX заставили задуматься о том, что лежит внутри этих репозиториев. Оказалось, не только легитимный код. Там есть и попытки заработать без особых усилий, просто собирая информацию, и даже полноценные стиллеры. Причем негативных изменений стало больше после известных событий.

Почему мы обратили внимание на зависимости

Меня зовут Леонид Безвершенко, я — младший исследователь угроз информационной безопасности в команде Глобального центра исследований и анализа угроз (GReAT) подразделения Threat Research «Лаборатории Касперского». Это исследование, а также наш инструмент для поиска закладок в репозиториях и, конечно, сама статья написаны в соавторстве с моим коллегой по GReAT, главным экспертом по исследованию угроз информационной безопасности Игорем Кузнецовым.

В марте 2022 года мы с Игорем решили отвлечься от привычного исследования бинарщины — рассмотрения apt, реверса malware — и заглянуть в opensource. В этом направлении нас подтолкнула новость о node-ipc, который используется в большом количестве других пакетов (в том числе в Unity Hub) в качестве зависимости.

17 марта появилась информация, что пакет удаляет файлы у пользователей, IP которых бьется как русский или белорусский.

Когда в проблеме начали разбираться и в конечном счете обратились к автору, тот сначала отмалчивался, а потом заявил, что это его способ выразить протест. Иными словами, это не история взлома, а пример того, как автор сам злонамеренно превратил свой пакет в троян. 

А вы давно заглядывали внутрь ваших зависимостей? - 2

Мы предположили, что подобные истории наверняка можно найти и в других opensource-пакетах. Эта идея лежит на поверхности. Выполняя install, мы особо не смотрим, что скачиваем. А все распространенные современные языки поддерживают парадигму «скачай и запусти какую-нибудь зависимость».

  • Node: “node install%package%”

  • Python: “pip install%package%”

  • Rust: curl …rustup.sh | /bin/sh; cargo run

  • Go: go get github.com/… В этом случае пакет скачивается с GitHub и можно посмотреть на него до того, как он соберется. Но вряд ли кто‑то так делает…

Казалось бы, у популярных пакетов миллионы пользователей, централизованные репозитории. Кто-то ведь должен следить за безопасностью? Но мы заглянули внутрь пакетов и поняли, что это работает не так.

Например, в Python есть пакет, который должен заниматься математикой. Но с вероятностью 1 к 100 он открывает у пользователя порносайт.

А вы давно заглядывали внутрь ваших зависимостей? - 3

Спустя некоторое время по секьюрити комьюнити прошла еще одна история о Rust-пакете rustdecimal. Пакет скопировали с опечаткой в имени, добавив в новую версию malware. Автор оригинального пакета был в курсе, но сообщество не знает, как работать с такими атаками.

А вы давно заглядывали внутрь ваших зависимостей? - 4

Так мы пришли к идее проверки opensource-пакетов, которые часто подтягивают в качестве зависимостей.

Там должно быть что-то…

Идея была довольно простая. Надо собрать все пакеты, изменившиеся с февраля 2022 года (потому что это горячее время), посмотреть разницу с предыдущей версией и проанализировать в поисках закладок. Изначально было понятно, что правила детектирования придется исправлять, поэтому обнаруженные изменения мы решили складывать в базу, чтобы потом их можно было легко пересканировать.

 Под эту идею мы расчехлили свою заначку — виртуальную машину с 4 ТБ дискового пространства:

  • 4 ТБ HDD

  • 16 ГБ RAM

  • Ubuntu

  • Python & PostgreSQL

Мы решили начать с двух репозиториев: npm (node.js) и PyPI (python) — они довольно популярные, да и в новостях уже появлялась информация о находках.

Обобщенная архитектура написанного нами сервиса выглядит так:

А вы давно заглядывали внутрь ваших зависимостей? - 5

Четыре модуля работают асинхронно:

  • Первый взаимодействует с API репозиториев (npm или PyPI в нашем случае). Он берет данные о новых релизах пакетов — сверяет не только сами версии, но и описание, ищет новых контрибьюторов и т. п.

  • Второй скачивает новый релиз.

  • Третий сравнивает новую и предыдущую версии пакетов. Это классический инструмент Diff. Назовем его Differ.

  • Четвертый — сканер. Мы подобрали набор хантинговых правил, который нам действительно помог.

Но не все так просто…

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

Первая проблема заключалась в том, что, когда мы собрали весь этот асинхронный сетап, он стал работать слишком быстро. Нас начали банить.

А вы давно заглядывали внутрь ваших зависимостей? - 6

Пришлось различными эвристическими способами подбирать sleep.

А вы давно заглядывали внутрь ваших зависимостей? - 7

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

Следующая проблема скрывалась в Differ-е. На одном из пакетов размером не более 900 МБ он завис на несколько часов. А ведь это был не самый большой размер пакета — встречаются файлы по 2 или 3 ГБ. Мы прогнали на этом пакете обычный Diff из Linux, и тот отработал за несколько секунд.

Мы предположили, что проблема в нашем коде и его надо дебажить. Но после всех изысканий оказалось, что виновата стандартная библиотека Python — difflib, которая сравнивает файлы и прочие объекты. Оказывается, она не оптимизирована и для нашей задачи не подходит — с ней мы просто не смогли бы выйти на поток.

А вы давно заглядывали внутрь ваших зависимостей? - 8
А вы давно заглядывали внутрь ваших зависимостей? - 9

В качестве альтернативы мы нашли diff-match-patch от Google. Сами ее не тестировали, но поверили комментатору со Stackoverflow, который заявлял, что она в 20 раз быстрее. 

А вы давно заглядывали внутрь ваших зависимостей? - 10

С этой библиотекой все заработало очень хорошо. Мы немного потеряли в красоте Differ-а, но в данном случае она была не важна.

Следующая проблема, с которой мы встретились, также была связана с Differ-ом.

Мы увидели, что наш робот поднимается и падает из-за того, что не хватает оперативной памяти. Размер пакета — 186 МБ, что странно. Но когда мы его разархивировали, там оказалось 3 ГБ. Пакет назывался ‘similar-persian-words’ и, как ни странно, содержал в себе JSON со всеми персидскими словами. Им действительно пользуются, у него есть загрузки.

А вы давно заглядывали внутрь ваших зависимостей? - 11

Понятно, что здесь была проблема арифметики. У нас было 16 ГБ оперативной памяти, а размер пакета — 3 ГБ. Итого: 3 ГБ — предыдущая версия, 3 ГБ — новая версия и еще сам Differ требовал 3 ГБ. После этого анализа мы нашли и исправили ошибку в своем коде — он не очень правильно считал хеш от разницы (не чанками). Естественно, пришлось и объем памяти на виртуальной машине увеличить.

Что мы обнаружили

А теперь поговорим про найденные проблемы.

Всего за 5 месяцев, с февраля 2022 года, в двух репозиториях мы проанализировали 2 184 498 пакетов. Из них:

  • 97% — npm

  • 3% — PyPI

По графику ниже видно, что разработчики open source по выходным отдыхают. А разработчики PyPI на фоне разработчиков npm отдыхают почти всегда.

А вы давно заглядывали внутрь ваших зависимостей? - 12

 Еще немного статистики:

  • мы скачали 4 873 242 уникальные версии пакетов;

  • в хранилище в сжатом виде пакеты вместе с изменениями занимают 6 ТБ.

Мы храним в том числе и удаленные пакеты, которые более недоступны. Когда в новостях мы слышим о том, что в очередном пакете найдена какая-то проблема, как правило, он уже удален — не получается его подробно изучить после того, как кто-то из вендоров в нем что-то обнаружил. Но благодаря тому что мы храним все, мы можем ретроспективно писать новые правила и придумывать свежие эвристики.

Наш набор правил (в том числе на обфускацию) обнаружил 6200 подозрительных изменений. Это примерно 0,1% от всех проанализированных расхождений. Сюда включены все выявленные в пакетах политические лозунги, проявления активизма, удаление файлов и т. п.

А вы давно заглядывали внутрь ваших зависимостей? - 13

Мы посмотрели вглубь и нашли довольно странные вещи.

Например, нашли npm-пакеты, в которых есть куски легитимного кода, но прямо в инсталляции внедрен сбор информации о системе, пользователе, переменных окружения и т. п. Больше ничего этот код не делает. 

А вы давно заглядывали внутрь ваших зависимостей? - 14

Выглядит подозрительно. Все бы ничего, если бы не домены, куда это все отсылается, — interactsh, burpcollaborator или pydream. Возможно, читателю они знакомы. Это бесплатные эндпоинты для разработчиков и тестеров.

Есть и более подозрительные вещи, в частности скрипты конкретно под Windows, которые собирают еще больше информации, вплоть до наличия административных прав у пользователя. 

А вы давно заглядывали внутрь ваших зависимостей? - 15

Этот скрипт тоже отсылает всю информацию, которую только можно запаковать, но никакого дополнительного кода не исполняет. Понятно, что следующая версия могла прийти уже с полной нагрузкой. Но тем не менее чаще мы видели только такие «отстуки».

В один прекрасный день мы нашли пакет, в котором в readme автор честно описал, что же происходит. Он просто пытается получить денег с какого-нибудь вендора.

А вы давно заглядывали внутрь ваших зависимостей? - 16

В качестве объяснения своего поступка он даже приложил ссылку, где за подобное заплатили 3 тысячи долларов. 

А вы давно заглядывали внутрь ваших зависимостей? - 17

Помимо любителей такого заработка мы нашли огромное количество пакетов — 1915 штук — которые так или иначе обфусцированы. В основном это obfuscate.io.

А вы давно заглядывали внутрь ваших зависимостей? - 18

 Чтобы понять, что внутри, нужно каждый из них деобфусцировать. Иногда люди закрывают свои пакеты, думая, что это спасет от выуживания оттуда некой информации. Но выглядит это так же подозрительно, как и malware. Все это нужно разбирать. 

После фильтрации осталось 638 пакетов от горе-хакеров.

А вы давно заглядывали внутрь ваших зависимостей? - 19

Среди них есть и вполне «безобидные» истории, которые легко отлавливаются одним из правил. Например, часто эти горе-хакеры используют бесплатные хостинги для питон-скриптов, чтобы реализовать админку, собрать информацию и пойти с ней к вендору.

Но дальше появились более интересные находки.

Больше всего (60+) мы нашли программ, которые воруют кредиты Discord. Понятно, что до кучи они собирают информацию по кредитным картам, троянят сам Discord. Но почему-то пользователи этого мессенджера — основная таргет-аудитория.  

А вы давно заглядывали внутрь ваших зависимостей? - 20

Еще одна интересная находка была в удаленных пакетах.

Как правило, в новостях об обнаруженном malware публикуется целый список пакетов, подробно в которые никто не смотрит. Мы наткнулись на такой python-пакет aiohttp-proxies-forked, благо у нас он был уже отложен к моменту выхода публикации (и удаления пакета). Внутри мы обнаружили прекрасный асинхронный бэкдор под Windows, причем завернутый не в exe (https://blog.sonatype.com/this-week-in-malware-npm-malware-exfiltrates-windows-sam-amazon-ec2-credentials). 

А вы давно заглядывали внутрь ваших зависимостей? - 21
А вы давно заглядывали внутрь ваших зависимостей? - 22

 Он был написан на Python.

А вы давно заглядывали внутрь ваших зависимостей? - 23

 Логирование в этом пакете на чистейшем русском.

А вы давно заглядывали внутрь ваших зависимостей? - 24

Более свежая находка — и, пожалуй, одна из самых интересных — пакет, загружающий полноценный стиллер.

Прочитав очередной отчет Checkmarx с большим количеством вредоносных пакетов, мы обновили свои правила и просканировали все, что было обнаружено к этому моменту. И таким образом наткнулись на два пакета, которые были гораздо интереснее всего списка Checkmarx, — ultrarequests и pyrequests. Они мимикрируют под один из самых известных пакетов — requests.

Фокус заключался в том, что злоумышленник полностью скопировал описание легитимного пакета, так что на сайте PyPi мы видим оригинальную статистику — 48 тысяч звезд GitHub, 8 тысяч форков, 230 миллионов скачиваний. Увидев эту статистику, человек подумает, что ничего плохого в пакете быть не может. 

А вы давно заглядывали внутрь ваших зависимостей? - 25

Внутри этот пакет почти ничем не отличается от оригинального requests, кроме одного файла — exceptions.py. В нем в одном из классов ошибок сделан злой прелоад в base64, который декодируется и загружает стиллер. Он, в свою очередь, ворует данные кредитных карт, ищет файлы с паролями, ворует cookie и сохраненные пароли и т. п.

Мы сразу же сообщили об этом пакете в PyPi, но быстрого ответа не получили. Зато когда написали твит, он разлетелся очень быстро (https://twitter.com/bzvr_/status/1557807795877171201).

А вы давно заглядывали внутрь ваших зависимостей? - 26

После того как мы сообщили о пакете в базу открытых уязвимостей Snyk.io, его почти сразу забанили. А на PyPi пакет прожил две недели. Только потом нам ответили из ассоциации Python, что очень нам благодарны за находку, и удалили его. 

Любопытно, что по графику скачиваний этого пакета после твита видно, что его популярность выросла почти на 50%. То есть мы в принципе его разрекламировали.

Что мы будем делать дальше

Наше исследование — лишь вершина айсберга. Мы попробовали текстовый diff, нашли некоторое количество закладок. Но мир open source огромен. Плюс есть еще много языков, которые мы не успели подключить, — для начала это Rust и Golang. И мы уже работаем над этим.  

А вы давно заглядывали внутрь ваших зависимостей? - 27

Следующая идея — следить за всем GitHub. И это бесконечная история. Нам каждый день прилетают какие-то детекты, с ними нужно что-то делать, но рук не хватает. Хочется сказать: «Горшочек не вари», но мы продолжаем. Уверен, что у нас еще будут интересные находки, и именно вы можете стать тем, кто их обнаружит. Присоединяйтесь к нашим командам Threat Research и командам Security Services. Сможете заниматься расследованием кибершпионажа, поиском глобального malware, программами-вымогателями и прочими трендами мира киберпреступлений. Это новые интереснейшие задачи каждый день.

Разрабатываете, но не знаете, как в этой ситуации жить дальше? Следите за нашими анонсами. В разработке для частных целей, наверное, этого достаточно. Не без влияния таких новостных публикаций вендоры начинают следить за репозиториями, и это радует. Корпоративной разработке сложнее — возможно, придется морозить версии, поскольку однозначного ответа на вопрос о безопасности нет.

Автор: Леонид Безвершенко

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js