- PVSM.RU - https://www.pvsm.ru -

Почему анализ защищенности Java Script нельзя по настоящему автоматизировать?

Почему в случае JavaScript приходится обходиться простыми подходами статического анализа, когда есть более интересные подходы [1] к автоматическому анализу кода?

В ответ на этот вопрос, мой коллега Алексей Гончаров kukumumu [2] ответил лаконично: «Java Script это панковский язык» и кинул ссылку на статью Jasper Cashmore «A Javascript journey with only six characters» [3], которая действительно погружает нас в путешествие в эзотерический мир JSFuck и сразу все ставит на свои места.

Мне настолько понравилось, что я решил перевести статью на русский язык.

Перевод статьи “A Javascript journey with only six characters”

Javascript это странный и замечательный язык позволяющий нам писать чокнутый код который все равно работает. В этом нам помогает сам язык преобразуя данные в определенные типы на основе того как мы обращаемся с ними.

Если мы добавим строку символов к чему либо, JS предположит что мы хотим добавить текст, так что он преобразует тип данных в String. Если добавим знак плюс или минус, JS так же решит что мы имеем ввиду число и данные переводится в тип Number, если это возможно.

Если мы какие-то данные отрицаем, они переводятся в логический тип Boolean.
Мы можем эксплуатировать помощь Javascript чтобы проделать магические вещи используя только символы [,],(,),! и +.

Если вы это читаете не с мобильного устройства, можете открыть JS консоль чтобы проследить за нами и проверить работоспособность приведенных примеров просто скопировав их.

Начнем с основ. Основные правила которые нужно запомнить:

Начав с ! получаем тип Boolean
Начав с + получаем тип Number
Добавляя [] получаем тип String

Вот эти правила в действии:

![] === false
+[] === 0
[]+[] === ""

Еще одну вещь которую важно знать, это то что можно возвращать определенные символы из строк используя скобки, вот таким образом:

"hello"[0] === "h"

Кроме того, помните что можно получать цифры добавляя их составляющие в виде строк а потом переведя результат в тип Number используя правило №2:

+("1" + "1") === 11

Вот так вот. Теперь давайте комбинируем вышеперечисленное чтобы получить символ a.

![] === false
![]+[] === "false"
+!![] === 1
------------------------
(![]+[])[+!![]] === "a" // same as "false"[1]

Клево!

Получается, используя относительно простые комбинации мы можем получить любую из букв составляющих слова true и false. a,e,f,l,r,s,t,u. Как же мы можем получить остальные буквы?

Есть например еще undefined, который мы можем получить написав глупости типа [][[]]. Переводим в тип string используя одно из наших вышеперечисленных Основных Правил и мы дополнительно получаем буквы d,i и n.

[][[]] + [] === "undefined"

Из имеющихся букв, мы можем получить такие слова как fill, filter и find . Конечно можно получить и другие слова, но эти примечательны тем, все они являются методами массивов Array methods. Это значит что являются объекта Array и могут быть вызваны напрямую в массивах, например [2,1].sort().

Теперь, другая важная вещь которую нужно знать в Javascript это то что свойства объекта могут быть доступны с помощью нотаций dot notation или square bracket notation [4]. Т.к. Упомянутые выше методы массива являются свойствами самого массива, мы можем вызывать используя эти методы используя квадратные скобки вместо dot notation.

Так получается что [2,1]["sort"]() тоже самое что [2,1].sort().

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

[]["fill"]

Это процедуры function fill() { [native code] }. Мы можем превратить этот метод в строку снова используя наше золотое правило:

[]["fill"]+[] === "function fill() { [native code] }"

Вот мы и получили следующие символы: c,o,v,(,),{,[,],}, .

С нашими найденными c и o мы теперь сможем сформировать слово constructor. constructor это метод который имеют все объекты JS. Этот метод возвращает формирующую функцию:

Давайте получим презентацию формирующих функций для объектов с которыми мы до сих пор имели дело:


true["constructor"] + [] === "function Boolean() { [native code] }"  
0["constructor"] + []    === "function Number() { [native code] }"  
""["constructor"] + []   === "function String() { [native code] }"
[]["constructor"] + []   === "function Array() { [native code] }"

Из этого мы дополнительно получаем в наш арсенал следующие символы: B,N,S,A,m,g,y.

И мы теперь можем сформировать "toString", что является функцией которую мы можем использовать с квадратными скобками.

(10)["toString"]() === "10"

Но мы ведь и так можем превратить что угодно в строку, используя наше золотое правило, так как же это может быть полезно?

Но что я если я вам скажу что метод toString типа Number имеет секретный аргумент secret argument [5] под названием radix которое может изменить основание системы счисления заданного числа перед переводом в строку. Взгляните:

(12)["toString"](10) === "12" // base 10 - normal to us
(12)["toString"](2) === "1100" // base 2, or binary, for 12
(12)["toString"](8) === "14" // base 8 (octonary) for 12
(12)["toString"](16) === "c" // hex for 12

Но зачем останавливаться на 16? Максимум это 36, что по сути дает нам все символы от 0-9 и a-z. Так что мы можем вызвать любую цифру или букву:

(10)["toString"](36) === "a"
(35)["toString"](36) === "z"

Замечательно! Но как насчет других символов типа заглавных букв и знаков препинания? Копаем глубже:

В зависимости от того где выполняется ваш код, у вас может быть доступ к предустановленным объектам или данным. Если вы запускаете код в браузере, велики шансы что вы можете иметь доступ к некоторым методам HTML wrapper methods [6].

Например, bold это метод String который добавляет теги <b>.

"test"["bold"]() === "<b>test</b>"

Это дает нам символы <, > и /.

Вы так же возможно слышали о функции escape. Она конвертирует строку в формат URI который простые браузеры смогут переварить. Эта функция важная часть нашего квеста, так что нам нужно получить к ней доступ. Мы можем ее произнести, но сможем ли мы ее выполнить? Это не типичная функция как все предыдущие, а функция глобального уровня.
Какая у нее конструирующая функция?

Ответ function Function() { [native code] }, сам объект Function и есть конструктор.
[]["fill"]["constructor"] === Function

Используя это, мы можем передать строку кода для создания функции.

Function("alert('test')");  

Процедуры:

Function anonymous() {  
    alert('test')
}

Уже этот код мы способны вызвать просто используя () в конце.
Так что мы можем вызвать функцию escape следующим образом:

[]["fill"]["constructor"]("return escape(' ')")() === "%20"

Если мы передаем нашу < описанную ранее в функцию escape, мы получим %3C. Это заглавная C очень важна чтобы получить остальные символы которых нам не хватает.

[]["fill"]["constructor"]("return escape('<')")()[2] === "C"

Используя ее мы можем написать написать теперь функцию fromCharCode, которая возвращает символы Unicode из заданного десятичного представления. Это часть объектов String, которую мы можем вызвать конструктор как было описано ранее.

""["constructor"]["fromCharCode"](65) === "A"
""["constructor"]["fromCharCode"](46) === "."

Мы можем проверить любые десятичные представления символов Юникод здесь: Unicode lookup [7].

Фух. Вроде все!

У нас теперь есть возможность вызвать почти любой символ на свете, составить из них код и даже выполнить, это значит что мы получаем полноту по тюрингу в Javascript используя всего шесть символов: [,],(,),+ и !.

Хотите доказательство? Запустите этот код в своем браузере:

Раскрыть код

[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]]+(+(!+[]+!+[]+!+[]+[!+[]+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(+![]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(+![]+[![]]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]](!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]])+(!![]+[])[+[]]+(![]+[])[+[]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()

Если вы читаете это с мобильного, код выше это alert(«wtf») который выполняется.

Есть даже тулза под названием JSFuck [8]к оторое автоматизирует преобразование, а вот [9]как она транслирует каждый символ.

Какое практическое применение?

Никакое. Но вот eBay недавно сделал нехорошие вещи [10] что позволило продавцам внедрить код JS в свои страницы используя именно эти символы, хотя это не очень распространенный вектор атак. Некоторые люди упоминают обфускацию, но есть более лучшие методы обфускации.

Прошу извинить.

Надеюсь вам понравилось путешествие!

Спасибо VladimirKochetkov [11] и Ксеня Кириллова за помощь с переводом.

Автор: rami0

Источник [12]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/263348

Ссылки в тексте:

[1] интересные подходы: https://habrahabr.ru/company/pt/blog/224547/

[2] kukumumu: https://habrahabr.ru/users/kukumumu/

[3] «A Javascript journey with only six characters»: http://www.jazcash.com/a-javascript-journey-with-only-six-characters/

[4] нотаций dot notation или square bracket notation: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Property_accessors

[5] secret argument: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString

[6] HTML wrapper methods: https://developer.mozilla.org/en-US/docs/tag/HTML%20wrapper%20methods

[7] Unicode lookup: http://unicodelookup.com/

[8] JSFuck : http://www.jsfuck.com/

[9] вот : https://raw.githubusercontent.com/aemkei/jsfuck/master/jsfuck.js

[10] нехорошие вещи: http://arstechnica.co.uk/security/2016/02/ebay-has-no-plans-to-fix-severe-bug-that-allows-malware-distribution/

[11] VladimirKochetkov: https://habrahabr.ru/users/vladimirkochetkov/

[12] Источник: https://habrahabr.ru/post/337212/