Содержание статьи
Раньше фаззить движки JavaScript (те самые, что позволяют делать в браузере падающий снег или разрабатывать бэкенды на Node.js) было сложно. Мутации JS-кода приводили к синтаксическим ошибкам, что серьезно замедляло работу. Семплы отбрасывались движком, и приходилось генерировать новые и новые. На помощь пришли фаззеры на основе грамматики, но их применение тоже не назовешь легким.
В 2019 году исследователь безопасности saelo публично открыл свою разработку — фаззер Fuzzilli. Идея была в том, чтобы вместо JavaScript генерировать подобие байт‑кода, которое будет проще подвергать мутациям. Собственно, хоть в названии и обыгран сорт пасты, происходит оно от FuzzIL — Fuzzing Intermediate Language, промежуточный язык для фаззинга.
Стенд
Для стенда нам понадобится виртуальная машина на Linux. Можно скачать готовую виртуалку с сайта osboxes.org, выбрав дистрибутив по вкусу. Я в статье буду использовать Ubuntu 22.
Чем больше ты выделишь виртуалке ресурсов, тем лучше. Фаззер показывает покрытие кода, и в зависимости от мощности машины на весь движок может уйти от одного дня до нескольких недель.
Из инструментов понадобится Git, язык программирования Swift (не путать с певицей), а также весь тулчейн, нужный для сборки JS-движка. Но об этом поговорим чуть позже.
Пока же запускай виртуалку и вводи свой пароль.
Password=osboxes.org
echo $Password | sudo -S apt update
sudo apt upgrade -y
Какие бывают фаззеры
Фаззинг — это такой метод тестирования, при котором в ПО вводят неправильные, неожиданные или рандомизированные данные, а фаззер отслеживает падения, срабатывания встроенных утверждений (assert) и утечки памяти.
Важный параметр в фаззинге — это покрытие кода. По сути это процент задействованного кода программы при выполнении определенного набора тестов.
Фаззинг можно разделить на «тупой», или неструктурированный, и «умный», или структурированный. Когда фаззер ничего не знает о структуре входных данных программы, то это тупой фаззинг. Если знает — умный.
Создание входных данных делится на генерацию и мутацию. Генерация — это когда данные создают полностью с нуля, мутация — когда изменяют имеющиеся.
Еще фаззеры можно разделить на тестирующие методом черного и белого ящика — в зависимости от того, какие у нас есть знания об исходном коде.
Тестирование методом черного ящика означает полное отсутствие данных о структуре программы, в таком случае фаззер создает рандомизированные входные данные.
Фаззинг методом белого ящика подразумевает анализ программы для повышения покрытия кода. Например, символическое исполнение для обхода разных частей программы. Но анализ программы занимает больше времени, чем при фаззинге методом черного ящика.
Еще «ящик» может быть серым. В таком случае мы применяем инструментацию кода вместо анализа программы. Это позволяет получать информацию о программе без анализа. То есть что‑то среднее между белым и черным ящиком. Получается, можно быстро генерировать входные данные, но при этом узнать информацию о покрытии кода.
Фаззер Fuzzilli относится как раз к третьему виду. По типу генерации входных данных он совмещает в себе генерацию и мутацию. По типу фаззинга он скорее «умный».
JavaScript-движки
Основные части движка JavaScript — это парсер, интерпретатор и компилятор.
Все начинается с парсинга исходного кода на JavaScript. Строится абстрактное синтаксическое дерево (AST). На его основе создается байт‑код. Затем интерпретатор выполняет байт‑код.
Во время выполнения записывается разная информация — profiling data. В дальнейшем она используется при компиляции байт‑кода в машинный. Этим занимается компилятор.
Машинный код генерируется в тех случаях, когда какой‑то участок часто используется. Например, функция выполняется в цикле. Тогда выгоднее потратить время на его компиляцию и в дальнейшем выиграть во времени выполнения (ведь интерпретация идет медленнее).
Обычно применяется несколько компиляторов, и выбор происходит в зависимости от уровня оптимизации кода.
www
Подробнее о работе движков JS — в презентации «JavaScript engines: The Good Parts» (PDF, WebArchive).
Подготовка фаззера
Fuzzilli поставляется в виде исходного кода, написанного на языке Swift.
Для скачивания исходников понадобится Git, для сборки Fuzzilli — пакеты GCC, Binutils и, конечно, исходники фаззера. Ставим зависимости и клонируем репозиторий Fuzzilli.
Password=osboxes.org
echo $Password | sudo -S apt update
sudo apt install git binutils gcc -ygit clone https://github.com/googleprojectzero/fuzzilli
Теперь переходим на сайт Swift в раздел Download и ищем релиз для своего дистрибутива. Для Ubuntu 22 качаем релиз Ubuntu 22.04 x86_64.
Распаковываем архив и копируем папку usr
, чтобы установить Swift. После этого убеждаемся, что все корректно настроено.
Вот мини‑скрипт для ленивых. Если читаешь эту статью спустя много лет, поменяй переменные SwiftUrl
на соответствующий URL со страницы Swift.
# Установка SwiftPassword=osboxes.org
SwiftUrl=https://download.swift.org/swift-5.8.1-release/ubuntu2204/swift-5.8.1-RELEASE/swift-5.8.1-RELEASE-ubuntu22.04.tar.gz
SwiftTar=$(echo $SwiftUrl | sed 's:.*/::')SwiftFolder=${SwiftTar%.tar.gz}# Переходим домойcd $HOME# Качаем архивwget $SwiftUrl# Извлекаемtar -xzf $SwiftTar# Устанавливаемecho $Password | sudo -S cp -r $SwiftFolder/usr /
# Удаляем архивrm $SwiftTar# Удаляем папкуrm -rf $SwiftFolder# Тестовый запускswift --version
Теперь мы готовы к сборке фаззера. Переходим в папку Fuzzilli и запускаем сборку.
cd fuzzilli && swift build -c release
Фаззер готов. Можно почитать раздел помощи, если есть желание.
swift run -c release FuzzilliCli --help
Переходим к подготовке JS-движков. На главной странице репозитория инструкция гласит: «Скачайте исходный код движка. Скомпилируйте его, как описано в инструкции к нему в папке Targets». Для каждого движка там есть отдельная папка, в которой указано, как собрать движок для фаззинга.
Сборка и фаззинг V8
Теория
Начнем с движка браузера Google Chrome, он называется V8. Это движок JavaScript и WebAssembly, разработанный в Google, распространяется с открытым исходным кодом, написан на C++. Используется в Chrome, Node.js и множестве дериватив Chrome.
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»