Это история о том, как я нашел 10.000 репозиториев в GitHub, в которых находится ссылка на скачивание zip архива. В этом архиве — троян. Все эти репозитории от разных контрибьюторов, с разным названием и не являются форками других репозиториев. Но у всех них есть одинаковый паттерн, который и позволил написать скрипт для поиска таких репозиториев.
Начало
У меня есть проект в гитхабе и я хотел проверить, проиндексировали ли его поисковые системы. Ввёл название проекта в Google, в выдаче появился мой репозиторий. Ввёл такой же запрос в Bing, в выдаче появился чужой репозиторий. С таким же названием и описанием. Там была копия моего репозитория со всеми коммитами, а я был указан в списке контрибьюторов. Но час назад был отправлен еще один коммит с изменением readme. В нём добавилась ссылка на zip архив.
Я выбирал подходящие теги для другого моего проекта в гитхабе. Перешел по этим тегам, чтобы посмотреть аналогичные продукты. В списке нашел репозиторий, название и описание которого полностью совпадают с еще одним репозиторием из этого списка. Оказалось, что в нем также скопированы все коммиты этого репозитория, а 2 часа назад в readme была добавлена ссылка на zip архив.
Понаблюдав за этими двумя репозиториями, я выяснил, что они каждые несколько часов удаляют предыдущий коммит и снова отправляют такой же коммит. В этом коммите только 1 изменение: добавление ссылки на архив в readme файл.
Я отправил запрос в поддержку гитхаба с просьбой удалить эти репозитории. За 2 недели ничего не изменилось, поддержка гитхаба не ответила. Я обсудил с ИИ, что еще можно с этим сделать, но полезных советов он не дал. Я открыл обсуждение на гитхабе, ответили 3 человека, с таким же ИИ слопом без какой-либо пользы.
Еще через месяц поддержка гитхаба прислала мне письмо о том, что они удалили эти репозитории.
Вы можете открыть другие подобные репозитории, посмотреть последний коммит и увидеть, что несколько часов назад в readme была добавлена ссылка на zip архив:
https://github.com/Dicrida123/java-sdk
https://github.com/A2A-MC/ccresume
https://github.com/1-RAY-1/project-startup-cursor
https://github.com/123abukhaled0/FinCoach
Zip архив содержит 4 файла:
— Application.cmd или Launcher.cmd
— loader.exe или luajit.exe или another_name.exe
— random_name.cso или random_name.txt
— lua51.dll
Если указать ссылку на архив в virustotal, он найдет 0 вирусов.
Если отправить zip файлом, он найдет в нём троян.
Продолжение
Казалось, я уже забыл об этом событии, но моё подсознание не забыло. И часто подсознание подкидывает мне интересные идеи когда я сплю или просыпасюь. Недавно я проснулся и в ту же секунду понял, что мне нужно сделать. Мне нужно составить общий паттерн, а затем написать скрипт, который проанализирует все репозитории гитхаба и найдет среди них те, которые попадают под этот паттерн.
Паттерн для поиска:
— Каждые несколько часов удаляется предыдущий коммит и отправляется новый
— В коммите обновляется только readme файл
— В readme файле находится ссылка на zip архив
— Коммиты скопированы с другого репозитория
— Это новый репозиторий, а не форк
— У всех репозиториев разные контрибьюторы и разные названия
Из последних 2 пунктов становится понятно, что даже если мы найдем один такой репозиторий, мы не сможем по нему найти другие подобные репозитории. Но в гитхабе 500 миллионов репозиториев. Как нам их все проанализировать? Гитхаб позволяет делать 5.000 запросов в час с одним токеном. Для каждого репозитория нам надо сделать несколько запросов для получения списка коммитов, измененных файлов и контента readme файла. Я не хотел ждать год, пока скрипт проанализирует все репозитории.
Но ведь нам не нужны все репозитории, нам нужны только те, которые обновляются каждые несколько часов. Я нашел сервис gharchive, с которого можно скачать все события гитхаба за любой день. Значит нам нужно получить события за последние дни, найти из них пуш коммитов, и найти репозитории, которые обновляются от 2 до 10 раз каждые 10 часов.
За последние 5 дней было 16 миллионов пушей коммитов. Из них всего 3.000 репозиториев, которые обновляются каждые несколько часов.
Но в событиях нет информации о том, какие именно файлы были изменены. Значит для каждого подходящего репозитория нам нужно сделать дополнительные запросы к API гитхаба.
После запуска сприпт выдал много репозиториев. Я добавил в фильтры несколько параметров:
— Коммит должен быть от пользователя, а не от бота
— Между последним коммитом и предпоследним прошло более месяца
— В репозиториях больше одного контрибьютора
После этого нашлось только 14 репозиториев, которые полностью совпадают с паттерном. И мне не давал покоя вопрос, почему нашлось так мало репозиториев? Какая вероятность того, что я наткнулся на эти репозитории 2 месяца назад и их всего 14 штук по всему гитхабу? Ведь их должно быть гораздо больше. Представьте, какой был бы заголовок этой статьи, если бы я нашел миллион таких репозиториев, ну или хотя бы тысячу.
Но я смирился с тем, что их всего 14, и начал писать эту статью. Я решил перепроверить их еще раз, чтобы не добавить в статью лишние репозитории по ошибке. И какого же было мое удивление, когда я увидел, что все они обновлялись последний раз 20 часов назад. Значит параметр «обновляются каждые несколько часов» был вообще не правильный. Фильтр отбросил все репозитории, которые обновляются редко.
Еще при ручной проверке я увидел репозитории, в которых есть ссылка на zip архив и есть недавний коммит, но в нём 0 изменений. А фильтр учитывал только репозитории, в которых был изменен 1 файл readme в последнем коммите.
Еще я заметил, что последний коммит во всех этих репозиториях называется одинаково: «Update README.md».
Я поменял фильтр. Теперь скрипт искал репозитории, которые обновлялись от 1 до 24 раз каждые 24 часа. Таких репозиториев нашлось 40.000.
Репозиториев, которые полностью совпадают по паттерну — 10.000. Это 25% от общего количества.
Каждый из этих репозиториев содержит zip архив с трояном.
Эти репозитории существуют много месяцев, некоторые даже больше года, гитхаб их автоматически не детектит и не удаляет.
Полный список репозиториев я опубликовал на GitHub.
Скрипт для поиска таких репозиториев: Git Malware Finder
Открытые вопросы
1. Почему они копируют только новые репозитории, а не популярные?
2. Зачем они удаляют коммит и отправляют новый каждые несколько часов?
3. Почему гитхаб не детектит такие репозитории автоматически?
4. Что именно делает исполняемый exe файл из архива?
5. Какой реальный масштаб этой схемы?
Мои предположения
Задача хакеров — понять, как работает система, найти в ней ограничения и уязвимости, и воспользоваться этой информацией. Если перезаписывание коммитов помогает обойти алгоритмы безопасности гитхаба, то они этим воспользовались. Возможно, по этой же причине каждый коммит называется «Update README.md».
Вторая задача это распространение вируса. Как сделать так, чтобы люди его нашли и скачали? Думаю для этого они копируют только новые репозитории и сразу попадают в топ выдачи поисковых систем по низкочастотным запросам. И они добавляют эти репозитории в популярные теги гитхаба, чтобы увеличить шанс индексации, и чтобы люди нашли эти репозитории из этих тегов.
Но почему они копируют все коммиты и контрибьюторов? Ведь они могли просто скопировать весь исходный код? Это возможно сделано для доверия. Когда человек заходит в репозиторий, он видит контрибьюторов, может в них перейти и увидеть, что это не аккаунты однодневки. И сохраняется история коммитов, чтобы было понятно, что репозиторий появился не вчера. Но возможно это также сделано для обхода алгоритмов гитхаба.
Это только мои предположения, а реальность может быть совершенно другая.
Заключение
У меня было ограничение API гитхаба на 5.000 запросов в час. Я оптимизировал скрипт для поиска только подходящих репозиториев, и думаю из-за фильтра скрипт нашел только малый процент репозиториев. У команды гитхаба таких ограничений нет. Они могут проанализировать все 500 миллионов репозиториев, найти в них любые архивы или исполняемые файлы и проверить их на вирусы.
На этот раз я не буду отправлять запрос в GitHub. Репозиториев слишком много. Если у кого-то из вас есть прямой контакт со службой безопасности гитхаба, отправьте им ссылку на эту статью.
ссылка на оригинал статьи https://habr.com/ru/articles/1048986/