Джаваскриптовское
Вот вполне честная работающая программа на Джаваскрипте:
Можете запустить в браузере, если не верите (не бойтесь, не вирус). Должно вывалиться сообщение с текстом "1", всего-то.
Теперь собираем мозги обратно внутрь черепной коробки и разбираемся, как это работает по шагам. Итак:
$=[]
Все просто. Переменной под названием $ присваивается значение в виде пустого массива.
__=!$+$
__ как и $ - легальное название переменной. Чему она равна? !$ сначала превращает значение $ в булевский тип, потом делает отрицание. Массив (любой) всегда превращается в булевский true, значит, на выходе у нас false. Теперь пытаемся сложить false и [] . Джаваскрипт умеет складывать хоть яблоки с аэростатами, в таких случаях и те, и те сначала конвертятся в строчки, как правило. false становится "false", а [] - пустой строкой. Итого "false"
_=-~-~-~$
~ это побитовое отрицание, а _ это тоже легальное название переменной. Чтоб значение побитово отрицать, его сначала превращают в 32-битное число. Не можешь - научим. Сначала превратим в строку (пустую, как мы уже видели), потом распарсим строку как float (получается 0.0), потом float обрежем до целого, т.е просто 0. Браузеры поумнее обходятся без промежуточной стадии, но стандарт - в принципе - требует, чтоб численные значения представлялись в общем случае с плавающей точкой. Кроме, конечно, исключений, вроде битовых операций.
Да. Мы не еще закончили. ~$ у нас получилось побитовым отрицанием 0, т.е числом изо всех единичных битов, что, как известно, есть -1. -~$ это, стало быть, 1. В качестве несложного упражнения для читателя, оставляю убедиться, что -~x увеличивает любое число на единицу. Инкрементируем таким образом три раза, получаем _ = 3
Следующим шагом мы считаем
(__=!$+$)[_=-~-~-~$] или "false"[3]
Строчки в джаваскрипте ведут (почти) как массивы, поэтому мы берем элемент по индексу 3, и получаем букву "s".
({}+$)[_/_]
3 делим на 3, получаем 1 (обратите внимание, этот трюк используется несколько раз) {} - это пустой объект, + как и в прошлый раз, превращает его в строку. На сей раз строка будет "[object Object]" Так принято. Складываем с пустым-массивом-превращенным-в-пустую-ст року, ничего не меняется. У нас получился метод перевода значений в строки. Можно было бы написать ({}).toString() или '' + {} То же самое. (зато {} + '' даст совсем другой результат. Ладно, не будем отвлекаться) Берем от "[object Object]" элемент с индексом 1, это "о"
($_=!''+$)[_/_]
Это уже элементарщина. ! как мы знаем, превращает значение в булевское и логически отрицает. Пустая строчка превращается (в отличие, от пустого массива) в false, а ее отрицание в true, сложение с $ опять превращает значение в строчку, то есть "true" (заодно его сохраняем в переменную $_) , а от строки берется элемент 1, то есть "r"
$$=(($_=!''+$)[_/_] + $_[+$])
Первое слагаемое только что разобрали. Во втором мы считаем +$ что эквивалентно превращению значения переменной $ в число. Как мы уже проходили, это просто 0 Чему равно $_ мы тоже знаем - это "true" нулевой элемент от "true" - это "t" . Складывем с результатом предыдущего шага, выходит "rt". Нам "rt" еще понадобится, поэтому сохраняем его в переменную с мнемоническим именем $$
Теперь мы складываем вместе результаты предыдущих шагов получаем... "s" + "о" + "rt" то есть "sort"
Следите еще? Теперь мы почти выяснили, чему равняется под-выражение
($=[$=[]][(__=!$+$)[_=-~-~-~$]+({}+$)[_/_] +($$=($_=!''+$)[_/_]+$_[+$])])
Это же тоже самое что и
[]["sort"]
Как известно каждому ребенку, все объекты в джаваскрипте - это хэш-мапы, индексированные строчками. В том числе и массивы. У массивов, кроме собственно элементов есть еще и методы, они тоже индексированы строчками. x["sort"] это тоже что и х.sort В случае массива, у нас получается ссылка на функцию сортировки (по-простому можно было бы написать Array.prototype.sort, но кто ж так пишет?). Ее мы пока сохраняем в переменную $, стирая предыдущее значение.
Теперь у нас есть функция sort, которую и исполняем. Это происходит, когда интерпретатор доходит до () посреди выражения. Но sort это функция-метод, она обычно вызывается так:
[2,1].sort()
[1,2]
А что если ее выполнить просто так? Просто так в Джаваскрипте не бывает. Все функции выполняются на каком-то объекте. Если он явно не указан, то им будет глобальный объект window. Что будет, если отсортировать window? Ничего с ним не будет, у него нет элементов с номерами (можно добавить, но в эту степь мы не пойдем) sort вернет объект в исходном виде. Таким образом мы получили себе ссылку на глобальный объект window. Наше выражение сократилось до
window[__[_/_]+__[_+~$]+$_[_]+$$](_/_)
Почти все под-выражения мы уже встречали, кроме
_+~$
_ у нас равно 3, а с ~$ поступаем обычно. Превращаем $, который у нас теперь функция sort, в строчку, выходит "function sort() {\n [native code]\n}" (или что-то в этом духе, в зависимости от браузера). Затем парсим в число. Вообще-то получается NaN (Not a Number), что обычно означает ошибку, но джаваскриптовские побитовые операции так просто не сдаются. Для них NaN это ноль. Отрицание 0, как мы видели, равно -1. Значит, имеем 3+(-1)=2.
Подставляем значения всех переменных:
window["false"[1]+"false"[2]+"true"[3]+"r t"](1)
или
window["alert"](1)
Как уже обсуждалось, это то же самое, что выполнить функцию alert на глобальном объекте window с параметром 1. Иными, неинтересными, словами:
alert(1)
Что и происходит. Вот, собственно, и все дела. Теперь можно шутить про Перл.
Источник: код взят отcюда , куда попал с конференции Blackhat DC 2010, но автор остался не указан. Возможно, кто-то со sla.ckers.org, где третий год растет длиннючий тред на тему обхода защиты от межсайтового скриптинга. Если кто хочет поразбираться в наворотах джаваскрипта и HTML итп, то вам туда. Попробуйте побиться головой об клавиатуру - результат будет удивительно похож на представленный в треде код.
Update: В коментах на реддите дают ссылку на конвертор любого джаваскрипта в эквивалентный скрипт, состоящий только из символов []()+! К примеру, тот же
alert(1)
превращается в
($=[$=[]][(__=!$+$)[_=-~-~-~$]+({}+$)[_/_] +($$=($_=!''+$)[_/_]+$_[+$])])()[__[_/_] +__[_+~$]+$_[_]+$$](_/_)
Можете запустить в браузере, если не верите (не бойтесь, не вирус). Должно вывалиться сообщение с текстом "1", всего-то.
Теперь собираем мозги обратно внутрь черепной коробки и разбираемся, как это работает по шагам. Итак:
$=[]
Все просто. Переменной под названием $ присваивается значение в виде пустого массива.
__=!$+$
__ как и $ - легальное название переменной. Чему она равна? !$ сначала превращает значение $ в булевский тип, потом делает отрицание. Массив (любой) всегда превращается в булевский true, значит, на выходе у нас false. Теперь пытаемся сложить false и [] . Джаваскрипт умеет складывать хоть яблоки с аэростатами, в таких случаях и те, и те сначала конвертятся в строчки, как правило. false становится "false", а [] - пустой строкой. Итого "false"
_=-~-~-~$
~ это побитовое отрицание, а _ это тоже легальное название переменной. Чтоб значение побитово отрицать, его сначала превращают в 32-битное число. Не можешь - научим. Сначала превратим в строку (пустую, как мы уже видели), потом распарсим строку как float (получается 0.0), потом float обрежем до целого, т.е просто 0. Браузеры поумнее обходятся без промежуточной стадии, но стандарт - в принципе - требует, чтоб численные значения представлялись в общем случае с плавающей точкой. Кроме, конечно, исключений, вроде битовых операций.
Да. Мы не еще закончили. ~$ у нас получилось побитовым отрицанием 0, т.е числом изо всех единичных битов, что, как известно, есть -1. -~$ это, стало быть, 1. В качестве несложного упражнения для читателя, оставляю убедиться, что -~x увеличивает любое число на единицу. Инкрементируем таким образом три раза, получаем _ = 3
Следующим шагом мы считаем
(__=!$+$)[_=-~-~-~$] или "false"[3]
Строчки в джаваскрипте ведут (почти) как массивы, поэтому мы берем элемент по индексу 3, и получаем букву "s".
({}+$)[_/_]
3 делим на 3, получаем 1 (обратите внимание, этот трюк используется несколько раз) {} - это пустой объект, + как и в прошлый раз, превращает его в строку. На сей раз строка будет "[object Object]" Так принято. Складываем с пустым-массивом-превращенным-в-пустую-ст
($_=!''+$)[_/_]
Это уже элементарщина. ! как мы знаем, превращает значение в булевское и логически отрицает. Пустая строчка превращается (в отличие, от пустого массива) в false, а ее отрицание в true, сложение с $ опять превращает значение в строчку, то есть "true" (заодно его сохраняем в переменную $_) , а от строки берется элемент 1, то есть "r"
$$=(($_=!''+$)[_/_] + $_[+$])
Первое слагаемое только что разобрали. Во втором мы считаем +$ что эквивалентно превращению значения переменной $ в число. Как мы уже проходили, это просто 0 Чему равно $_ мы тоже знаем - это "true" нулевой элемент от "true" - это "t" . Складывем с результатом предыдущего шага, выходит "rt". Нам "rt" еще понадобится, поэтому сохраняем его в переменную с мнемоническим именем $$
Теперь мы складываем вместе результаты предыдущих шагов получаем... "s" + "о" + "rt" то есть "sort"
Следите еще? Теперь мы почти выяснили, чему равняется под-выражение
($=[$=[]][(__=!$+$)[_=-~-~-~$]+({}+$)[_/_]
Это же тоже самое что и
[]["sort"]
Как известно каждому ребенку, все объекты в джаваскрипте - это хэш-мапы, индексированные строчками. В том числе и массивы. У массивов, кроме собственно элементов есть еще и методы, они тоже индексированы строчками. x["sort"] это тоже что и х.sort В случае массива, у нас получается ссылка на функцию сортировки (по-простому можно было бы написать Array.prototype.sort, но кто ж так пишет?). Ее мы пока сохраняем в переменную $, стирая предыдущее значение.
Теперь у нас есть функция sort, которую и исполняем. Это происходит, когда интерпретатор доходит до () посреди выражения. Но sort это функция-метод, она обычно вызывается так:
[2,1].sort()
[1,2]
А что если ее выполнить просто так? Просто так в Джаваскрипте не бывает. Все функции выполняются на каком-то объекте. Если он явно не указан, то им будет глобальный объект window. Что будет, если отсортировать window? Ничего с ним не будет, у него нет элементов с номерами (можно добавить, но в эту степь мы не пойдем) sort вернет объект в исходном виде. Таким образом мы получили себе ссылку на глобальный объект window. Наше выражение сократилось до
window[__[_/_]+__[_+~$]+$_[_]+$$](_/_)
Почти все под-выражения мы уже встречали, кроме
_+~$
_ у нас равно 3, а с ~$ поступаем обычно. Превращаем $, который у нас теперь функция sort, в строчку, выходит "function sort() {\n [native code]\n}" (или что-то в этом духе, в зависимости от браузера). Затем парсим в число. Вообще-то получается NaN (Not a Number), что обычно означает ошибку, но джаваскриптовские побитовые операции так просто не сдаются. Для них NaN это ноль. Отрицание 0, как мы видели, равно -1. Значит, имеем 3+(-1)=2.
Подставляем значения всех переменных:
window["false"[1]+"false"[2]+"true"[3]+"r
или
window["alert"](1)
Как уже обсуждалось, это то же самое, что выполнить функцию alert на глобальном объекте window с параметром 1. Иными, неинтересными, словами:
alert(1)
Что и происходит. Вот, собственно, и все дела. Теперь можно шутить про Перл.
Источник: код взят отcюда , куда попал с конференции Blackhat DC 2010, но автор остался не указан. Возможно, кто-то со sla.ckers.org, где третий год растет длиннючий тред на тему обхода защиты от межсайтового скриптинга. Если кто хочет поразбираться в наворотах джаваскрипта и HTML итп, то вам туда. Попробуйте побиться головой об клавиатуру - результат будет удивительно похож на представленный в треде код.
Update: В коментах на реддите дают ссылку на конвертор любого джаваскрипта в эквивалентный скрипт, состоящий только из символов []()+! К примеру, тот же
alert(1)
превращается в
([][(![]+[])[!+[]+!+[]+!+[]]+(!![]+[][(! []+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]] +(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![ ]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]) [+!+[]+[+[]]]+(!![]+[])[+!+[]]+(!![]+[]) [+[]]][([][(![]+[])[+[]]+(![]+[]+[][[]]) [+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+ [])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![] +[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[] )[+!+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+ []+!+[]]]()[(![]+[])[+!+[]]+(![]+[])[!+[ ]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+ [])[+!+[]]+(!![]+[])[+[]]])(+!+[])