A Restaurant Serves Harmless Maleware Code

Recently I stumbled over some malware code embedded in a WordPress site. The obfuscated code caught my attention, so I dug into it. This article sheds some light into the darkness of browser behaviour, JavaScript mess and layered obfuscation.

The malicious JavaScript code, which I reverse engineered, lied on a local restaurant’s WordPress site. It had a simple structure of a variable, two standard JS functions and a Base64 encoded string of 23.5 kB size. Code snippet of the obfuscated code on the main page Looks pretty suspicious, doesn’t it?\n\natob(), a standard JS function, decodes the Base64 string which is being stored in the variable BIUYQSVJLR. eval(), also a standard JS function, executes(!) the content in BIUYQSVJLR – more about that later.

The same code was embedded on the main site as well as on all sub pages.

Decoding fun

So I thought to myself, let’s look what’s behind that code. A quick decoding of the string returned this:

$ base64 -d 01-encoded-base64.txt
var XFKLJMHSFD = String.fromCharCode (19-9,127-9,101-4,120-6,38-6,112-5,106-5,127-6,33-1,63-2,38-6,44-5,81-5,116-7,110-4,126-9,124-8,91-1,73-8,104-6,122-5,116-7,45-6,67-8,18-8,127-9,102-5, ..., 66-7,11-1,11-1);

Again, we have a similar structure but with a different kind of code obfuscation. String.fromCharCode() also a standard JS function takes unicode values and converts them into characters. We get another string in XFKLJMHSFD which will be executed by eval().

To decode the 3314 character big char array, I wrote a simple program in my preferred language. A snippet of the important part:

char foo[] = {19-9,127-9,101-4,120-6,38-6,112-5,106-5,127-6,33-1,63-2,38-6,44-5,81-5,116-7,110-4,126-9,124-8,91-1,73-8,104-6,122-5,116-7,45-6,67-8,18-8,127-9,102-5, ..., 66-7,11-1,11-1};
fprintf(stdout, "%s\n", foo);

The output of this was pretty interesting! Code snippet of some more obfuscated code

Another Base64 encoded string and a XOR decryption function. Now, that looks interesting, challenge accepted!

Decryption fun

Till now, we had simple decoding fun. But now things get a bit more challenging.

We have a key var key = 'LmjutZAbum';, the suspicious code in var enced and a function called xor_enc() that takes two arguments. We also have a variable dec which takes the decrypted string from xor_enc(). dec will be called by (new Function(dec))();.

To decrypt the code I needed to:

  1. Base64 decode enced
  2. Iterate over every element inside that string and XOR it with the remainder of my current position in the key divided by ten (length of the key)
  3. Attach every decrypted character to new string/output\n\nI wrote a small decoder to help me sort this out more quickly. A snippet of the work horse part: ``` char key[] = \“LmjutZAbum\“; int key_size = sizeof(key)/sizeof(key[0]);

for (int i = 0; i < string_size; i++) { int c = (string[i] ^ (key[(i % (key_size -1))])); fprintf(stdout, \“%c\“, c); }

`string` contains the whole Base64 decoded content of `enced` and `string_size` the length of it.

So I fed the decoded string into the program and got finally the suspicious JS code.
## Analysing the code
First, the JS code checks every 10 ms if the current site is fully loaded:
![Code analysis](/images/2017/02/03-code-analysis.png)\nIf this is the case, it starts the `start()` function. At the beginning are some escape checks for situations in which the code shall not be executed:

  * When a key `yYjra4PCc8kmBHess1ib` with a value `1` already has stored in the local key-value store `localStorage`
  * When a cookie `referrerRedirectCookie` has already been set
  * When a cookie `wordpress_logged` or `wp-settings` or `wordpress_test` is set
  * When no user agent string is present or a user agent has `google`, `bot` or `crawl` in it
  * When the current browsing history is not present respectively smaller than two sites.

If all this is not the case, the actual malware code will be executed:

\nvar wlocation = ‘/?pagerd’ + Math.random().toString(36).substring(7);\nwindow.location = w_location; ```

window.location is a WebAPI that holds, among other things, the current URI as a Location object. The documentation says:

Though Window.location is a read-only Location object, you can also assign a DOMString to it.

So one can simply assign a new location by passing a new URI string to it. The remarkable thing is, that as soon as one assigns a new value to window.location the browser loads this new URI instantly!

The malware code seems to be broken or somehow incomplete, because '/?pagerd_' + Math.random().toString(36).substring(7) is not a valid new location but just a non-sense path. There are other unused variables as well.\n\nThat’s it. Nothing more happens here.


I searched a little bit in the web and found several posts, describing this kind of code in different versions but with a similar structure.\nSome of the examples are not broken like the one I analysed and would redirect all requests to a suspicious site somewhere in the web.

eval() and window.location foo

From the documentation of eval():

The argument of the eval() function is a string. If the string represents an expression, eval() evaluates the expression. If the argument represents one or more JavaScript statements, eval() evaluates the statements.\n\nI’m not a web developer and my JS knowledge is limited, but from a security point of view, the eval() function looks fishy.\nI would not wonder if eval(ubuntu-16.04.1-desktop-amd64.iso) booted in my browser… ;-)\n\nThe WebAPI window.location is crying to be exploited. Any embedded JS code is able to assign new URI values and once done, the browser loads a new site without protesting.


Nested inside several layers of obfuscation lies a broken or incomplete redirection code. From what I see, this code was intended to redirect all requests away from the restaurants WP site to another site somewhere in the web.

The heavy usage of functions like atob() and eval() combined with the window.location object are signs for suspicious code.

Although this malware seems to be harmless, it is a clear evidence that the site has been compromised some time ago.

Also, it’s only a matter of time till the first AV scanners will block user access to this restaurant’s site because of such suspicious code.\n\nTo conclude this, I had a good time researching the code and structure and learned a lot more about browser behaviour and JS/WebAPI foo.

And yes, of course, I informed the folks from the restaurant about their compromised site. ;-)