В cdnjs, предоставляемой компанией Cloudflare сети доставки контента, предназначенной для ускорения доставки JavaScript-библиотек, выявлена критическая уязвимость, позволяющая выполнить произвольный код на серверах CDN. Опасность проблемы усугубляется тем, что сервисом пользуется для загрузки JavaScript-библиотек около 12.7% всех сайтов в интернете и компрометация инфраструктуры позволяет подменить библиотеки, отдаваемые любым из этих сайтов.
Сервис cdnjs осуществляет загрузку пакетов из Git или репозитория NPM, после чего даёт возможность любому сайту бесплатно воспользоваться сетью доставки контента Cloudflare для ускорения загрузки JavaScript-библиотек. Проблема вызвана тем, что в коде cdnjs, обеспечивающем загрузку и распаковку NPM-пакетов в архивах tgz, используется штатный модуль archive/tar на языке Go, которые выдаёт список файлов как есть, без нормализации путей. В случае, когда скрипт распаковывает содержимое на основании выданного списка, наличие в архиве файлов вида “../../../../../../../tmp/test” может привести к перезаписи произвольных файлов в системе, насколько это позволяют права доступа.
Было предположено, что атакующий может подать заявку на добавление свей библиотеки в cdnjs и загрузить в репозиторий NPM специально оформленный архив, содержащий файлы с символами “../” в пути. На серверах cdnjs периодически выполняется операция “autoupdate”, в ходе которой обработчик загружает новые версии предложенной библиотеки и распаковывает содержимое. При помощи файлов c путями “../” атакующий может добиться перезаписи файлов со скриптами сервиса и выполнения своего кода на сервере на котором производилась распаковка.
В случае загрузки обновлений из Git было выяснено, что загружающий обновления обработчик не учитывал символические ссылки при копировании файлов из Git. Данная особенность позволяла организовать чтение любых файлов с сервера через добавление в Git символических ссылок.
Эксперименты с демонстрацией взлома cdnjs для получения премии на HackerOne было решено начать с проверки гипотезы относительно чтения файлов. В Git-репозиторий отдаваемой через CDN JavaScript-библитеки была добавлена символическая ссылка test.js, указывающая на файл /proc/self/maps. После публикации новой версии библиотеки обработчик обновлений в обработал данный репоизиторий и опубликовал указанный файл в cdnjs (test.js был создан как символическая ссылка и при запросе данного файла выдавалось содержимое /proc/self/maps).
Подставив символическую ссылку на файл /proc/self/environ автор исследования заметил, что внутри отданных данных присутствуют значения переменных окружения GITHUB_REPO_API_KEY и WORKERS_KV_API_TOKEN. В первой переменной хранился ключ к API для доступа с правом записи в репозиторий robocdnjs на GitHub. Во второй переменной хранился токен к хранилищу KV в cdnjs. Воспользовавшись полученными сведениями злоумышленник мог внести изменения в cdnjs и полностью скомпрометировать инфраструктуру.