SReject
SReject

Reputation: 3936

Get full alphabet without using letters

After seeing the following code, I started wondering if there was a way to access the full lowercase alphabet without using any letters(conditions to be applied below):

[($=(!0)+'')[0]+$[1]+$[2]+((!1)+'')[3]+$[0],(([]+[])[1]+'')[1]+([]+{})[1],([]+{})[1]+(([]+[])[1]+'')[1]+$[3]].join(' ');
// "trust no one"

Using the various statements below the following letters can be accessed a b c d e f g i j l m n o p r s t u v x y:

// "true" yeilds: e r t u
!0+'';

// "false" yeilds: a f l s
!1+'';

// "[object Object]" yeilds: b c j o t
[]+{}+'';

// "undefined" yeilds: d i n
[][1]+'';

// "Infinity" yeilds: y
1/0+'';

// Using the above statements "constructor" can be spelled
// It has no value by itself but can be coupled with other statements to get more letters
($=[]+{}+'')[5]+$[1]+(([]+[])[1]+'')[1]+((!1)+'')[3]+($=!0+'')[0]+$[1]+$[2]+($=[]+{}+'')[5]+$[6]+$[1]+((!0)+'')[1];

// "function RegExp() { [native code] }" yeilds: g p v x
(/./)[/*constructor" from above*/]+'';

// "function Number() { [native code] }" yeilds: m
(0)[/*"constructor" from above*/]+'';

What are ways to access to remaining characters h q w z with the following limits applied:

  1. Only non-letter characters can be used in the code(symbols, numbers and punctuation)
  2. All characters used within the code must fall into ASCII's first 128 characters
  3. Code must not rely on environment variables such as global for node, window for browsers, etc
  4. Reencoding letters such as using escaped variants, octlet syntax, etc should be refrained from until all other avenues have been explored.

Upvotes: 0

Views: 1488

Answers (3)

Athelstone
Athelstone

Reputation: 69

Here's my solution to produce all English letters both in lowercase and uppercase. This solution is not using unescape function but do utilize dynamic function generator to implicitly un-escape hex literal string.

((_,$,$$) =>
/* _ = 'abcdefghijklmnopqrstuvwxyz'
   $ = code => Function( arg, code )
   declare $$ (will be defined later)
*/
_[ // invoke _.toUpperCase() ...
  // construct "toUpperCase"...
  _[19]+_[14]+ // "to"
  ($$=( // $$ = hexCode => { return `\x${hexCode}` }
    __ => $( // __ as hexCode, invoke the $ function...
      [ _[17]+_[4]+_[19]+_[20]+_[17]+_[13], // "return"
        ' `\\',_[23],__,'`'] // ` \x${hexCode}`
      [ _[9]+_[14]+_[8]+_[13] ]('') // .join('')
    )()
  ))(55)  // 'U'
  +_[15]+_[15]+_[4]+_[17]  // "pper"
  +$$(43)  // '\x43' --> 'C'
  +_[0]+_[18]+_[4] // "ase"
]() // --> "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+_  // concatenate with the _
)(...( // call with spread operator...
  ( (_,$,$$) => [
    _[1]+_[28]+_[31]+_[11]+_[4]+_[0]  // "abcdef"
    + ( _ += // append following string to _
        ''[
            $=[ // "constructor", saved as $
              _[31]+_[27]+_[10]+_[3]+_[5]
              +_[6]+_[7]+_[31]+_[5]+_[27]+_[6]
            ]
        ] // --> "function String() { [native code] }"
        + ''+/./[$]
          // --> "function RegExp() { [native code] }"
      )[55]  // 'g'
    + (17)[
        $$=_[5]+_[27]+_[50]+_[5]+_[6]+_[21]+_[10]+_[55]
        // $$ = "toString"
      ](36)  // (17).toString(36) --> 'h'
    +_[21]+_[29]  // "ij"
    +(20)[$$](36)  // (20).toString(36) --> 'k'
    +_[2] // 'l'
    +(0[$]+'')[11] // (Number.toString())[11] --> 'm'
    +_[10]+_[27]+_[90] // "nop"
    +(26)[$$](36) // (26).toString(36) --> 'q'
    +_[6]+_[3]+_[5]+_[9]+_[66] // "rstuv"
    +(32)[$$](36) // (32).toString(36) --> 'w'
    +_[89]+_[25] // "xy"
    +(35)[$$](36) // (35).toString(36) --> 'z'
    // code=>Function(arg,code)
    , _ => (()=>{})[$]('_',_) 
  ])(
    // "falsetrueundefinedInfinity[object Object]"
    ''+![]+!![]+[][0]+(1/0)+{}
  )
));

Returned string: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".

Explanation:

  1. Generate initial string...
    ''+![]+!![]+[][0]+(1/0)+{}

which will produce

"falsetrueundefinedInfinity[object Object]"

Let's name this string as {s1} for this explanation.

  1. Pass string s1 to closure function f1 as first argument (the _ variable)

  2. Grab "abcdef" from s1 (now stored in _ variable)...

    _[1] + _[28] + _[31] + _[11] + _[4] + _[0]
  1. Compose "constructor" from s1 ...
    _[31]+_[27]+_[10]+_[3]+_[5]
    +_[6]+_[7]+_[31]+_[5]+_[27]+_[6]

and saved it into $ variable ($ is declared as undefined argument in f1 function)

  1. Get the String function by taking constructor of any string instance (in this case we can just use an empty string)...
<string_instance>.constructor
= ''.constructor = ''['constructor']
= ''[$] // $ = "constructor" in previous step
= the String function

Convert it to string by appending it to an empty string to get "function String() { [native code] }"

  1. Do the same to a RegExp instance...
/./[$]   //--> the RegExp function

Convert it into a string --> "function RegExp() { [native code] }"

  1. Do the same to a Number instance...
0[$]   // --> the Number function

Convert it into a string --> "function Number() { [native code] }"

  1. Append strings from step 5, 6 and 7 to the _ variable. Let's name this new string as s2. Content of s2 now is...
   "falsetrueundefinedInfinity[object Object]function String() { [native code] }function RegExp() { [native code] }function Number() { [native code] }"
  1. From s2, grab the character 'g' at index #55

  2. Compose "toString" from s2 ...

_[5]+_[27]+_[50]+_[5]+_[6]+_[21]+_[10]+_[55]

and store it into the $$ variable (it is also declared as undefined argument in f1 function)

  1. Now we can call toString() function from any number to get any lower case letter by supplying 36 as its radix argument, thus calling (17).toString(36) will yield the 'h' letter. In our code, this accomplished by: (17)[$$](36)

  2. Next take letter 'i' and 'j' from s2

  3. Get letter 'k' using the same toString(36) method as in step 11, this time with number 20.

  4. Grab "lmnop" from s2

  5. Use (26).toString(36) to get letter 'q'

  6. Grab "rstuv" from s2

  7. Use (32).toString(36) to get letter 'w'

  8. Grab "xy" from s2

  9. Use (35).toString(36) to get letter 'z'.

  10. Now we have all lowercase letters. Put it into f1's result array as its first element.

  11. To get the uppercase letters is a little tricky. We'll use function generator (the Function function) to generate a function which returns character decoded from given argument. As first step, obtain the Function function by referencing constructor of a function instance...

<function_istance>.constructor
= ( ()=>{} )[ 'constructor' ]
= (()=>{})[$]
= Function

and wrap it into a closure to generate our desired function...

code => Function( argument_name, code )

Because we can't use letters, just reuse the '_' name for its argument...

_ => Function( '_', _ )

Please don't be confused between the _ (argument of the closure) with the '_' (argument of the new function generated as the result of calling the closure). For the sake of clarity, let's name this closure function as f2. We'll put the f2 as second element in f1's result array.

  1. Now f1 is finished, we'll pass the result (array from the previous two steps) using spread operator as _ and $ argument into function f3. So in f3, our s2 string is in _ variable, and f2 is in $ variable.

  2. Create new function f4, which is to return a character from given argument. We'll need f4 to produce two uppercase letters: 'U' (char code 0x55) and 'C' (char code 0x43). This will be accomplished by simple return statement followed by a hex-literal string "return \x??" where ?? is the argument to be passed on. Because we have all required letters to compose the code (all of them is lowercase letters), we just need to assemble them. Put f4 as variable $$ (it is already defined as undefined argument in f3).

  3. Call f4 with 55 as argument (will be automatically casted into '55', prefixed with hard-coded '\x' become '\x55' --> letter 'U'.

  4. Prepend with "pper" grabbed from s2

  5. Call f4 again with 43 as argument, this will produce letter 'C'.

  6. Prepend with "ase", thus we have "toUpperCase"

  7. Invoke _.toUpperCase() to get upper case version of s2

  8. Prepend string from step 28 with s2

  9. Return from f3 with result string from step 29: all letters both in lowercase and uppercase forms.

Upvotes: 1

Dre
Dre

Reputation: 4329

Aha got it. If unescape is allowed, not encoded for clarity:

[]['constructor']['constructor']['call']('','return unescape' + '("%68%71%77%7' + 'a' +'")')()

This gives us hqwx, and can of course give us anything else.

the only bit that cannot be reached is '("%68%71%77%7<a goes here>")', but that satisfies the symbols and numbers rule. The a can be constructed otherwise.

If we want to avoid unescape, we can use (828035)['toString'](36) -- The "magic" number 828035 was generated by using parseInt('hqwz',36).

And encoded -- with large parts broken out for readability:

// From your post
str_constructor = ($=[]+{}+'')[5]+$[1]+(([]+[])[1]+'')[1]+
    ((!1)+'')[3]+($=!0+'')[0]+$[1]+$[2]+($=[]+{}+'')[5]+
    $[6]+$[1]+((!0)+'')[1];

// call
str_call = ([]+{}+'')[5]+($=!1+'')[1]+$[2]+$[2];

// return unescape ( bonus, not using a literal space character )
ret_unescape = ($=!0+'')[1]+$[3]+$[0]+$[2]+$[1]+($=''[1]+'')[1]+
    ([]+{}+'')[7]+$[0]+$[1]+$[3]+($=!1+'')[3]+([]+{}+'')[5]+$[1]+
     ((/./)[str_constructor]+'')[14]+(!0+'')[3];


// finally
[][str_constructor][str_constructor][str_call]('',ret_unescape + '("%68%71%77%7' + (!1+'')[1] +'")')() // "hqwz"

// or -- toString
str_toString = (!0+'')[0]+([]+{}+'')[1]+($=(('')[str_constructor]+''))[9]+$[10]+$[11]+$[12]+$[13]+$[14]

(828035)[str_toString](36)  // hqwz

Bonus-bonus:

We can even ditch numbers if we are sneaky.

true: !![]
false: ![]

0: ![]+![]
1: !![]+![]
2: !![]+!![]
10: (!![]+![]+'')+(![]+![])

My big nasty magic constant could therefore be:

((!![]+!![])*(!![]+!![])*(!![]+!![])+'')+((!![]+!![])+'')+
    ((!![]+!![])*(!![]+!![])*(!![]+!![])+'')+
    (![]+![]+'')+(!![]+!![]+!![]+'')+((!![]+!![])*(!![]+!![])+!![])-![]

Upvotes: 1

Aidan Brumsickle
Aidan Brumsickle

Reputation: 657

([]+{}+'')[5]+([]+{}+'')[1]+(([]+[])[1]+'')[1]+(!1+'')[3]+(!0+'')[0]
+(!0+'')[1]+(!0+'')[2]+([]+{}+'')[5]+(!0+'')[0]+([]+{}+'')[1]+(!0+'')[1]

gives you 'constructor', which you can then use with a string literal like this:

('')[([]+{}+'')[5]+([]+{}+'')[1]+(([]+[])[1]+'')[1]+(!1+'')[3]+(!0+'')[0]
+(!0+'')[1]+(!0+'')[2]+([]+{}+'')[5]+(!0+'')[0]+([]+{}+'')[1]+(!0+'')[1]]+''

which gives you 'function String() { [native code] }' which gives you 'v' and 'g'

Edit: You found 'constructor' too, it's tricky to get much more without a way to access the global variable.

Here's a way to get the global variable in Node:

('')['constructor']['constructor']('','return global')()

Using the approaches above:

('')[
    // 'constructor'
    ({}+'')[5] + ({}+'')[1] + (([]+[])[1]+'')[1] + (!1+'')[3] +
    (!0+'')[0] + (!0+'')[1] + (!0+'')[2] + ({}+'')[5] +
    (!0+'')[0] + ({}+'')[1] + (!0+'')[1]
][
    // 'constructor'
    ([]+{}+'')[5] + ([]+{}+'')[1] + (([]+[])[1]+'')[1] + (!1+'')[3] +
    (!0+'')[0] + (!0+'')[1] + (!0+'')[2] + ([]+{}+'')[5] +
    (!0+'')[0] + ([]+{}+'')[1] + (!0+'')[1]
](
    '',
    // 'return'
    (!0+'')[1] + (!0+'')[3] + (!0+'')[0] + (!0+'')[2] + (!0+'')[1] + (([]+[])[1]+'')[1] +
    ' ' +
    // 'g'
    (('')[
        ([]+{}+'')[5] + ([]+{}+'')[1] + (([]+[])[1]+'')[1] +
        (!1+'')[3] + (!0+'')[0] + (!0+'')[1] + (!0+'')[2] +
        ([]+{}+'')[5] + (!0+'')[0] + ([]+{}+'')[1] + (!0+'')[1]
    ] + '')[14] +
    // 'lobal'
    (!1+'')[2] + ({}+'')[1] + ({}+'')[2] + (!1+'')[1] + (!1+'')[2]
)()

From there you could access global.env and from there it's almost cheating.

Edit: You can also build this:

[]['constructor']['constructor'](
    'o',
    "var a=[];for(var x in o){a.append(x)};return a")

Which gives you a poor man's Object.keys(), which you can use to access the names of various objects' methods.

You can also build an eval function & assign it to $:

$=[]['constructor']['constructor']('s','return eval(s)')

Upvotes: 1

Related Questions