Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Сегодня в меню макароны! Точнее, наглядная демонстрация того, как использовать фаззер Fuzzilli, чтобы искать уязвимости в движках JavaScript. Теории будет всего чуть‑чуть, сосредоточимся на практике. Быстренько соберем необходимый инструментарий, а затем приступим к поиску багов при помощи фаззинга.
Раньше фаззить движки JavaScript (те самые, что позволяют делать в браузере падающий снег или разрабатывать бэкенды на Node.js) было сложно. Мутации JS-кода приводили к синтаксическим ошибкам, что серьезно замедляло работу. Семплы отбрасывались движком, и приходилось генерировать новые и новые. На помощь пришли фаззеры на основе грамматики, но их применение тоже не назовешь легким.
В 2019 году исследователь безопасности saelo публично открыл свою разработку — фаззер Fuzzilli. Идея была в том, чтобы вместо JavaScript генерировать подобие байт‑кода, которое будет проще подвергать мутациям. Собственно, хоть в названии и обыгран сорт пасты, происходит оно от FuzzIL — Fuzzing Intermediate Language, промежуточный язык для фаззинга.
Fuzzilli
Для стенда нам понадобится виртуальная машина на Linux. Можно скачать готовую виртуалку с сайта osboxes.org, выбрав дистрибутив по вкусу. Я в статье буду использовать Ubuntu 22.
Чем больше ты выделишь виртуалке ресурсов, тем лучше. Фаззер показывает покрытие кода, и в зависимости от мощности машины на весь движок может уйти от одного дня до нескольких недель.
Из инструментов понадобится Git, язык программирования Swift (не путать с певицей), а также весь тулчейн, нужный для сборки JS-движка. Но об этом поговорим чуть позже.
Пока же запускай виртуалку и вводи свой пароль.
Password=osboxes.org
echo $Password | sudo -S apt update
sudo apt upgrade -y
Update и upgrade
Какие бывают фаззеры
Фаззинг — это такой метод тестирования, при котором в ПО вводят неправильные, неожиданные или рандомизированные данные, а фаззер отслеживает падения, срабатывания встроенных утверждений (assert) и утечки памяти.
Важный параметр в фаззинге — это покрытие кода. По сути это процент задействованного кода программы при выполнении определенного набора тестов.
Фаззинг можно разделить на «тупой», или неструктурированный, и «умный», или структурированный. Когда фаззер ничего не знает о структуре входных данных программы, то это тупой фаззинг. Если знает — умный.
Создание входных данных делится на генерацию и мутацию. Генерация — это когда данные создают полностью с нуля, мутация — когда изменяют имеющиеся.
Еще фаззеры можно разделить на тестирующие методом черного и белого ящика — в зависимости от того, какие у нас есть знания об исходном коде.
Тестирование методом черного ящика означает полное отсутствие данных о структуре программы, в таком случае фаззер создает рандомизированные входные данные.
Фаззинг методом белого ящика подразумевает анализ программы для повышения покрытия кода. Например, символическое исполнение для обхода разных частей программы. Но анализ программы занимает больше времени, чем при фаззинге методом черного ящика.
Еще «ящик» может быть серым. В таком случае мы применяем инструментацию кода вместо анализа программы. Это позволяет получать информацию о программе без анализа. То есть что‑то среднее между белым и черным ящиком. Получается, можно быстро генерировать входные данные, но при этом узнать информацию о покрытии кода.
Фаззер Fuzzilli относится как раз к третьему виду. По типу генерации входных данных он совмещает в себе генерацию и мутацию. По типу фаззинга он скорее «умный».
Основные части движка JavaScript — это парсер, интерпретатор и компилятор.
JS-пайплайн
Все начинается с парсинга исходного кода на 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.
Swift
Распаковываем архив и копируем папку 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
Установка Swift
Теперь мы готовы к сборке фаззера. Переходим в папку Fuzzilli и запускаем сборку.
cd fuzzilli && swift build -c release
Собираем Fuzzilli
Фаззер готов. Можно почитать раздел помощи, если есть желание.
swift run -c release FuzzilliCli --help
Переходим к подготовке JS-движков. На главной странице репозитория инструкция гласит: «Скачайте исходный код движка. Скомпилируйте его, как описано в инструкции к нему в папке Targets». Для каждого движка там есть отдельная папка, в которой указано, как собрать движок для фаззинга.
Начнем с движка браузера Google Chrome, он называется V8. Это движок JavaScript и WebAssembly, разработанный в Google, распространяется с открытым исходным кодом, написан на C++. Используется в Chrome, Node.js и множестве дериватив Chrome.
Источник: xakep.ru