javascript

Вредоносный код в npm-пакетах и борьба с ним

  • среда, 9 августа 2017 г. в 03:12:33
https://habrahabr.ru/company/ruvds/blog/335144/
  • Разработка веб-сайтов
  • Информационная безопасность
  • Node.JS
  • JavaScript
  • Блог компании RUVDS.com


В начале августа в нескольких десятках npm-пакетов был обнаружен вредоносный код. Администрация npmjs.com оперативно на это отреагировала и тут же подготовила отчёт о предпринятых мерах. Позже Доминик Кундел из twilio.com поделился советами о том, как найти проекты, «заражённые» подобными пакетами. Представляем вашему вниманию рассказ об этих событиях.


Вредоносный пакет crossenv в npm-реестре


1-го августа сего года нам, администрации npmjs.com, сообщили в Twitter о том, что пакет, имя которого очень напоминало популярный cross-env, отправляет на npm.hacktask.net переменные окружения из контекста его установки. Мы немедленно провели расследование и удалили из реестра этот пакет. Дальнейшее изучение ситуации привело к обнаружению в реестре ещё около 40 вредоносных пакетов.

19 июля пользователь hacktask опубликовал некоторое количество пакетов, имена которых были очень похожи на имена популярных npm-пакетов. Мы называем данное явление «typo-squatting», это — захват некоего ресурса из-за опечатки. Ранее подобное происходило, в основном, случайно. Несколько раз мы видели умышленное использование такого способа именования пакетов, к которому прибегали авторы библиотек, конкурирующих с уже существующими пакетами. Сейчас же имена пакетов были подобраны специально, и сделано это было явно со злым умыслом. А именно, автор пакетов намеревался красть данные у введённых в заблуждение пользователей. В результате все пакеты пользователя hacktask были удалены из реестра.

Адам Болдуин из Lift Security также заинтересовался этим происшествием и решил выяснить, имеются ли в реестре другие пакеты, не принадлежащие hacktask, но содержащие такой же код. У него есть список хэшей содержимого всех общедоступных пакетов, что делает возможными подобные исследования. Ему не удалось найти в реестре другие файлы с таким же содержимым.

▍Список вредоносных пакетов


Вот список пакетов пользователя hacktask с общим количеством их загрузок за период с 19 по 31 июля. Число загрузок этих пакетов возросло сразу после обнаружения вредоносного кода, что вызвано всеобщим интересом к проблеме. Данные по загрузкам до нахождения проблемы более точно отражают масштаб происшествия. Обратите внимание на то, что около сорока загрузок — это типичное число для любого общедоступного пакета, опубликованного в реестре, так как это соответствует числу автоматических загрузок на зеркала реестра. Учитывая это, вы можете видеть, что реальная угроза исходит от пакета crossenv, который набрал почти 700 загрузок, на втором месте — пакет jquery.js. Однако, тут также нужно учитывать то, что большинство загрузок выполнено зеркалами, которые запрашивали копии 16-ти опубликованных версий пакета crossenv. Мы оцениваем число реальных установок crossenv примерно в 50, возможно, их ещё меньше.

  • babelcli: 42
  • cross-env.js: 43
  • crossenv: 679
  • d3.js: 72
  • fabric-js: 46
  • ffmepg: 44
  • gruntcli: 67
  • http-proxy.js: 41
  • jquery.js: 136
  • mariadb: 92
  • mongose: 196
  • mssql-node: 46
  • mssql.js: 48
  • mysqljs: 77
  • node-fabric: 87
  • node-opencv: 94
  • node-opensl: 40
  • node-openssl: 29
  • node-sqlite: 61
  • node-tkinter: 39
  • nodecaffe: 40
  • nodefabric: 44
  • nodeffmpeg: 39
  • nodemailer-js: 40
  • nodemailer.js: 39
  • nodemssql: 44
  • noderequest: 40
  • nodesass: 66
  • nodesqlite: 45
  • opencv.js: 40
  • openssl.js: 43
  • proxy.js: 43
  • shadowsock: 40
  • smb: 40
  • sqlite.js: 48
  • sqliter: 45
  • sqlserver: 50
  • tkinter: 45

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

▍О дальнейших действиях по защите реестра


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

Мы поддерживаем Lift Security и Node Security Project в их текущей работе по выполнению статического анализа общедоступных пакетов, но эти усилия не позволят найти абсолютно все проблемные пакеты. Определение того, содержит ли пакет нечто вредоносное при публикации, конечно, эквивалентно приостановке работы, сделать мы этого не можем.

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

Как найти проекты, «заражённые» вредоносными npm-пакетами


Вот скриншот из твита Оскара Болмстена, благодаря котоому в npmjs.com узнали о том, что пакет crossenv, вероятно, ворует переменные окружения.


Анализ пакета crossenv

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

▍Проверка проектов на наличие в них вредоносных пакетов


Пакеты, о которых идёт речь, были удалены из реестра, однако, так как кража данных осуществляется в ходе установки пакета, вам следует проверить, не установили ли вы один из них. Иван Акулов собрал список этих пакетов и опубликовал его в своём блоге. Кроме того, он написал небольшую программу, которую вы можете использовать для проверки того, не используются ли эти пакеты в вашем текущем проекте:

npm ls | grep -E "babelcli|crossenv|cross-env.js|d3.js|fabric-js|ffmepg|gruntcli|http-proxy.js|jquery.js|mariadb|mongose|mssql.js|mssql-node|mysqljs|nodecaffe|nodefabric|node-fabric|nodeffmpeg|nodemailer-js|nodemailer.js|nodemssql|node-opencv|node-opensl|node-openssl|noderequest|nodesass|nodesqlite|node-sqlite|node-tkinter|opencv.js|openssl.js|proxy.js|shadowsock|smb|sqlite.js|sqliter|sqlserver|tkinter"

▍Поиск «заражённых» проектов в Mac и Linux


Если вы, как и я, регулярно разрабатываете под Node.js, у вас может быть целый набор проектов, которые хорошо было бы проверить. Я расширил код Ивана именно по этой причине. В частности, я воспользовался командами find и xargs для сканирования всех поддиректорий папки, содержащей мои проекты. Каждый проект затем проверяется с помощью вышеприведённого кода. Запустить скрипт можно, просто скопировав его в командную строку:

find . -type d -maxdepth 4 -name node_modules -print0 | xargs -0 -L1 sh -c 'cd "$0/.." && pwd && npm ls 2>/dev/null | grep -E "babelcli|crossenv|cross-env.js|d3.js|fabric-js|ffmepg|gruntcli|http-proxy.js|jquery.js|mariadb|mongose|mssql.js|mssql-node|mysqljs|nodecaffe|nodefabric|node-fabric|nodeffmpeg|nodemailer-js|nodemailer.js|nodemssql|node-opencv|node-opensl|node-openssl|noderequest|nodesass|nodesqlite|node-sqlite|node-tkinter|opencv.js|openssl.js|proxy.js|shadowsock|smb|sqlite.js|sqliter|sqlserver|tkinter"'

Знаю, код получился немаленьким, поэтому объясню что тут к чему.

  • Скрипт, начиная с текущей директории, выполняет рекурсивный поиск папок с именем node_modules, используя команду find. Глубина поиска в настоящий момент ограничена 4-мя уровнями вложенности, но вы можете это изменить сообразно структуре ваших проектов.

  • Затем здесь применяется команда xargs, которая занимается исполнением кода для каждой строки (то есть — директории), возвращённой find.

  • Код, который будет исполнен, создаёт новый экземпляр оболочки, в котором будут выполнены следующие действия:

    1. Для начала оболочка переходит в родительскую директорию папки node_modules.

    2. Далее, выводится имя текущей сканируемой директории с использованием команды pwd. Обратите внимание, то, что будет выведено имя директории, не означает, что она «заражена».

    3. После этого запускается npm ls, что приводит к выводу всех установленных в проекте модулей.

    4. Так как команда npm ls может вывести сообщения о несуществующих зависимостях или о других ошибках, мы перенаправляем все сообщения, предназначенные для stderr, в /dev/null (то есть, просто отбрасываем их).

    5. Всё остальное передаётся grep для проверки на то, содержится ли там упоминание вредоносных пакетов. Если такой пакет будет найден, программа сообщит об этом с указанием пути к нему.

▍Поиск «заражённых» проектов в Windows


Если вы работаете в Windows, вот PowerShell-скрипт, который написал Кори Уэзерс. Делает он то же самое, что и только что рассмотренная программа для Mac и Linux.

Get-ChildItem $directory -Directory -Recurse -Include "node_modules" | foreach { cd $_.FullName; cd ..; npm ls | Select-String -Pattern "babelcli|crossenv|cross-env\.js|d3\.js|fabric-js|ffmepg|gruntcli|http-proxy\.js|jquery\.js|mariadb|mongose|mssql\.js|mssql-node|mysqljs|nodecaffe|nodefabric|node-fabric|nodeffmpeg|nodemailer-js|nodemailer\.js|nodemssql|node-opencv|node-opensl|node-openssl|noderequest|nodesass|nodesqlite|node-sqlite|node-tkinter|opencv\.js|openssl\.js|proxy\.js|shadowsock|smb|sqlite\.js|sqliter|sqlserver|tkinter"} -ErrorAction Ignore

▍Как понять, что был найден вредоносный пакет?


Вот как выглядит экран при обнаружении вредоносного пакета. Мы, в данном случае, в демонстрационных целях, искали пакет express.


Красным отмечено сообщение о найденном вредоносном пакете

▍Что, если вредоносный пакет найден?


В подобной ситуации следует немедленно поменять все секретные данные, которые были сохранены в переменных окружения. Речь идёт, например, о паролях доступа к учётным записям, об API-ключах, и так далее. Если уязвимость найдена в проекте, над которым ведётся совместная работа, не забудьте оповестить об опасности всех разработчиков. Помните о том, что системы непрерывной интеграции и облачные хостинги так же используют переменные окружения. Поэтому, если один из подобных проектов попал в продакшн, или использует систему, в которой имеются переменные окружения, примите меры к тому, чтобы данные, которые могли попасть к злоумышленнику, оказались бесполезными.

▍Если ничего не найдено — значит всё хорошо?


Приведённые выше скрипты просто проверяют наличие в проектах npm-пакетов, об опасности которых мы знаем. Однако, экосистема npm огромна, поэтому нельзя с уверенностью утверждать, что в ней нет других опасных пакетов. В любом случае, полезно периодически менять пароли и бережно хранить ценные данные.

Кроме того, следует внимательно относиться, например, к тому, как используются сервисы, учётные данные которых хранятся в переменных окружения. Скажем, если речь идёт об аккаунте на Twilio, подозрение должен вызвать неожиданный скачок числа телефонных звонков или сообщений.

Итоги


Если окажется так, что вы обнаружите подозрительный npm-пакет, обязательно сообщите об этом в службу безопасности npmjs.com, написав им по адресу security@npmjs.com. Они исследуют ситуацию и, если опасения подтвердятся, удалят из реестра опасный пакет, а, возможно, и несколько пакетов.
Вредоносные npm-пакеты — явление сравнительно новое. Надеемся, все вместе мы сможем справиться с этой угрозой.

Уважаемые читатели! Доводилось ли вам сталкиваться с подозрительным поведением npm-пакетов?