Один разработчик случайно наткнулся на 10 000 репозиториев на GitHub, распространяющих трояны. Всё началось с того, что он проверил в Bing, как проиндексирован его проект. Поиск выдал чужой репозиторий с тем же именем и описанием. Это была точная копия его кода, но час назад в README добавили ссылку на ZIP-архив. Потом он заметил такой же клон в списке похожих проектов по тегам. Оба репозитория обновлялись по одному шаблону: каждые несколько часов старый коммит удаляли и пушили новый — с единственным изменением в readme.
Автор обратился в поддержку GitHub. Две недели тишины. Он спросил совета у AI — без толку. Открыл тред — три ответа с бесполезным AI-слагом. Через месяц GitHub ответил, что репозитории удалили.
Но идея засела в подсознании. Однажды утром он проснулся с чётким планом: найти все такие репозитории по общему паттерну. Вскрылась закономерность: каждые несколько часов удаляется старый коммит, обновляется только README, в нём ссылка на архив. Репозиторий — не форк, а новый, с разными контрибьюторами и названиями. Связать их по цепочке нельзя.
Проблема: на GitHub 500 млн репозиториев. Один токен даёт 5000 запросов в час — ждать год. Но нужны только часто обновляемые. Автор использовал сервис gharchive.org, скачал события за несколько дней. Из 16 млн коммитов выделил 3000 репозиториев, которые правят каждые несколько часов. Потом добавил фильтры: коммит от человека, а не бота; перерыв между последним и предпоследним коммитом больше месяца; больше одного контрибьютора.
Сначала нашлось всего 14 штук. Показалось мало. Но когда он решил перепроверить, увидел, что все обновились 20 часов назад — фильтр "каждые несколько часов" работал неверно. Он заметил и другие репозитории: коммит есть, но изменений ноль. А все последние коммиты назывались "Update README.md".
После смены фильтра на "от 1 до 24 обновлений в сутки" скрипт нашёл 40 000 репозиториев. Из них 10 000 идеально совпали с паттерном. Каждый содержит ZIP-архив с трояном. В архиве четыре файла: Application.cmd или Launcher.cmd, loader.exe (или luajit.exe), файл со случайным именем .cso или .txt и lua51.dll. VirusTotal не видит вирус по ссылке, но находит троян при проверке самого архива.
Репозитории живут месяцами, некоторые больше года. GitHub их не удаляет автоматически. Автор выложил полный список и скрипт поиска на GitHub.
Зачем всё это? Гипотеза: хакеры клонируют только новые репозитории, которые сразу попадают в топ поиска по низкочастотным запросам. Копируют все коммиты и контрибьюторов, чтобы вызвать доверие. А перезапись коммитов с одним и тем же названием может обходить алгоритмы безопасности GitHub.
Автор не стал отправлять новый запрос в поддержку — их слишком много. Он просит читателей, у которых есть прямой контакт с командой безопасности GitHub, передать им ссылку на статью. В апреле выходила статья про 109 таких репозиториев со SmartLoader и StealC — там подробно описан механизм работы трояна.