📜 ⬆️ ⬇️

Javascript six-character journey


Javascript is a strange and beautiful language that allows you to write crazy, but still valid code. He tries to help us by converting one thing to another depending on how we work with them.


If you add a string to something, it will allow us to get the text, so it will convert everything into a string.


If we add the plus or minus prefix, it will assume that we need a numeric representation and convert the string to a number if it can.


If we deny something, it will convert it to a boolean value.


We can use these features of the language and create a bit of magic with just six characters: [ , ] , ( , ) ! and + . If you are reading this on the desktop, you can open the console in your browser (developer tools, for example) and run the code. Just copy any code from the examples below to the console, and it should be executed and return true.


Let's start with the simple. Here are the main rules:


  1. Prefix ! converts to Boolean
  2. Prefix + Converts to Number
  3. Adding [] converts String

Here they are in action:


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

Another important point to remember is using square brackets to get a specific character (letter) from a string like this:


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

Also remember that you can take a few numbers and add them in a string representation, and then convert it back to a number.


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

Well, let's try to combine these tricks and get the letter a .


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

Cool


With this fairly simple combination, you can get all the letters from the words true and false . a , e , f , l , r , s , t , u . Okay, is it possible to get letters elsewhere?


Well, there are undefined , which can be obtained with the help of strange nonsense like [][[]] . Convert it to a string using one of our main rules and get additional letters d , i and n .


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

Using letters that we still have, you can write the words fill , filter and find . Of course, there are other words, but these three words are interesting to us, because these are array methods (Array) . That is, they are part of an Array object and can be called directly from an array instance. For example, [2,1].sort() .


An important feature of Javascript: object properties are accessible through a dot (dot notation) or square brackets (square bracket notation) . Since array methods are properties of the Array object itself, you can call these methods using square brackets instead of a period.


That is, [2,1]["sort"]() is the same as [2,1].sort() .


Let's see what happens if we use one of the array methods using the available letters, but we will not call it:


 []["fill"] 

This gives function fill() { [native code] } . You can convert this method header to a string with a rule we know about:


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

Here, we now have additional characters: c , o , v , ( , ) , { , [ , ] , } , .


With the letters c and o we can now write a constructor . constructor is a method available in all Javascript objects; it simply returns a constructor function.


Let's get a string representation of the constructor function for all of the objects available to us now:


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

From here we get new letters for the arsenal: B , N , S , A , m , g , y .


Now you can collect the word "toString" . This is a function that can be called with square brackets. Yes, this time we will actually call her:


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

But we, after all, were able to convert anything into a string using one of the basic rules. What is the use?


Well, what if I say that the Number type's toString method has a secret argument called radix , which changes the base of the number system of the returned number before converting it to a string. See:


 (12)["toString"](10) === "12" //  10 (12)["toString"](2) === "1100" //  2,   (12)["toString"](8) === "14" //  8,   (12)["toString"](16) === "c" //   12 

But why stop at 16? The maximum is 36, which includes all the digits 0 - 9 and the letters a - z . Now you can get any character:


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

Cool! But what about other characters like punctuation and capital letters? We dive even deeper into the rabbit hole!


Depending on where you run Javascript, you may or may not have access to some pre-defined objects and data. If you are working in a browser, then HTML wrapping methods are most likely available to you.


For example, bold is a string method that adds tags for boldness:


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

From here you can get < , > and / .


You've probably heard about the escape function. Roughly speaking, it converts a string into a URI format so that simple browsers can interpret it. If we give it a space, we get %20 . If you pass it < , you get %3C . This capital C very important if you need to get all the remaining missing characters.


With this letter you can write fromCharCode . This function returns a Unicode character based on the specified decimal number. It is part of a String object, which can be obtained by calling a constructor, as we have done before.


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

You can use the Unicode lookup and easily find the code for any Unicode character.


So, now we can write anything as a string, and we can run any function on the types Array, String, Number, Boolean and Object through their constructors. Decent power for just six characters. But that is not all.


What is the constructor of any function?


The answer is function Function() { [native code] } , that is, the Function object itself.


 []["fill"]["constructor"] === Function 

Using this, you can pass a line of code and create a real function.


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

We get:


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

And you can immediately call it by adding () to the end. Yes, now we can run the real code!


Whew! Everything!


Now we have access to all the characters, you can write any code with them and run it. So Javascript Turing is full with only six characters [ , ] , ( , ) , + and ! .


Want evidence? Run this code in the console.


There is a tool that automates the conversion, and this is how it translates each character.


What is the use?


Not with anything. eBay has done some bad things quite recently, which allowed sellers to insert the executable JS into their pages using these symbols, but this is not the typical attack vector. Some people raise the topic of obfuscation, but to be honest, there are better methods for this.


Excuse me.


But I hope you enjoyed this trip.


Sources:



')

Source: https://habr.com/ru/post/312172/


All Articles