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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Другая важная вещь, которую нужно знать о JS, — это то, что свойства объекта могут быть доступны с помощью точечной или скобочной нотации. Так как упомянутые выше методы массива являются свойствами самого массива, мы можем вызывать эти методы, используя квадратные скобки вместо точечной нотации.

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

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

Получается function fill() < [native code] >. Мы можем превратить этот метод в строку, используя наше золотое правило:

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

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

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

Так мы добавим в наш арсенал следующие символы: B , N , S , A , m , g , y .

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

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

Что если я скажу вам, что у метода toString типа Number есть секретный аргумент секретный аргумент под названием radix , который может изменить основание системы счисления заданного числа перед переводом в строку? Взгляните:

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

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

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

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

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

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

Что представляет собой конструктор функции?

Ответ — function Function() < [native code] >, сам объект Function и есть конструктор.

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

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

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

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

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

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

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

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

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

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

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

📎📎📎📎📎📎📎📎📎📎