[Перевод] Провоцирование сбоев браузера при помощи поведенческого фаззинга

image

В этой статье я расскажу вам, как я использовал фаззинг, чтобы найти несколько сбоев в Firefox. Обычно целью фаззинга является нахождение сбоя, указывающего на повреждение памяти, но моя цель заключается в другом: я хочу обнаружить неожиданную реакцию браузера. Это могут быть символы, которые открывают или закрывают необычный тег, или, возможно, символы, которые игнорируются парсером JavaScript. Такое неожиданная реакция часто может быть использована для проведения XSS-атак, минуя фильтры безопасности и избегая песочницы JavaScript.

Первая ошибка, о которой я хочу поговорить — это как закрыть HTML-комментарий по-другому. Если Вы читали спецификацию HTML, вы знаете, что комментарий можно закрыть с помощью --> или --!>. А как же сделать это иначе? Отличный вопрос для начала фаззинга! Вам просто нужно сгенерировать код, который даст ответ.

Еще в 2008 году, когда я собрал Shazzer для фаззинга поведения браузера, я был ограничен примерно 10 000 направлениями на страницу. Сегодня, в 2019 году все работает быстрее, поэтому мы можем фаззить намного чаще. Кроме того, использование DOM ускоряет фаззинг, потому что вам больше не нужно добавлять каждое направление к текущему документу. Стоит отметить, что это ненадежный подход, поскольку вы можете получить разные результаты. Действительно, я нашел случаи, когда DOM допускает пустые значения (NULL) в аргументах атрибутов, таких как href, но парсер HTML так не делает. Это все еще некритичные сбои, но вы не всегда можете доверять результатам, чтобы получить полное представление о том, что будет делать парсер HTML. Однако в большинстве случаев он работает, и это гораздо быстрее, чем вывод HTML с серверной стороны.

Первый шаг уже сделан — у нас есть вопрос: «Какие символы могут закрыть HTML-комментарий?». Чтобы ответить на него, нам нужно использовать существующие символы, которые закроют HTML-комментарий и фаззить символы, которые мы не знаем. Следующий шаг — использование соответствующих программ для фаззинга. В моем случае я использую свой инструмент Hackvertor, но с помощью локального веб-сервера можно добиться тех же результатов. Идея этого инструмента заключается в том, чтобы поместить вводимые данные в поле ввода, немного преобразовать теги и сделать что-то с выводом. Так как нам нечего конвертировать, мы можем поместить наш код непосредственно в поле вывода. Поэтому нажмите на область вывода текста и создайте массив для хранения отфаззенных символов и элемент div для тестирования HTML:

log = [];
div=document.createElement('div');


Затем нам нужно отфаззить более 1000000 символов Юникода или, точнее, 0×10ffff. Простой цикл for — это все, что нам нужно:

for(i=0;i<=0x10ffff;i++){


Затем мы повторно используем элемент div, который мы создали для каждого символа. В этом случае я тестирую позицию после!, так что символ будет введен после!… Затем я использую элемент img, чтобы увидеть, был ли фаззинг успешным. Если этот элемент существует, то HTML-комментарий был закрыт, и у нас есть некоторые интересные символы!

div.innerHTML = '';


Наконец, с помощью querySelector мы проверяем, существует ли img и добавляем символы в логи. Затем я закрываю оператор if и цикл for. Наконец, ввожу результаты в поле ввода слева:

if(div.querySelector('img')){
 log.push(i);
 }
}
input.value=log


Вот полная версия кода. Вам нужно открыть URL в Firefox, а затем поместить вводимые символы в поле вывода и нажать кнопку «Execute JS», чтобы фаззировать символы. После завершения фаззинга вы должны увидеть цифры в поле ввода, они соответствуют кодам символов, которые были успешными. На момент написания материала Firefox (версия 67) все еще допускает новые символы строки — \n и \r — после!, чтобы закрыть комментарий. Мне сообщили, что это исправлено в будущих версиях Firefox. Итак, последний этап фаззинга заключается в сборке вашей полезной нагрузки, это довольно просто. Вам нужно заменить код символа символом и добавить полезную нагрузку XSS:


Вы можете снова использовать Hackvertor для проверки его работы, вставив вышеуказанное в поле вывода, а затем нажав «Test HTML». Должно появиться окно предупреждения, потому что Firefox (версия 67) разрешает новую строку как часть заключительного комментария.

Так что это позволило нам найти некритичную ошибку в парсере HTML Firefox. Давайте найдем ещё одну! Нам нужен новый вопрос: «Какие символы могут открыть HTML-комментарий?». Вместо того, чтобы выйти за рамки существующего HTML-комментария, мы теперь будем использовать HTML-комментарий, чтобы выйти за рамки существующего атрибута HTML. Как я уверен, вы все знаете, что можно открыть HTML-комментарий с »>';
Таким образом, символ, который мы фаззим, будет находиться после первого дефиса. Если символ успешно создает открывающий HTML-комментарий, он будет комментировать элемент div и, таким образом, выходить из атрибута title. На этот раз, когда мы запускаем «Execute JS», получаем два результата в Firefox (версия 67):»0,45». Код 45 ожидаем, потому что это символ дефиса, но 0 является NULL символом! Это означает, что Firefox интерпретирует последовательность

document.body.innerHTML = '
';


Давайте перейдем на JavaScript вместо HTML. Я протестировал каждый браузер, и мне жаль Mozilla, но Firefox снова творит какую-то дичь. Я вдохновился тем, что фаззинг из твита jinmo123 использует новые интересные фичи ES6 для вызова функций без скобок. Вопрос, который я придумал для фаззинга, был: «какие символы разрешены после операторов in или instanceof?». Затем мы снова создаем код в Hackvertor, он следует аналогичному шаблону, но на этот раз не использует DOM. Сначала создаем массив и цикл for:

log = [];
for(i=0;i<=0x10ffff;i++){


Тогда мы будем использовать eval вместо innerHTML для фаззинга наших значений. Сначала нам нужно использовать блок try catch, чтобы обнаружить любые исключения, вызванные недопустимыми символами.

try{
eval("/a/"+String.fromCodePoint(i)+"instanceof function(){}");


Функция eval используется, чтобы увидеть, является ли наш JavaScript допустимым. Если да, то она перейдет к следующей строке, если нет, выдаст исключение, которое будет замечено, а затем перейдет к следующему символу. Следующая строка просто регистрирует символ, а потом закрывает блок try catch и цикл for. Затем функция выводит результаты в поле ввода.

log.push(i);
}catch(e){}
}
input.value=log


Если вы запустите этот код с помощью «Execute JS», вы получите кучу результатов! Firefox игнорирует множество символов. Если вы попробуете код на Chrome, вы получите более разумные результаты. Найдите код символа в поле ввода, который вы хотите использовать, в моем случае это было »1114110» или »0×10fffe» в hex. Теперь мы создадим наш вектор JavaScript:

eval("1337"+String.fromCodePoint(1114110)+"in"+String.fromCodePoint(1114110)+"alert(1337)");


Вы также можете представить его внутри скрипта SVG:

hv92k2ivxpvq3-2faoms6akr9hg.png

На DEDIC.SH доступны новейшие двухпроцессорные конфигурации выделенных серверов с процессорами Intel Scalable 2019 года:

  • 2x Xeon Silver 4214 — суммарно 24 ядра
  • 2x Xeon Gold 5218 — суммарно 32 ядра
  • 2x Xeon Gold 6240 — конфигурация с 36 ядрами.


Стоимость сервера с двумя Xeon Silver 4214 — от 15210 руб/мес
Так же мы готовы собрать для Вас любую конфигурацию — напишите нам!

Если большие мощности выделенного сервера не требуются — VDS от 150 руб/мес — то, что вам нужно!

© Habrahabr.ru