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

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

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


    image

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


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

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

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

    Если вы читаете это не с мобильного устройства, можете открыть 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 и могут быть вызваны напрямую в массивах, например, [2,1].sort().

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

    Так получается что [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 есть секретный аргумент секретный аргумент под названием 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.

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

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

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

    Она конвертирует строку в 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.

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

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

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

    Раскрыть код
    [][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]]+(+(!+[]+!+[]+!+[]+[!+[]+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(+![]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(+![]+[![]]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]](!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]])+(!![]+[])[+[]]+(![]+[])[+[]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()

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

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

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


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

    Извините.

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

    Спасибо VladimirKochetkov и Ксеня Кириллова за помощь с переводом.
    Positive Technologies 303,12
    Компания
    Поделиться публикацией
    Комментарии 20
    • 0

      Ну что я могу сказать? JavaScript очень… Эээ… Гибкий, во! Гибкий и удивительный. И беспощадный.

      • +5

        Не нашел ответа на вопрос из заголовка. Так почему анализ защищенности-то не того?

        • 0
          (Абзацы: второй и за последним заголовком.) Когда-то ebay решил, что если резать буквы и цифры, то это достаточно безопасно. Кто-то додумался сделать атаку на JS вообще без использования этих символов, и она работала. Ну, и как вы такое автоматизируете? Тут всё сводится к тому, что исследовательские и творческие задачи практически не автоматизируются потому, что как только кто-то придумал что-то новое, ваш старый подход не работает.
          • +1

            Ну вы извините, но "Когда-то ebay решил, что" говорит только об уровне интеллекта тамошних программистов — не более того. Делать из этого глубокие выводы — это как-то непредусмотрительно.


            Насколько я понял, тут предлагается что-то типа кодирования Черча для js кода под названием jsfuck. Это конечно интересно — но в целом далеко не ново.


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

            Ну в общем, заголовок все равно кажется слегка желтоватым.

            • 0

              Так соль в том, что как только будет принято решение «а давайте автоматизируем анализ защищённости», то это решение именно такого уровня. Потому что стоит кому-то придумать новую атаку, как система станет беззащитной. Хуже того, некому будет защищать. Всё ж автоматизировано, людей нет.

          • +1
            Ответ тут читается между строчек :) «Более интересные подходы к анализу», о которых упомянул автор в начале, будут анализировать более-менее серьёзный проект на JS до второго пришествия. Почему так — недавно подробно расписывал на RSDN (https://rsdn.org/forum/philosophy/6761512.flat#6761512, см. стартовое сообщение и комменты).
            • 0
              Простите, никак не привыкну к местному парсеру :( Вот ссылка на обсуждение, в виде ссылки ^_^
            • 0
              Возможно и желтоватый заголовок, но он не лишен правды. В начале я привел ссылку на статью Владимира Кочеткова о методах автоматизации анализа, станет понятно, что с анализом Java Script методом абстрактной интерпретации машина без бутылки не справится.

              Если вы приведете пример успешной автоматизации поиска уязвимостей в Java Script причем желательно такой, чтобы еще выдавал на выходе готовый экслойт, буду благодарен!
              • 0

                Ну, на самом деле я бы просто попробовал сформулировать немного иначе — чтобы не было излишнего обобщения (про "все методы" — что скорее всего неверно), и возможно в тексте уточнить (а не только в виде ссылки куда-то), почему именно (потому что производительность анализа слишком плохая, например).


                К сожалению, предложить конкретный вариант заголовка не могу — не приходит в голову.

            • 0
              Автоматизация без головы, на текущем уровне развития ИТ — это как на Тесле врубить автопилот и сесть на заднее сидение. Не нужно удивляться результату, короче.

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

              • +2
                Забыл дописать — JSFuck филигранная вещь :) отнес бы её к ИТ-арту
                • 0
                  Мы в Positive Technologies стремимся к тому, чтобы анализ кода проводился пока вы сидите на заднем сидении.
                  • 0
                    Мы в Микро Фокусе стремимся, чтобы анализ кода проводился пока вы отдыхаете на яхте ;)

                    По существу же, моя практика и статьи Вашей компании, коллега, показывают, что выхлоп статического анализатора это, суть, подозрения, которые нужно еще подтвердить. Можно, конечно, еще пентест добавить для объективного контроля, но мозг выключить и сесть ни в Теслу сзади, ни на яхту, на совсем не получится.
                • +2

                  К слову, мы на Tproger эту статью перевели уже год назад, когда она только вышла: https://tproger.ru/translations/js-magic-with-6-symbols/

                  • +2
                    Если верить датам, то еще месяцем раньше ее перевели на хабре:
                    https://habrahabr.ru/post/312172/
                    • 0
                      Тем более
                      А такие ситуации на Хабре как-то регулируются? (я просто новенький :))
                      Или «всё новое — хорошо забытое старое?
                      • 0
                        Ох какая жесть. Я честно искал по фамилии автора перед публикацей.
                        Ну теперь даже не знаю что делать :)
                  • +1

                    мне одному бросается в глаза "Java Script" написанный не слитно?

                    • 0
                      поправлю спасибо
                    • +2

                      Почему вы не оформили статью как перевод?

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                      Самое читаемое