TanStack и МНОГИЕ другие пакеты взломаны: подробный разбор и анализ
MMaximilian Schwarzmüller
Computing/SoftwareBusiness NewsInternet Technology
Transcript
00:00:00Прямо сейчас происходит еще одна крупная, действительно масштабная атака на цепочку поставок,
00:00:06и она перекинулась из NPM в экосистему Python, так что, возможно, сейчас лучше не устанавливать
00:00:12никакие пакеты NPM или Python. И убедитесь, что ваша система в целом настроена безопасно. У меня есть видео
00:00:19на эту тему, я оставлю ссылку в описании и вернусь к этому здесь, но сначала я хочу
00:00:23рассказать подробности о том, что именно пострадало, и как узнать, затронуло ли это вас. Все началось с
00:00:30пакетов TanStack: TanStack query, TanStack router, TanStack start и так далее. Вчера, 11 мая,
00:00:36за довольно короткий промежуток времени несколько вредоносных пакетов, а фактически все пакеты TanStack,
00:00:43были опубликованы с вредоносными версиями, но атаку удалось локализовать быстро, в течение 20 минут.
00:00:50В итоге угрозу обнаружили и устранили оперативно, но все эти вредоносные пакеты успели выйти
00:00:57в этот короткий отрезок времени. А затем атака начала распространяться дальше, и она все еще
00:01:03распространяется. Она затронула пакеты Mistral, у которых всего четыре пользователя, но даже они
00:01:09пострадали, потому что это вредоносное ПО работает как червь: крадет данные и учетные данные,
00:01:16возможно, и ваши, если оно попало в систему. Я вернусь к тому, как проверить вашу систему,
00:01:20буквально через секунду, но вирус продолжил заражать новые пакеты NPM, так как в этом и заключалась идея,
00:01:26а затем добрался и до экосистемы Python, и это происходит прямо сейчас. Этой новости всего несколько часов,
00:01:32буквально два часа на момент записи этого видео. Итак, как узнать, затронуло ли это вас?
00:01:39Если вы устанавливали любой пакет TanStack вчера вечером (в моем случае по немецкому
00:01:45времени), вы должны считать себя пострадавшим. Если установка была в это время — имейте в виду,
00:01:54что время указано в UTC, так что пересчитайте на свой часовой пояс — тогда считайте,
00:02:00что вы под ударом. Но поскольку вирус перекинулся на пакеты Mistral и на множество других JavaScript-пакетов,
00:02:06которых слишком много, чтобы перечислять, вам стоит считать свою машину скомпрометированной.
00:02:13Я поделюсь ссылками на посты ниже, чтобы вы могли изучить вопрос подробнее и увидеть полный список
00:02:18всех затронутых пакетов по мере их появления. Но, как я уже сказал, атака продолжается,
00:02:22поэтому, возможно, сейчас лучше вообще ничего не устанавливать. Также есть индикаторы компрометации.
00:02:31Стоит проверить определенные хэши файлов, SHA-хэши, для роутера в JS-файле. Я тоже дам ссылку на пост.
00:02:38И если у вас есть возможность отслеживать сетевые запросы на вашей машине,
00:02:42ищите исходящий трафик на этот URL — это будет еще одним четким индикатором того,
00:02:48что данные были украдены из вашей системы. Что именно означает «компрометация»? Это значит,
00:02:55что это вредоносное ПО делает две основные вещи. Первое и самое важное — сбор данных. Оно
00:03:03ищет токены NPM, токены GitHub, учетные данные AWS и другие секреты. Оно сканирует систему на предмет
00:03:12типичных мест хранения паролей и ключей, собирает их и отправляет на тот самый
00:03:18URL, который я показывал. То есть крадет секреты. Но это еще не все. Как я уже упоминал,
00:03:26оно действует как червь, поэтому использует украденные токены GitHub.
00:03:33Например, оно использует их вместе с токенами NPM для публикации новых зараженных пакетов. Если вы
00:03:40сопровождаете какой-то пакет или если у вас запущен рабочий процесс CI/CD в этот период,
00:03:46зависящий от пакетов TanStack, то в этот процесс CI/CD подтянулись вредоносные,
00:03:53скомпрометированные пакеты TanStack. Зловредный код мог там выполниться. И тогда внутри этого процесса
00:04:00(то есть не на вашей машине, а именно в CI/CD) он мог украсть учетные данные,
00:04:06чтобы опубликовать вредоносную версию того пакета, который собирал ваш рабочий
00:04:14процесс. Вот так он и распространяется. Как я уже сказал, он ведет себя как червь. Он использует
00:04:20украденные данные и токены для выпуска новых зараженных пакетов. Именно так он попал в
00:04:26в Mistral, в другие JavaScript-пакеты и даже в экосистему Python. И на этом
00:04:32И, насколько мне известно, заражение продолжается. Как от этого защититься?
00:04:39Я сделал видео об этом на своем другом канале, AkataMind. Ссылка тоже будет внизу.
00:04:44Если вкратце: нужно стараться запускать код или вести разработку
00:04:51не напрямую на основной машине, а в виртуальной машине или в dev container, или в чем-то подобном.
00:04:57Не храните секреты в открытом виде на компьютере. Например, для AWS
00:05:03лучше использовать Single Sign-On вместо хранения учетных данных IAM на диске,
00:05:10и применяйте аналогичные техники для других сервисов. Кроме того,
00:05:16рассмотрите использование сервисов типа InPhysical или Doppler для хранения ваших секретов
00:05:25в облаке, а не на жестком диске в файлах .env. Это то, что стоит сделать.
00:05:30Опять же, я подробно говорю об этом в том видео. Также используйте пакетные менеджеры
00:05:38и настройки, позволяющие задать минимальный возраст релиза, как это делает Bun.
00:05:44В файле bunfig.toml можно установить минимальный возраст, гарантирующий, что даже
00:05:49при выполнении bun install вы установите только те пакеты, которым исполнилось хотя бы X секунд или дней.
00:05:56У pnpm есть похожая функция, и в последних версиях npm она тоже появилась.
00:06:02Я разбирал это в другом видео. Если вы используете Bun или правильно настроили npm,
00:06:09(а в Bun это включено по умолчанию), то это также блокирует выполнение,
00:06:15например, скриптов post-install — скриптов жизненного цикла устанавливаемых пакетов.
00:06:21Это дает дополнительный уровень защиты, так как подобные вирусы обычно полагаются
00:06:28на выполнение таких скриптов в вашей системе. Итак: защищенный пакетный менеджер и его
00:06:36конфигурация, запуск кода в виртуалке или dev container и отказ от хранения секретов в тексте.
00:06:41Это общие правила, но сейчас они актуальны как никогда, потому что подобные атаки
00:06:46будут становиться все серьезнее. Давайте разберем, как именно сработала эта атака, это очень любопытно.
00:06:52Конечно, таких случаев становится больше. Я записываю подобные видео почти каждый месяц,
00:06:58а может и чаще, потому что, во-первых, их стало проще организовывать.
00:07:04В эпоху ИИ легче анализировать пакеты и зависимости, которые вы хотите заразить,
00:07:12изучать их исходный код или настройки CI/CD на предмет потенциальных векторов атак.
00:07:22Именно это произошло с TanStack. Не компьютер разработчика был взломан,
00:07:28а был атакован сам процесс CI/CD TanStack. Я к этому еще вернусь.
00:07:34С помощью ИИ проще искать уязвимости и проще писать код, в том числе и вредоносный.
00:07:40В то же время мы видим взрывной рост объемов ПО — кода пишется больше, чем когда-либо.
00:07:45Становится больше мишеней, включая те, где безопасности уделяется мало внимания.
00:07:51Это делает такие атаки еще более привлекательными для злоумышленников.
00:07:57С чего же все началось? Это очень интересно. Как я сказал, подход не новый,
00:08:03мы такое уже видели, но реализация довольно продуманная. Команда TanStack опубликовала
00:08:09постмортем — статью с объяснением причин. Ссылку я тоже оставлю.
00:08:15Но я дам вам краткую выжимку прямо сейчас, потому что атака строилась
00:08:22на трех основных шагах, которые я разберу подробно. Схема «Pull request target pwn request».
00:08:30Объясню, что это. Затем отравление кэша GitHub Actions через границу доверия форков
00:08:38и извлечение OIDC-токена из оперативной памяти. Что все это значит? Опять же,
00:08:45детали есть в статье, но давайте пройдемся по сути. Начнем со схемы
00:08:50«pull request pwn request». Что это такое? Для начала нужно понимать,
00:08:58что GitHub Actions — это CI/CD решение от GitHub. Кстати,
00:09:05у меня есть курс по GitHub Actions, если хотите научиться настраивать процессы,
00:09:10использовать продукт для CI/CD, публиковать пакеты или сайты и так далее.
00:09:16Как и все подобные инструменты, GitHub Actions опирается на события, которые запускают процессы,
00:09:24ведь суть CI/CD в автоматизации. Например, автоматический выпуск вашего сайта
00:09:29или его развертывание при пуше в основную ветку (main).
00:09:34Есть разные события-триггеры. «Push» — одно из них,
00:09:40когда вы говорите: «При пуше в ветку main я хочу выполнить определенные задачи».
00:09:44Например, установить зависимости, собрать проект и загрузить его на сервер.
00:09:49Вот что можно сделать. Другой триггер — «pull_request_target».
00:09:56Этот триггер срабатывает, когда в ваш репозиторий поступает запрос на слияние (pull request).
00:10:05Это означает, что любой человек может сделать форк вашего репозитория, что-то там изменить,
00:10:14запушить в свой форк и открыть PR в ваш проект. И это запустит рабочий процесс.
00:10:19Звучит опасно? Так и есть. С этого и началась атака.
00:10:25Существует также триггер «pull_request».
00:10:31Он работает похоже, но в этом случае CI/CD запускается
00:10:38в контексте форкнутого репозитория. То есть любые вредоносные действия
00:10:45происходят в форке, а не в базовом репозитории. Это не проблема.
00:10:52«pull_request_target», напротив, запускается в контексте базового репозитория. И это,
00:10:58конечно, потенциально опасно, так как открыть PR может кто угодно. Именно
00:11:04это и случилось в атаке на TanStack: в этот PR, в этот
00:11:10форк злоумышленник включил вредоносный код (червя) прямо в репозиторий TanStack,
00:11:20точнее в его копию. А когда атакующий открыл PR,
00:11:26это привело к срабатыванию «pull_request_target». После чего запускается агент GitHub
00:11:33Actions, и он выполняется в контексте основного репозитория. Что это значит?
00:11:40Это не дает атакующему прямого доступа к основному коду или возможности влить вредоносный код
00:11:46в репозиторий, но это означает, что, к примеру, используемый там кэш
00:11:53будет доступен для последующих запусков GitHub Actions из основного репозитория,
00:12:00даже вызванных другими событиями, например, обычным «push».
00:12:05Следующим шагом стало отравление кэша. Что это значит?
00:12:11Атакующий добавил в свой форк код, который при запуске
00:12:17через «pull_request_target» выполнял команду «hash files» (поддерживаемую GitHub Actions),
00:12:23чтобы сохранить нечто в кэш GitHub Actions. Зачем вообще нужен
00:12:28этот кэш? Его идея проста: ускорить выполнение рабочих процессов.
00:12:33Вы можете хэшировать зависимости. Смысл в том, что
00:12:39если зависимости вашего пакета не менялись, зачем заново проходить весь процесс
00:12:46установки? Это тратит время, а время — деньги, так как вы платите за
00:12:52минуты работы GitHub Actions. Никто не хочет, чтобы процессы шли бесконечно.
00:12:56Обычно при сборке пакетов TanStack
00:13:00вы сначала устанавливаете зависимости, а потом переходите к самой сборке.
00:13:06Опять же, если зависимости не изменились,
00:13:12зачем их переустанавливать? В этом суть кэширования, и это разумно. Проблема в том,
00:13:18Проблема в том, что выполнение GitHub Actions для цели pull request и другие запуски GitHub Actions,
00:13:24например, для триггера push, имеют один и тот же контекст и используют общий кэш. И именно
00:13:31здесь происходит отравление кэша, потому что злоумышленник смог кэшировать вредоносную версию или
00:13:39внедрить вредоносный код в зависимость TanStack и закэшировать её. После этого злоумышленнику
00:13:46оставалось лишь дождаться запуска обычного рабочего процесса GitHub Actions для пакетов TanStack.
00:13:53То есть, когда какой-то мейнтейнер отправит код, этот другой запуск GitHub Actions повторно
00:14:01использует тот же кэш, который был подготовлен вредоносным запуском ранее, и подтянет
00:14:08подготовленный отравленный кэш с вредоносным кодом. Вот так вредоносный код
00:14:13попал из форка в обычный процесс выполнения GitHub Actions при обычном пуше от обычного мейнтейнера,
00:14:21который никак не был затронут вредоносным кодом. В итоге кэш стал своего рода
00:14:28транспортным средством между этими двумя запусками GitHub Actions. И на третьем этапе, как только
00:14:35событию пуша, он украл краткосрочный токен NPM (OIDC-токен),
00:14:44чтобы выпустить вредоносную версию пакета TanStack. О чем речь? У NPM есть функция
00:14:54«доверенная публикация» (trusted publishing). Теоретически она делает выпуск пакетов безопаснее,
00:15:00потому что есть два пути публикации. Первый — создать токен в аккаунте
00:15:04NPM и использовать его вручную. Проблема в том,
00:15:11что если такой токен украдут, кто угодно сможет выпустить новую версию. Для повышения
00:15:19безопасности NPM предлагает: «Нет, не публикуйте со своего ПК, используйте доверенного
00:15:26провайдера, например, GitHub Actions». Интеграцию можно настроить,
00:15:33и тогда в рамках процесса запрашивается временный
00:15:37токен для публикации. Этот временный токен затем используется для подписи
00:15:44новой версии пакета. Считается, что его трудно украсть, так как он не
00:15:50хранится на компьютерах разработчиков и живет недолго. Но если сам код,
00:15:57выполняющийся в CI/CD и запрашивающий этот токен, заражен,
00:16:03то у него есть доступ к этому свежему краткосрочному токену. Это и случилось.
00:16:08Вредоносный код использовал токен для публикации новой
00:16:15версии пакета TanStack. Интересно, что атака немного «провалилась»,
00:16:21хотя токен был получен и использован для обращения к API NPM
00:16:27с целью выпуска версии с червем. Однако сам рабочий процесс
00:16:36GitHub Actions завершился с ошибкой из-за проблем в коде, который был запушен.
00:16:44Если бы атакующие выбрали момент, когда пушится валидный код,
00:16:52рабочий процесс завершился бы успешно. Им бы даже не пришлось
00:16:58публиковать пакет вручную через API — они бы внедрили код в процесс,
00:17:06он бы доработал до конца, и скомпрометированная версия TanStack вышла бы в свет,
00:17:12выглядя абсолютно легитимно. Но из-за того, что процесс упал,
00:17:19внешнему контрибьютору стало проще заметить неладное.
00:17:26Стало видно, что вышла новая версия TanStack, хотя рабочий
00:17:32процесс GitHub Actions зафейлился — значит, обновлений быть не должно. Это несовпадение
00:17:38помогло быстро раскрыть атаку, так что мейнтейнерам TanStack и всем нам повезло.
00:17:45Тем не менее, это была очень сложная атака, которая сработала
00:17:51без взлома чьих-либо компьютеров. И хотя её быстро пресекли, ущерб
00:18:00оказался серьезным, ведь заражение продолжается. Получился длинный
00:18:05GitHub Actions завершился сбоем, поэтому новая версия не должна была выйти. Можно было увидеть
00:18:12это несоответствие, что облегчило обнаружение атаки, и в этом плане
00:18:19разработчикам TanStack и всем нам повезло. Тем не менее, это довольно продуманная атака,
00:18:26так что это не конец. Не факт, что все будущие атаки будут
00:18:32замечены так же оперативно. Здесь была доля удачи, иначе ущерб мог быть
00:18:41еще масштабнее. Но он и так велик, и это еще не финал.
00:18:49Я уверен, что мы увидим больше подобных атак, потому что площадь
00:18:56атаки растет. Всё больше людей пишут код, многие не до конца
00:19:05понимают, что они делают, а ИИ помогает злоумышленникам. Вот такие дела.
00:19:11Если нет острой необходимости — лучше пока ничего не устанавливайте, проверьте
00:19:18свои настройки. Все ссылки для глубокого изучения и списки
00:19:24затронутых пакетов вы найдете в описании.
00:19:31становится всё больше и интереснее: код пишет всё больше людей, многие из которых
00:19:36не до конца понимают, что делают, а ИИ помогает в проведении таких атак. В общем, вот что
00:19:42сейчас происходит. Если нет острой необходимости, лучше ничего не устанавливайте, проверьте настройки, а
00:19:48все ссылки вы найдете ниже, если захотите изучить вопрос подробнее и увидеть полный список
00:19:51затронутых пакетов и прочего.
Community Posts
No posts yet. Be the first to write about this video!
Write about this video