На GitHub больше 1 000 уязвимых репозиториев: в чём суть угрозы и что с этим делать

Привет, Хабр! На связи технический директор MTC RED Денис Макрушин и команда Advanced Research Team: Павел Гусь, Иван Бессарабов и Андрей Сомсиков.

В январе разработчики GitLab нашли в своей системе две критические уязвимости. Из-за ошибок в верификации злоумышленники могут захватывать учётки пользователей и менять содержимое репозиториев. Такой тип атак называется RepoJacking. Мы изучили другой хостинг кода — GitHub — и нашли 1 300 потенциально уязвимых открытых репозиториев. Чем это опасно для разработчиков и их проектов — под катом.

76a2cd2d5a9f88c1dafe983391c43f43.jpg

Почему хакеры охотятся за уязвимостями в зависимостях

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

Большинство видов кибератак — фишинг, credentials stuffing, эксплуатация уязвимостей в периметре — не гарантируют результата.

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

Киберпреступникам на руку играет тренд на переиспользование готового кода. Например, для микросервисов доля зависимостей достигает 60–80%. Увеличивается как поверхность атаки, так и вероятность попадания хакером в целевую инфраструктуру.

Цепочка поставок — это и программные библиотеки, и компоненты, инструменты для разработки и доставки кода. Уязвимости в ней стали относительно дешёвым средством для получения качественного доступа к IT-инфраструктуре жертвы кибератаки.

Атаки на цепочку поставок в разработке ПО

Для защиты софта от атак на уязвимости в цепочке поставок есть фреймворк SLSA. Он контролирует разработку на каждом этапе. Но у SLSA есть ограничение: его авторы не рассматривают методы защиты зависимостей сборки. Эту работу выполним мы.

Типы атак

Типы атак

Из всех угроз конвейеру разработки выделим те, где атакуется конкретный артефакт:

  1. Repository hijacking (или RepoJacking) — атака на репозиторий или систему управления пакетами.

  2. Dependency confusion — это категория атак на зависимости пакета, чтобы внедрить вредоносный код в его репозиторий или сборку. Рекурсия: хакер атакует зависимости пакета, который сам является зависимостью для какого-то ПО.

  3. Typosquatting — создание вредоносного репозитория для его последующего внедрения в процесс сборки.

  4. Malicious code injection — любая runtime-атака, нацеленная на изменение логики работы программного пакета. Например, за счёт внедрения вредоносного компилятора.

Мы решили исследовать все эти угрозы и пошли с начала — с угроз типа RepoJacking — и прошерстили все (!) доступные репозитории на GitHub на уязвимость к ней. Мы взяли GitHub как самый популярный хостинг кода, но наш подход применим и к другим хранилищам программных пакетов.

Как искать уязвимости к атаке типа RepoJacking

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

Как происходит атака RepoJacking

  1. Разработчик напрямую подключает сторонний код из чужого репозитория к своему коду.

  2. Автор этого репозитория удаляет/переносит/продаёт свой аккаунт.

  3. Злоумышленник регистрирует или получает доступ к тому же аккаунту и размещает в нём вредоносный код.

  4. Все приложения, которые подключают код из этого репозитория, оказываются заражёнными.

Готово! Лёгкая победа для хакеров, стремящихся массово заражать зависимости.

Наше исследование не первое — их регулярно проводят и корпорации уровня Microsoft, и обычные ИБ-компании. Однако такая аналитика — ресурсоёмкая работа. Поэтому исследователи обычно ограничиваются небольшим процентом репозиториев на GitHub. А количество уязвимостей во всём хостинге кода вычисляется статистически.

Обычно исследователи рассматривают выборку в 2­-5% от доступного объёма репозиториев, вычисляют, например, что 0,1% из них уязвимы, и распространяют это значение на всю выборку.

Мы же решили вопрос кардинально — исследовали все репозитории, находящиеся в публичном доступе на GitHub. Так мы поимённо узнали уязвимые зависимости, а также разработали методику их поиска в вашем коде.

Для исследования мы проверили все репозитории через пакетные менеджеры PyPI и NPM, а также использовали открытый набор данных GitHub в Google BigQuery. Мы стремились найти ссылки на репозитории, аккаунты которых были перенесены или удалены. Всего собрали 6 349 287 репозиториев. Проверка показала, что 4,7 млн из них — уникальные. В них-то мы и будем искать ссылки на уязвимые репозитории.

Как мы искали уязвимые репозитории на GitHub и почему не всегда это было легко

Схема поиска уязвимостей в зависимостях GitHub

Схема поиска уязвимостей в зависимостях GitHub

Извлечение ссылок, ведущих на GitHub

У нас было три инструмента, через которые мы проверяли ссылки на репозитории GitHub: Google BigQuery, менеджеры PyPI и NPM.

Для получения полного списка репозиториев из Google BigQuery хватило стандартного запроса (SELECT * From 'bigquery-public-data.github_repos'). Это практически не составило труда, если не считать времени и ресурсов на обработку нескольких миллионов ссылок.

С PyPI тоже не возникло сложностей — мы написали парсер, в котором использовался метод подстановки имени пакета (https://pypi.org/project/{имя искомого пакета}) с дальнейшим изъятием значения (href) из элемента DOM-дерева сайта, ведущего на https://github.com/{Имя пользователя}/{Имя искомого пакета}.

Извлечение ссылок

Извлечение ссылок

Трудности возникли с пакетным менеджером NPM. Сначала мы действовали по аналогии с PyPI: перебрали методом подстановки имена пакетов (https://www.npmjs.com/package/{имя искомого пакета}) с дальнейшим изъятием значения (href) из элемента DOM-дерева сайта, ведущего на https://github.com/{Имя пользователя}/{Имя искомого пакета}.

Однако коллеги из NPM Inc защитили свой ресурс от парсеров: после каждого 3–5 запроса мы получали ошибку 429 от сервера (too many requests). Чтобы не ждать окончания тестирования вечность, мы использовали The Onion Router (aka Tor). Tor позволяет постоянно менять IP, поэтому ограничений на количество запросов не возникало. Это ускорило выполнение парсинга. Но мы слишком разогнались — стали получать от сервера ошибку 504 (gateway time-out). Компромисс нашли, замедлив скорость обращений. В комбинации этой опции с Tor удалось закончить опрос NPM в приемлемые сроки.

Получение битых ссылок и уязвимых репозиториев

Для поиска битых ссылок (corrupted links), по которым репозитории с кодом больше недоступны, мы воспользовались утилитой из набора Kali Linux — nuclei. Этот инструмент позволяет отправлять запросы на основе шаблонов с ожиданием заданного ответа. Для получения необходимого результата в шаблонах nuclei использовались две текстовые фразы: Sign in to GitHub и a GitHub Pages site here For root URLs, — эти сообщения выдаёт GitHub при обращении по битым ссылкам. Таким образом мы получили 7 820 corrupted links, то есть ссылок на репозитории, по которым на самом деле нет кода.

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

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

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

Чтобы узнать, сможем ли мы перерегистрировать на себя «битый» аккаунт, создали временный почтовый ящик и собрали список из 7 820 имён пользователей.

Далее в автоматическом режиме поочерёдно подставляли имена в поле для регистрации https://github.com/signup и ожидали ответ »{имя пользователя} is available» — это значило бы, что логин свободен для регистрации. Имена таких аккаунтов записывались в отдельный файл — это и есть наш список пользователей, подверженных атаке типа Repository Hijacking.

С каждого аккаунта может быть заведено множество репозиториев. Чтобы понять, сколько из них доступно для перерегистрации, мы построчно проверили, какие имена входят в список ссылок на репозитории в Google BigQuery.

Затем аналогичную операцию провели для менеджеров пакетов PyPI и NPM. Мы получили 1 363 ссылки на репозитории, относящиеся к уязвимым аккаунтам. К ним до сих пор может обращаться программный код. Насколько они востребованы — тема для последующих исследований.

Исследование в цифрах

Если перевести результаты исследования в цифры, то итоги таковы:

  • суммарно обработано 6 349 287 репозиториев кода:

    • из них уникальных репозиториев — 4 650 987

    • запросами в BigQuery через Google Cloud Сonsole найдено 3 325 634 репозитория, из них уникальных — 3 325 634

    • менеджер пакетов PyPI: 484 233 репозитория, из которых 293 470 уникальных

    • NPM: 2 539 420 репозиториев, из них уникальных — 1 031 884

  • суммарно обнаружено 7 820 битых ссылок:

  • суммарно легитимная перерегистрация пользователей возможна для 986 уникальных аккаунтов (их репозитории уязвимы для атаки RepoJacking):

    • из них 636 аккаунтов обнаружены через Google BigQuery

    • в PyPI — 294 аккаунта

    • в NPM — 56 аккаунтов

  • суммарно мы обнаружили репозиториев, подверженных кибератакам типа RepoJacking — 1 363:

    • через Google BigQuery — 937 репозиториев

    • PyPI — 352 репозитория

    • NPM — 74 репозитория

023b0e0154a9802fffc8882a7f809ddc.png

Всего уязвимых репозиториев от общего числа исследованных — 0,03%. Мелочь? И да, и нет. Важно не просто количество библиотек, но и то, как часто к ним обращаются. Это тема следующего исследования, а пока поделимся методикой для бесплатной проверки вашего кода на известные уязвимости RepoJacking.

Инструкция по бесплатной проверке программного кода на уязвимости RepoJacking

Разработчикам, которые хотят опередить атакующих, рекомендуем четыре простых действия:

  1. Извлеките все ссылки на git из вашего кода.

  2. Проверьте актуальность этих ссылок и убедитесь, что ни одна из них не возвращает ответ «Ошибка 404» или «Ошибка 301». Для этого можно использовать сканер nuclei с шаблоном для обнаружения атак типа subdomain takeover (атаки RepoJacking являются их подвидом).

  3. Исключите из кодовой базы все репозитории, которые возвращают ошибку 404 или 301.

  4. Не забудьте повторить пункты 1–3 в следующем релизе.

Более конкретно методика проверки кода описана здесь.

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

Если они это сделали до нашего исследования, то могли уже совершить атаку RepoJacking. Чтобы в будущем этого не произошло, рекомендуем несколько проактивных мер для создания кода без уязвимостей в зависимостях:

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

  2. Внедрите инструмент software composition analysis (SCA), даже если у вас в компании пока не построен процесс DevSecOps (безопасная разработка) и не используется какой-нибудь способ тестирования кода типа SAST/DAST.

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

  4. Если у вас уже сформирован Центр мониторинга (SOC), стоит учиться закрывать набор техник матрицы MITRE-атак Supply Chain Compromise: Compromise Software Dependencies and Development Tools, создавать инфраструктуру разработки и подбирать инструменты анализа компонентов программного обеспечения. Для поддержания информационной безопасности компании контролируйте код ещё с самого начала разработки.

Исследование никогда не заканчивается: планы на будущее

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

  1. Мы уже расширяем аналитику по полученным данным. Хотим понять, как часто программы обращаются по выявленным нами уязвимым ссылкам. Мы подсчитываем вес (частота встречаемости) для каждого уникального аккаунта и репозитория.

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

  3. И конечно, хотим расширить охват проверки доступности ссылок — не GitHub’ом единым. Не зря же мы начали статью с уязвимостей GitLab. Со временем добавим и другие ресурсы.

Будем рады, если вы в комментариях расскажете, полезно ли вам наше исследование? Оптимальна ли методика? Хотели бы вы присоединиться к будущим исследованиям?

© Habrahabr.ru