Се­год­ня в меню макаро­ны! Точ­нее, наг­лядная демонс­тра­ция того, как исполь­зовать фаз­зер Fuzzilli, что­бы искать уяз­вимос­ти в движ­ках JavaScript. Теории будет все­го чуть‑чуть, сос­редото­чим­ся на прак­тике. Быс­трень­ко соберем необ­ходимый инс­тру­мен­тарий, а затем прис­тупим к поис­ку багов при помощи фаз­зинга.

Рань­ше фаз­зить движ­ки JavaScript (те самые, что поз­воля­ют делать в бра­узе­ре пада­ющий снег или раз­рабаты­вать бэкен­ды на Node.js) было слож­но. Мутации JS-кода при­води­ли к син­такси­чес­ким ошиб­кам, что серь­езно замед­ляло работу. Сем­плы отбра­сыва­лись движ­ком, и при­ходи­лось генери­ровать новые и новые. На помощь приш­ли фаз­зеры на осно­ве грам­матики, но их при­мене­ние тоже не назовешь лег­ким.

В 2019 году иссле­дова­тель безопас­ности saelo пуб­лично открыл свою раз­работ­ку — фаз­зер Fuzzilli. Идея была в том, что­бы вмес­то JavaScript генери­ровать подобие байт‑кода, которое будет про­ще под­вергать мутаци­ям. Собс­твен­но, хоть в наз­вании и обыг­ран сорт пас­ты, про­исхо­дит оно от FuzzIL — Fuzzing Intermediate Language, про­межу­точ­ный язык для фаз­зинга.

Fuzzilli
Fuzzilli
 

Стенд

Для стен­да нам понадо­бит­ся вир­туаль­ная машина на Linux. Мож­но ска­чать готовую вир­туал­ку с сай­та osboxes.org, выб­рав дис­три­бутив по вку­су. Я в статье буду исполь­зовать Ubuntu 22.

Чем боль­ше ты выделишь вир­туал­ке ресур­сов, тем луч­ше. Фаз­зер показы­вает пок­рытие кода, и в зависи­мос­ти от мощ­ности машины на весь дви­жок может уйти от одно­го дня до нес­коль­ких недель.

Из инс­тру­мен­тов понадо­бит­ся Git, язык прог­рамми­рова­ния Swift (не путать с певицей), а так­же весь тул­чейн, нуж­ный для сбор­ки JS-движ­ка. Но об этом погово­рим чуть поз­же.

По­ка же запус­кай вир­туал­ку и вво­ди свой пароль.

Password=osboxes.org
echo $Password | sudo -S apt update
sudo apt upgrade -y
Update и upgrade
Update и upgrade

Какие бывают фаззеры

Фаз­зинг — это такой метод тес­тирова­ния, при котором в ПО вво­дят неп­равиль­ные, неожи­дан­ные или ран­домизи­рован­ные дан­ные, а фаз­зер отсле­жива­ет падения, сра­баты­вания встро­енных утвер­жде­ний (assert) и утеч­ки памяти.

Важ­ный параметр в фаз­зинге — это пок­рытие кода. По сути это про­цент задей­ство­ван­ного кода прог­раммы при выпол­нении опре­делен­ного набора тес­тов.

Фаз­зинг мож­но раз­делить на «тупой», или нес­трук­туриро­ван­ный, и «умный», или струк­туриро­ван­ный. Ког­да фаз­зер ничего не зна­ет о струк­туре вход­ных дан­ных прог­раммы, то это тупой фаз­зинг. Если зна­ет — умный.

Соз­дание вход­ных дан­ных делит­ся на генера­цию и мутацию. Генера­ция — это ког­да дан­ные соз­дают пол­ностью с нуля, мутация — ког­да изме­няют име­ющиеся.

Еще фаз­зеры мож­но раз­делить на тес­тиру­ющие методом чер­ного и белого ящи­ка — в зависи­мос­ти от того, какие у нас есть зна­ния об исходном коде.

Тес­тирова­ние методом чер­ного ящи­ка озна­чает пол­ное отсутс­твие дан­ных о струк­туре прог­раммы, в таком слу­чае фаз­зер соз­дает ран­домизи­рован­ные вход­ные дан­ные.

Фаз­зинг методом белого ящи­ка под­разуме­вает ана­лиз прог­раммы для повыше­ния пок­рытия кода. Нап­ример, сим­воличес­кое исполне­ние для обхо­да раз­ных час­тей прог­раммы. Но ана­лиз прог­раммы занима­ет боль­ше вре­мени, чем при фаз­зинге методом чер­ного ящи­ка.

Еще «ящик» может быть серым. В таком слу­чае мы при­меня­ем инс­тру­мен­тацию кода вмес­то ана­лиза прог­раммы. Это поз­воля­ет получать информа­цию о прог­рамме без ана­лиза. То есть что‑то сред­нее меж­ду белым и чер­ным ящи­ком. Получа­ется, мож­но быс­тро генери­ровать вход­ные дан­ные, но при этом узнать информа­цию о пок­рытии кода.

Фаз­зер Fuzzilli отно­сит­ся как раз к треть­ему виду. По типу генера­ции вход­ных дан­ных он сов­меща­ет в себе генера­цию и мутацию. По типу фаз­зинга он ско­рее «умный».

 

JavaScript-движки

Ос­новные час­ти движ­ка JavaScript — это пар­сер, интер­пре­татор и ком­пилятор.

JS-пайплайн
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 -y
git clone https://github.com/googleprojectzero/fuzzilli
Клонируем репозиторий
Кло­ниру­ем репози­торий

Те­перь перехо­дим на сайт Swift в раз­дел Download и ищем релиз для сво­его дис­три­бути­ва. Для Ubuntu 22 кача­ем релиз Ubuntu 22.04 x86_64.

Swift
Swift

Рас­паковы­ваем архив и копиру­ем пап­ку usr, что­бы уста­новить Swift. Пос­ле это­го убеж­даем­ся, что все кор­рек­тно нас­тро­ено.

Вот мини‑скрипт для ленивых. Если чита­ешь эту статью спус­тя мно­го лет, поменяй перемен­ные SwiftUrl на соот­ветс­тву­ющий URL со стра­ницы Swift.

# Установка Swift
Password=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
Ус­танов­ка Swift

Те­перь мы готовы к сбор­ке фаз­зера. Перехо­дим в пап­ку Fuzzilli и запус­каем сбор­ку.

cd fuzzilli && swift build -c release
Собираем Fuzzilli
Со­бира­ем Fuzzilli

Фаз­зер готов. Мож­но почитать раз­дел помощи, если есть желание.

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»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии