Глава 7. JavaScript без букв и цифр
Содержание
Все началось с того, что пользователи форума бездельников (slackers) заметили неожиданный новый пост Йосуке Хасэгавы, выдающегося японского
исследователя безопасности. В посте он подробно описал, как вы можете выполнять JavaScript не применяя буквенно-цифровые символы. Это стало
для всех нас откровением, и мы начали анализировать как это работает. Основная идея состояла в том, чтобы для создания строк использовать
квадратные скобки и выражения JavaScript, а затем для доступа к строкам и их объединения под создание допустимых имён свойств и, в
конечном итоге, написания произвольного JavaScript без буквенно-цифровых символов применять числовые индексы, также основанные на выражениях.
Это также стало известно как JSF*ck. Я скрыл букву "u", чтобы в этой книге не отображались нецензурные слова. С этого момента я буду
называть его подходящим для семьи названием "без букв и цифр" JavaScript, или не-альфа JS. Чтобы создать не-альфа JS, вам сначала нужен
способ генерации числа, а поскольку JavaScript обладает слабой типизацией, вы можете осуществить это при помощи инфиксного оператора
"+", данный оператор попытается преобразовать следующее выражение в число или
NaN (Not a number - не число), когда нет возможности такого преобразования. Итак, первый шаг — получение
нуля:
1 +[]//0
Отлично, итак мы обладаем нулём, но это позволит нам получать лишь самый первый символ строки:
1 'abc'[+[]]//a
Но как мы можем получать "b"? Ладно, вы можете сочетать метод доступа квадратных скобок
с неким массивом и получать ссылку на элемент в таком массиве, а JavaScript позволяет вам увеличивать/уменьшать на единицу это значение так же,
как будто это было идентификатором:
1 [+[]]//создаёт массив с 0 в нём
2
3 [+[]][+[]]//получает самый первый элемент в этом массиве
4
5 ++[+[]][+[]]//увеличивает на единицу самый первый элемент в этом массиве для создания 1
6
7 'abc'[++[+[]][+[]]]//сочетает все приведённое выше для получения b
Надеюсь, вы следите за ходом действий. Возможно, стоит попробовать каждый отдельный фрагмент кода и оценить его в консоли чтобы понять что происходит. Как только вы усвоите эту концепцию, вы сможете легко приступать к выработке строк и чисел. Вам просто необходимо просто вкладывать вырабатываемые массивы и продолжать увеличивать их и объединять буквы для формирования свойств JavaScript. Давайте сгенерируем число два, а я буду пользоваться пробелами чтобы различать числа:
1 ++[ ++[+[]][+[]] ] [+[]]//2
Обычно вы не пользуетесь пробелами. Я только что добавил их с тем, чтобы было проще отслеживать. Итак, из приведённого выше кода вы можете
наблюдать, что при помощи +[] вы создаёте массив, в котором содержится ноль, затем вы получаете доступ
к самому первому элементу в этом массиве, снова применяя +[], а потом вы применяете оператор приращения
для увеличения числа, которое потом завёртываете в другой массив и следуете тем же самым процессом, причём становится трудно читать при
вложениях дальше и дальше, но как только вы освоите эту концепцию, вы будете способны её писать.
Из своего текста мы способны получить "c":
1 'abc'[++[ ++[+[]][+[]] ] [+[]]]
Ну, у нас имеются основы выработки чисел без буквенно- цифровых символов, но как вы сгенерируете строки? Мы снова воспользуемся преимуществами
слабой типизации JavaScript для преобразования различных типов в строки. Например, давайте посмотрим на логические значения, мы способны
извлечь символы "f", "a",
"l", "s"
"e" из false и мы можем выполнить аналогичный процесс,
который мы осуществляли для чисел, но на этот раз мы будем применять булев оператор not,
данный оператор вернёт false если его операнд можно преобразовать в
true и наоборот. Это означает, что мы можем воспользоваться пустым массивом снова и преобразовать его в
булев:
1 ![]//false
Когда мы получаем булево значение, нам необходимо преобразовать его в строку чтобы мы были способны выделять необходимые символы. Для выполнения этого мы просто производим его конкатенацию с другим массивом, что оформляет строку с логическим значением и пустым массивом, который преобразуется в пустую строку:
1 ![]+[]//false (строка)
Великолепно, итак теперь у нас имеются символы, но как их выделить? Мы можем последовать тому же процессу что и ранее, мы можем поместить своё выражение вовнутрь массива и получить самый первый элемент в этом массиве (нашей строке), а затем воспользоваться индексом для получения отдельного символа:
1 [![]+[]]//добавляем строковое значение false в массив
2 [![]+[]][+[]]//получаем самый первый элемент своего массива
3 [![]+[]][+[]][+[]]//f - получаем самый первый символ из данной строки
Затем вы можете следовать этим же процессом для всех остающихся символов и просто увеличивать значение индекса, как мы это делали для инкрементации своих чисел. Самый простой способ выполнения этого заключается в выполнении этого для пометки вашего выражения комментария, как я это и сделали последующей комбинации их, таким образом, нам требуется значение следующего символа, стоящего в позиции один. Если мы вернёмся к фрагменту его кода для и скопируете это будет так, как приведено ниже:
1 ++[+[]][+[]]//1
Затем получим false из другого примера:
1 [![]+[]][+[]]//false (строка)
Теперь соединим вместе строку false и средство доступа к значению числа:
1 [ ![]+[]] [+[]] [ ++[+[]][+[]] ]//a
Для ясности я выше добавил пробелы. Когда вы собираете символы, целесообразно сохранять их в текстовом файле с комментариями, чтобы показывать
что они собой представляют, это упрощает создание новых строк. Надеюсь, вы теперь достаточно уверенно создаёте такие символы. Давайте
продолжим создавать оставшиеся символы для false.
1 [ ![]+[]] [+[]] [ ++[++[+[]][+[]]][+[]] ]//l
Вам ясно что я сделал выше. Я просто изменил значение части доступа из своего предыдущего фрагмента кода вновь для увеличения значения числа. Я обернул его в массив, получил самый первый элемент этого массива и увеличил его на единицу. Вы можете проделать это с оставшимися символами:
1 [ ![]+[]] [+[]] [ ++[++[++[+[]][+[]]][+[]]][+[]] ]//s
2 [ ![]+[]] [+[]] [ ++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]] ]//e
Как вы можете наблюдать в приводимом выше сопоставлении, при создании символов "s" и
"e" требуется лишь небольшое изменение. На самом деле, мы можем повторно применять
весь этот процесс для создания противоположности true, которая выступает
false. Итак, помните, когда мы обнаружили, что ![] вырабатывает
false? Если мы снова воспользуемся логическим оператором not,
он преобразует это в true:
1 !![]//true
Мы просто заменяем одиночный восклицательный знак в каждом из выработанных ранее примеров кода на двойной, скажем:
1 [![]+[]][+[]][+[]]//f
становится
1 [!![]+[]][+[]][+[]]//t
и так далее:
1 [ !![]+[]] [+[]] [ ++[+[]][+[]] ]//r
2 [ !![]+[]] [+[]] [ ++[++[+[]][+[]]][+[]] ]//u
У нас уже имеется "e", поэтому нам не нужно вырабатывать его снова. Теперь вы можете увидеть,
как довольно просто генерировать символы. Вы можете задуматься о том, как можно сгенерировать произвольный JavaScript. Ну, сначала вам нужно
получить доступ к функции, и для этого вам нужно сгенерировать некоторые символы, которые при использовании в качестве средства доступа получают
функцию, а затем вы можете применять эту функцию, чтобы получить её конструктор, который будет конструктором функции, Вы видите, куда это ведёт?
Получив доступ к конструктору Function, вы можете вызывать его для генерации произвольного JavaScript, но об
этом мы поговорим позже. Самый первый шаг состоит в получении функции, и очень удобно, что имеется хорошая короткая функция, к которой мы уже можем
получить доступ при помощи выработанных нами символов. Функция at позволяет вам получать один символ строки
или элемент массива в зависимости от того, для какого объекта вы её применяете. Мы собираемся применять это, потому как, очевидно, это длина
сортировки. Итак, сначала нам нужен пустой массив:
1 []
Затем мы добавляем средство доступа:
1 [] [ ]
Теперь мы добавляем строку "a" и соединяем её с
"t":
1 [] [ [ ![]+[]] [+[]] [ ++[+[]][+[]] ] /*a* + [!![]+[]][+[]][+[]] \
2 /*t*/ ]//функция at
Раз мы обладаем доступом к функции, мы получаем возможность выработки гораздо большего числа символов. Это обусловлено тем, что функция способна преобразовываться в строку:
1 [].at+''//function at() { [естественный код] }
Если мы ищем выработанные нами ранее символы, единственными остающимися для производства нами символами выступают
"o", "c",
"n". Мы можем сгенерировать "n" при помощи
undefined, что мы и выполняем далее. Сначала мы создадим пустой массив и испытаем доступ к первому
undefined символу:
1 [][+[]]//undefined
Затем мы преобразуем это в строку и выполним доступ ко второму символу с позицией один:
1 [[][+[]]+[]][+[]][++[+[]][+[]]]//n
Теперь мы можем выработать всё остальное для создания своего свойства конструктора. Для выработки остающихся символов мы можем повторно
воспользоваться функцией at, преобразуя её в строку, выработать необходимое положение и, в конце
концов, выделить его.
Сначала мы создаём пустой массив и получаем доступ к его первому элементу:
1 [][+[]]
Затем мы помещаем свою функцию вовнутрь этого массива и выполняем конкатенацию с пустым массивом для создания строки:
1 [ [] [[![]+[]][+[]][++[+[]][+[]]]+ [!![]+[]][+[]][+[]]] +[] ][+[]]
Мы можем повторно воспользоваться строкой выше для выработки "c":
1 [[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]
2 //function at() { [естественный код] } в качестве строки
3 [++[++[++[+[]][+[]]][+[]]][+[]]]//3
4 //совместно производят c
Самая первая приведённая выше строка вырабатывает функцию at в виде строки, вторая строка выполняет
доступ к третьей позиции этой строки, которая производит "c".
Для выработки "o" нам снова требуется следовать этим же процессом, но получить доступ к 6й
позиции строки:
1 [[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]
2 //function at() { [естественный код] } в качестве строки
3 [++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]]//6
4 //совместно производят o
В точности как с пазлом, мы можем совместить это вместе для получения доступа к самому свойству конструктора:
1 [[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]
2 [++[++[++[+[]][+[]]][+[]]][+[]]]
3 //c
4
5 +
6
7 [[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]
8 [++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]]
9 //o
10
11 +
12
13 [[][+[]]+[]][+[]][++[+[]][+[]]]//n
14
15 +
16
17 [ ![]+[]] [+[]] [ ++[++[++[+[]][+[]]][+[]]][+[]] ]//s
18
19 +
20
21 [!![]+[]][+[]][+[]]//t
22
23 +
24
25 [ !![]+[]] [+[]] [ ++[+[]][+[]] ]//r
26
27 +
28
29 [ !![]+[]] [+[]] [ ++[++[+[]][+[]]][+[]] ]//u
30
31 +
32
33 [[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]
34 [++[++[++[+[]][+[]]][+[]]][+[]]]
35 //c
36
37 +
38
39 [!![]+[]][+[]][+[]]//t
40
41 +
42
43 [[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]
44 [++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]]
45 //o
46
47 +
48
49 [ !![]+[]] [+[]] [ ++[+[]][+[]] ]//r
Выше я отделил все буквы и поместил оператор конкатенации строк в каждый раздел, чтобы вы могли наблюдать как это работает. Когда всё
формируется воедино, это выстраивает строку "constructor". Для получения доступа к
реальной функции- конструктору, нам необходимо воспользоваться функцией at(), к которой мы ранее в
этой главе уже получили доступ без её преобразования в строку:
1 [ [] [[![]+[]][+[]][++[+[]][+[]]]+ [!![]+[]][+[]][+[]]] ][+[]]
2 //функция at()
3 [//добавили квадратные кавычки для формирования доступа к предыдущей функции
4
5 [[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]
6 [++[++[++[+[]][+[]]][+[]]][+[]]]+[[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]\
7 ]]+[]][+[]]
8 [++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]]+[[][+[]]+[]][+[]][++[+[]\
9 ][+[]]]+[ ![]+[]] [+[]] [ ++[++[++[+[]][+[]]][+[]]][+[]] ]+[!![]+[]][+[]
10 ][+[]]+[ !![]+[]] [+[]] [ ++[+[]][+[]] ]+[ !![]+[]] [+[]] [ ++[
11 ++[+[]][+[]]][+[]] ]+[[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[
12 ]]
13 [++[++[++[+[]][+[]]][+[]]][+[]]]+[!![]+[]][+[]][+[]]+[[] [[![]+[]][+[]][++[+[]][+[]]\
14 ]+[!![]+[]][+[]][+[]]]+[]][+[]]
15 [++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]]+[ !![]+[]] [+[]] \
16 [ ++[+[]][+[]] ]
17
18 ]//добавили квадратные кавычки для формирования доступа к предыдущей функции
19
20 //всё это вместе создаёт конструктор Function
Мы получили доступ к конструктору Function, соединив функцию at(),
а добавляя [] после и внутри метода доступа мы разместили строку
"constructor", которая затем возвращает необходимый конструктор
Function. Теперь мы можем исполнить произвольный JavaScript, передавая конструктору
Function некую строку и вызывая её дважды.
Теперь нам просто нужно выработать строку для её отправки конструктору Function. Мы собираемся вызвать
alert(1) в качестве традиционной полезной нагрузки XSS. У нас уже есть буквы и цифра один:
1 [ ![]+[]] [+[]] [ ++[+[]][+[]] ]//a
2 [ ![]+[]] [+[]] [ ++[++[+[]][+[]]][+[]] ]//l
3 [ ![]+[]] [+[]] [ ++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]] ]//e
4 [ !![]+[]] [+[]] [ ++[+[]][+[]] ]//r
5 [!![]+[]][+[]][+[]]//t
6 ++[+[]][+[]]//1
Нам остаётся сгенерировать открывающую и закрывающую скобки. Для этого мы можем повторно воспользоваться кодом, в котором мы выработали
свою функцию at() и преобразовали это в строку и затем получить доступ к 6й позиции данной строки:
1 [[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]
2 //function at() { [естественный код] } в качестве строки
3 [++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]]//6
Нам всего лишь требуется увеличить значение шесть для получения одиннадцатой позиции:
1 [[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]//function at() { [естест\
2 венный код] } в качестве строки
3 [++[++[++[++[++[++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]\
4 ]][+[]]][+[]]][+[]]]//11
5 //который производит (
И увеличить приведённое выше на единицу:
1 [[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]
2 //function at() { [естественный код] } в качестве строки
3 [++[++[++[++[++[++[++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]][\
4 +[]]][+[]]][+[]]][+[]]][+[]]]//12
5 //который производит )
Нам просто нужно расположить эти части в верном порядке и передать их ранее выработанному конструктору и это всё. Не забывайте добавлять
к каждой из строк оператор канкатенации "+".
1 [ [] [[![]+[]][+[]][++[+[]][+[]]]+ [!![]+[]][+[]][+[]]] ][+[]]
2
3 [
4
5 [[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]
6 [++[++[++[+[]][+[]]][+[]]][+[]]]+[[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]\
7 ]]+[]][+[]]
8 [++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]]+[[][+[]]+[]][+[]][++[+[]\
9 ][+[]]]+[ ![]+[]] [+[]] [ ++[++[++[+[]][+[]]][+[]]][+[]] ]+[!![]+[]][+[]
10 ][+[]]+[ !![]+[]] [+[]] [ ++[+[]][+[]] ]+[ !![]+[]] [+[]] [ ++[
11 ++[+[]][+[]]][+[]] ]+[[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[
12 ]]
13 [++[++[++[+[]][+[]]][+[]]][+[]]]+[!![]+[]][+[]][+[]]+[[] [[![]+[]][+[]][++[+[]][+[]]\
14 ]+[!![]+[]][+[]][+[]]]+[]][+[]]
15 [++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]]+[ !![]+[]] [+[]] \
16 [ ++[+[]][+[]] ]
17
18 ]
19 (
20 [ ![]+[]] [+[]] [ ++[+[]][+[]] ]+//a
21 [ ![]+[]] [+[]] [ ++[++[+[]][+[]]][+[]] ]+//l
22 [ ![]+[]] [+[]] [ ++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]] ]+//e
23 [ !![]+[]] [+[]] [ ++[+[]][+[]] ]+//r
24 [!![]+[]][+[]][+[]]+//t
25 [[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]
26 //function at() { [естественный код] } в качестве строки
27 [++[++[++[++[++[++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]\
28 ]][+[]]][+[]]][+[]]]+
29 //(
30
31 ++[+[]][+[]]+//1
32 [[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]
33 //function at() { [естественный код] } в качестве строки
34 [++[++[++[++[++[++[++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]][\
35 +[]]][+[]]][+[]]][+[]]][+[]]]//12
36 //)
37 )
Я надеюсь, вы следовали за нами и теперь способны создавать JS без альфа! С этим кодом вы можете осуществить некоторые оптимизации,
например, сократить [![]+[]][+[]] до (![]+[]), в этом коде
присутствует большое число мест для уменьшения. В качестве упражнения попробуйте сократить приведённый выше код до минимально возможного,
тем самым вы больше узнаете о JavaScript и вскоре будете способны писать JS без альфа как обычный код.
Теперь, когда вы уверенно пишите не-альфа код, мы можем воспользоваться полученные в предыдущих главах знаниями чтобы попытаться создать не-альфа код без круглых скобок. Для этой задачи мы будем применять ограниченный набор символов, а именно:
1 []`+!${}
Как вы уже знаете, шаблонные строки способны выполнять JavaScript через заполнители, причём их можно применять и для передачи аргументов
функциям. Мы намерены неверно воспользоваться этим фактом дабы создать некую не- альфа последовательность, которая вызывает конструктор
Function с нашей строкой alert.
Мы можем повторно воспользоваться кодом из предыдущего раздела данной главы, потому как нам требуется доступ к конструктору
Function для передачи ему кода.
Мы намерены вызвать такой конструктор Function воспользовавшись помеченной строкой шаблона,
что просто означает, что мы намерены поместить `` после такой функции, а затем мы намерены
выработать свою строку для прохода к ней. Для представления аргумента конструктору Function мы
воспользуемся символом $, который мы не собираемся применять, но он необходим, поскольку мы не
можем контролировать первый отправляемый в нашу функцию аргумент. Чтобы разобраться с тем что происходит, попробуйте оценить данный
вызов функции чтобы увидеть возвращаемый результат:
1 Function`$${"x"}$`
2 /*
3 function anonymous($,$
4 ) {
5 x
6 }
7 */
Как мы наблюдаем выше, эта функция вызывается с двумя следующими друг за другом $, а третий
аргумент применяется для выработки кода. Самый первый аргумент преобразуется из массива в строку, поэтому нам надлежит помещать символы
долларов до и после соответствующего заполнителя. Если бы мы не применяли эти доллары, конструктор Function
возбудил бы исключительную ситуацию из- за недопустимого JavaScript. Очень удобно, что доллар является допустимым идентификатором JavaScript
и разрешён в качестве имени параметра. Мы можем повторно воспользоваться кодом из предыдущей главы, причём мы сначала поместим код
конструктора Function, затем доллар, потом наш заполнитель, который вырабатывает строку
alert, а затем следует ещё один доллар. Данный код завершается ``,
которая вызывает выработанную нами функцию:
1 [[][[![]+[]][+[]][++[+[]][+[]]]+ [!![]+[]][+[]][+[]]]][+[]][[[] [[![]+[]][+[]][++[+[\
2 ]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]
3 [++[++[++[+[]][+[]]][+[]]][+[]]]+[[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]\
4 ]]+[]][+[]]
5 [++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]]+[[][+[]]+[]][+[]][++[+[]\
6 ][+[]]]+[![]+[]][+[]][ ++[++[++[+[]][+[]]][+[]]][+[]]]+[!![]+[]][+[]][+[]]+[!![]+[
7 ]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][++[++[+[]][+[]]][+[]]]+[[][[![]+[]][+[]][++[+[]
8 ][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[!![]+[]][+[]]
9 [+[]]+[[][[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]][++[++[++[++[++[+
10 +[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]]+[!![]+[]][+[]][++[+[]][+[]]]]
11
12 `$${[ ![]+[]] [+[]] [ ++[+[]][+[]] ]+
13 [ ![]+[]] [+[]] [ ++[++[+[]][+[]]][+[]] ]+
14 [ ![]+[]] [+[]] [ ++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]] ]+
15 [ !![]+[]] [+[]] [ ++[+[]][+[]] ]+
16 [!![]+[]][+[]][+[]]+
17 [[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]
18 [++[++[++[++[++[++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]\
19 ]][+[]]][+[]]][+[]]]+
20 ++[+[]][+[]]+
21 [[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]
22 [++[++[++[++[++[++[++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]][\
23 +[]]][+[]]][+[]]][+[]]][+[]]]
24 }$` ``
После большого числа взломов на форуме бездельников, пытавшихся выяснить, что было возможно при помощи не-альфа кода, мы все пришли к выводу,
что минимальное ограничение, которым вы можете обладать для выполнения произвольного JavaScript, составляет шесть символов. Это стало известно
как великая стена символов. Предел обусловлен тем, что без ! вы не можете создавать логические значения,
а без + вы не можете конвертировать в целые числа и объединять строки, не используя больше символов.
Наиболее вероятный способ сломать эту стену — использовать следующую кодировку +* и найти способ
выработки логического значения. Это важно, потому что false содержит
"s", а true содержит
"r". Без этих символов вы не сможете построить свойство конструктора и, следовательно, не сможете
выработать требуемую строку, чтобы получить к нему доступ.
Если бы вы собрались попытаться сломать эту стену, вам необходимо было бы вырабатывать больше символов, потому как вы застряли бы с
"NaN" и "undefined". Ну, только с помощью
+[] можно выработать Infinity! Давайте посмотрим, как это
делается. Сначала мы собираемся выработать, как и раньше, число один, затем вам нужно сгенерировать неопределённую строку, и нам требуется
из неё "е". После этого вы просто объединяете больше единиц в конце, чтобы сформировать строку
"1e1111", которая производит Бесконечность Infinity.
1 [[] [[![]+[]][+[]][++[+[]][+[]]]+[!![]+[]][+[]][+[]]]+[]][+[]]
2 //function at() { [естественный код] } в качестве строки
3 [++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]]//6
Прежде всего вырабатываем 1:
1 ++[+[]][+[]]//1
Затем вырабатываем строку undefined:
1 [][+[]]+[]//undefined в качестве строки
Из строки undefined нам требуется получить доступ к из неё
"е":
1 [[][+[]]+[]][+[]][++[++[++[+[]][+[]]+[]][+[]]][+[]]]//e
Соединяем всё вместе для формирования 1e1111:
1 [++[+[]][+[]]+[[][+[]]+[]][+[]][++[++[++[+[]][+[]]+[]][+[]]][+[]]]+[++[+[]][+[]]]+[+\
2 +[+[]][+[]]]+[++[+[]][+[]]]+[++[+[]][+[]]]]
Наконец, нам необходимо преобразовать массив/ строку в число при помощью инфиксного оператора +
и, в конечном счёте, обернуть его в массив и получить к нему доступ как к строке:
1 [[+[++[+[]][+[]]+[[][+[]]+[]][+[]][++[++[++[+[]][+[]]+[]][+[]]][+[]]]+[++[+[]][+[]]]\
2 +[++[+[]][+[]]]+[++[+[]][+[]]]+[++[+[]][+[]]]]]+[]][+[]]
3 //Infinity в качестве строки
Вы можете видеть, насколько это близко к разрушению нашей стены, хотя отсутствие логических значений имеет решающее значение для доступа к конструктору. Мы можем только надеяться, что браузеры представят новые функции или методы, которые позволят нам получить доступ к необходимым символам. На данный момент стена символов выглядит как состоящая из шести.
В этой главе мы рассмотрели, как вырабатывать числа с помощью безбуквенно-цифрового JavaScript, как использовать эти числа для получения строк,
комбинировать эти строки, для получения большего числа символов через доступ к свойствам и преобразования вывода в строку. Затем я показал, как вы
можете собрать это воедино для получения исполнения произвольного кода JavaScript. После этого я продемонстрировал, как вырабатывать не-альфа код
без применения круглых скобок. Наконец, я познакомил вас с великой стеной символов и показал метод создания Infinity,
с применением только +[].