JSFuck is a bad security barrier.

TL;DR JSFuck can be reversed with fair ease by pattern matching (or simply string matching). Check out the code section for the actual code.

You can jump to the solution section if you don't want the background details.

Why in my sane mind would I do this?

I was recently analysing some of JS obfuscation strategy used by the websites. The popular ones were minification, uglification, loading JS from encoded strings, etc. Mostly they were deployed to hide the APIs from being exploited outside of the sites. But upon careful inspection, almost all of the JS obfuscation gave away their APIs and the extracted knowledge could be used to write wrappers for those in any language of choice (although, using JS had the advantage to use their codes directly). Then I hit upon another strategy which made this task seemingly impossible. JSFuck.

All the APIs required some form of keys to be sent with each request which was verified on the server side. These keys were generated by some form of hashing or seeded random number generation. But this site loaded its API keys using JSFuck and they were unique for the each request.

The problem

So, in a nutshell, I had to get past some changing JSFuck code which injected some global variables and get the values of those variables.

JSFuck

Then I started to analyse how JSFuck gets evaluated and tried to reverse it. JSFuck works in an interesting way. It only uses six of the JS characters, ()+[]!, to generate all the codes.

The overall strategy is to use the Function method of JS to create a function from a string and then evaluate it. Which reduces the generation strategy to get hold of the Function method with the limited characters and generate the string with those characters.

The details of code generation can be checked from JSFuck's GitHub source and it would be redundant to go into the details. On a high-level summary, it can be said as recursive replacement of individual parts.


The solution

Now the question before me is how do I break it. I guess to fully reverse engineer the code would be very involved. But my target was to reverse a specific version with only specific part varying every time. So, I embarked upon the strategy of pattern matching.

The results of the initial inspection are:
  1. All codes began with a specific pattern which fetched Function.
  2. All of them ended with () which called the generated function.
  3. The code between them had segments enclosed within () of [], sometimes continuous, separated by +. They turned out to generate characters of the string being concatenated with +.
Then to further analyse the internals, I wrote some code to separate the blocks of above-mentioned types. Then tokenize them based on prefix matching of string from a mapping of the string to corresponding objects. Initially, the mapping contained only the pattern for Function and a few manually reversed characters.

To find the rest of the characters, I made the tokenizer print the unknown blocks separated by + in a JS compatible array which I then converted to the corresponding characters using JS's eval. This strategy didn't work for all the characters, especially the ones using CHAR_CODE to get the characters but it did convert a lot of other characters. After this, my tokenizer stopped spitting lots of unknown blocks and returned a lot of sane characters. (Actually, the code I was initially working with got fully deobfuscated until I hit another one with uppercase characters).

Other strategies

Before trying to solve this myself, I looked online for existing solutions. All the materials I found recommended to remove the last () and eval the code in JS. But my target was to reverse it from any language. Also removing () and using eval doesn't help if the code tried to inject some malicious code which can be easily placed any were in the middle.

Code

Who cares all the shit details? I want the damn code!

Here you go:

My code disclaimer:

  1. This code doesn't parse all the possible characters. I have added only those characters which I encountered while I was working. The missing characters can easily be added by adding the corresponding string to the jsfuck-map.lisp file.
  2. The code is in Common Lisp. I am not an experienced lisp programmer so some of the code may not be according to accepted standards. I left the commented out code intact to show the actual development process.

Result

JSFuck can be deobfuscated and the actual code can be obtained with fair ease. So, you should not be using JSFuck as a security layer.

As for that matter, I am still wondering how should one protect their API in the websites from being used outside of intended flow. Most of the strategies I have seen went down with some work.

Comments

  1. I have some JSfuck code that is missing/has extra characters. How can I use your code to decode what ever is decodable and later find typos myself?

    ReplyDelete

Post a Comment

Popular posts from this blog

Beginner's Guide to install Kali Linux in UEFI system (Lenovo Z510)

Hospital Management System (my second full fledged program)