Javascript-путешествие с шестью символами

Javascript-путешествие с шестью символами

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

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

Если мы добавляем префикс "плюс" или "минус", то он допустит, что нам нужно числовое представление и сконвертирует строку в число, если сможет.

Если мы отрицаем что-то, то он сконвертирует это в булево значение.

Мы можем использовать эти особенности языка и создать немного магии со всего-лишь шестью символами: [ , ] , ( , ) , ! и + . Если вы читаете это на десктопе, то можете открыть консоль в вашем браузере (developer tools, например) и запускать код. Просто копируйте любой код из примеров ниже в консоль, и он должен исполнится и вернуть true.

Давайте начнем с простого. Вот главные правила:

  1. Префикс ! конвертирует в Boolean
  2. Префикс + конвертирует в Number
  3. Добавление [] конвертирует String

Вот они в действии:

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

Также помните, что можно брать несколько цифр и складывать их в строковом представлении, а потом конвертировать это обратно в число.

Хорошо, давайте попробуем скомбинировать эти трюки и получить букву a .

Этой довольно простой комбинацией можно получить все буквы из слов true и false . a , e , f , l , r , s , t , u . Окей, можно ли получить буквы еще откуда-нибудь?

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

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

Важная особенность Javascript: свойства объекта доступны через точку (dot notation) или квадратные скобки (square bracket notation). Так как методы массива — это свойства самого объекта Array, можно вызвать эти методы с помощью квадратных скобок вместо точки.

То есть [2,1]["sort"]() - это то же самое, что [2,1].sort() .

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

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

Вот, теперь у нас есть дополнительные символы: c , o , v , ( , ) , < , [ , ] , >, .

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

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

Отсюда мы получаем новые буквы для арсенала: B , N , S , A , m , g , y .

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

Но мы ведь и так могли конвертировать все что угодно в строку с помощью одного из основных правил. В чем польза?

Ну, а что если я скажу, что метод toString у типа Number обладает секретным аргументом под названием radix , который меняет основание системы счисления возвращаемого числа перед конвертацией в строку. Смотрите:

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

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

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

Например, bold - это метод строки, который добавляет теги для полужирности:

Отсюда можно достать < , > и / .

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

С помощью этой буквы можно написать fromCharCode . Эта функция возвращает символ Юникода на основе заданного десятеричного числа. Она – часть объекта String, который можно получить вызовом конструктора, как мы уже делали раньше.

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

Так, теперь мы можем написать что угодно в виде строки, и можем запустить любую функцию у типов Array, String, Number, Boolean и Object через их конструкторы. Приличная мощь для всего лишь шести символов. Но это еще не все.

Что такое конструктор любой функции?

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

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

И ее можно сразу же вызывать добавив () в конец. Да, теперь мы можем запускать настоящий код!

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

Хотите доказательств? Запустите этот код в консоли.

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

В чем польза?

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

📎📎📎📎📎📎📎📎📎📎