For regular readers of this blog, there is one constant that pops up over and over: Malware gets more complex. When malware researchers, like myself, unlock new obfuscated code, it’s a signal to the black hats that they need to up their game. For me, figuring out their new hack attempts and then putting the findings online to help others is all in a day’s work, not to mention a big part of the fun. So, let’s get to the fun.
A colleague of mine, Ben Martin, sent me a piece of malicious code that had gone undetected for analysis. It’s important for us to understand how a piece of code goes undetected so that we can update our signatures and catch it the next time. After giving it a quick look, everything seemed to be clear. It certainly didn’t look like anything exceptional. Like I said before, the bad guys are always a step ahead, creating more and more sophisticated malware every day (even every hour), and we’re doing our best to make their “work” as hard as possible.
This particular sample would ordinarily be properly detected and cleaned like the others. That would be the end of it, except I felt like something was a little off.
Every malware researcher has some kind of sixth sense that alerts them when there’s something wrong in seemingly benign code. In this case, something just felt off and this led to me spend several hours with what turned out to be a very interesting analysis
What Was I Looking At?
We’ve written extensively about malicious plugins on this blog and most people are aware that they can be dangerous for websites. The only problem is that hackers know this as well and can attempt to take advantage of it as with the “simple” malware we’ll analyze in this post. In this case, the malicious snippet was hidden in the folder of a legitimate and working plugin. Making it even more difficult to detect, it looked very similar to the legitimate file and without a very close look would pass for real. Here’s what the file head looked like:
Then in the following code, I noticed something suspicious:
Why would a legitimate plugin file use hex chars obfuscation? This whole function just didn’t look quite right (and of course it isn’t ☺). With that in mind, let’s take a look at what those encoded strings are and what the function does:
original: $unique_id = "x62x61sx65x36x34x5fx64x65cx6fx64x65" decoded : $unique_id = "base64_decode" original: $unique_hash = "x63x72ex61x74x65x5fx66x75x6ecx74x69x6fx6e" decoded : $unique_hash = "create_function"
At this point, if it hadn’t already, this plugin grabbed my attention. You can see that it is a class constructor (this malware is OOP based) and the author is getting and running something from the database (DB) and it’s doing so in a very tricky way. In fact, this whole file is nothing but one BIG LIE (297 lines of it to be exact). All the functions are serving a single purpose; to perform actions on the DB content and run it.
At this point, I started to wonder what this code was doing with the database, but prior to checking the main code buried deep in the WordPress DB, I also wanted to know how this malware was activating. The files in the plugin folders are not loaded automatically and there was no include function anywhere in any other files, which is what I would have expected. So, I figured that it had to be in the DB – and you know what, it was. Here was my first search:
Do you see that better_blogroll.php? That’s how the author was loading and running the malware. There is no sign of it in the wp-admin dashboard and, in fact, there is no sign of it anywhere but in this single DB record modified to load the file. Now that we know how it’s executed, let’s see what code is being loaded.
Back to the Constructor Code
Remember that constructor code? Here are the lines where the DB record name and class are crafted:
$this->option_name = 'class_' . $this->id_base; $wp_blogroll_widget = new WP_Blogroll_Widget_Support('generic_support','auto');
So the final record name should be class_generic_support. Now, we just need to find something like this in the DB. I quickly searched for it and what do you know…
Wait a second, this is HUGE! I expected some short malicious code changing the blogpost titles to pharma spam, but what’s this? It’s clearly reverted base64 encoded content so I did a quick reversal of the string to format the mess and look at how deflating that is. Now I’ve got another 1,110 lines of malicious code to sift through.
If we take a look at the functions list used, it becomes clear that these are all title manipulation functions, but, interestingly, this malware also has other functionality highlighted by the door_main() function:
What we have here is yet another huge base64 encoded code block. Run it through a quick decoder and, wow, it turns out that it’s a complex backdoor with shell uploading functionality and the ability to steal system information. For an idea of what it can do, look at these code snippets:
Believe it or not, there’s still more, but this gives a clear picture of this “tiny, little” malware injection. There are a couple interesting aspects underlying this malware.
- The clever way it’s running itself by storing the main part of the payload in the DB
- The main spam distribution functionality also has a complex backdoor implemented
But is That Everything?
By this point, I was already surprised by this tricky piece of malware, but given how deep this rabbit hole was, I decided to go through the original code hidden in the DB again just to be sure that I wasn’t missing anything. Unsurprisingly, the code itself is really complex, but I noticed that the $door array variable was placed in several areas and it looked like some sort of configuration was stored in this variable:
$door = unserialize(base64_decode(strrev(get_option('wp_check_hash'))));
From this, I found that this was being stored in yet another place in the WordPress DB structure. The author is working with the standard WordPress get_option() function so now we need to have a look at where else this function is used:
And. Just. Wow.
While the wp_next_check and _feed_count_ were just integer values created and used by the malware, the wp_check_hash and rss_ records were much more interesting. The wp_check_hash included the malware configuration, of which this was the most interesting part:
The redir_URL probably serves as some sort of tracking script storing the info about the infected sites, but unfortunately I was not able to get anything else from this branch.
But what about that update host? That looks familiar, right? As it turns out, it’s just a similar address to a well-known url-shortening service (we’ve redacted the name). I tried to open it and it’s just an empty page. In any case, they have to be updating the code from this address somehow so I went back to the code analysis and took another look at this code snippet:
I crafted the link and, luckily, I was successful again. In this case, I was able to download the malware’s infector code, which is responsible for the initial infection. It has implemented lots of functionality responsible for checking the environment and based on that, the malicious file itself is downloaded. If you’re into this sort of thing, it is really interesting.
That’s a Lot of Code, But What Does it Do?
Finally, I was able to cull a couple of other pieces of information from file, among other things the author’s e-mail address, which he/she uses to send alerts to the address with warnings when something is wrong:
Unfortunately, I was not able to download any other remote content. At least not yet. Here is the summary sent to the author’s e-mail address. Notice the rather amazing attention to detail.
That right there is a pretty nice summary. With this, the attacker knows everything about your website, and in combination with the backdoor he/she placed, she also knows about your server.
Beyond that, the malware stores a huge list of IP addresses (collection of bot IPs) and an even bigger collection of SPAM data from which the SPAM content on the infected sites is crafted. From this, I was able to find a collection of other infected sites within the spam data. Both collections were, again, buried deep in the WP DB structure:
There you have it; the primary function of all of this code is to insert spam content into legitimate site posts. This malware sample isn’t just a sophisticated structure in and of itself, but is also a very complex method of injecting the spam into the content. It stores the spam content in the database and, at this point has more than 50,000 entries! I’d like to thank my colleague, Ante Kresic, for helping me out with analysis of this next part. Here are his findings.
What is Happening With Spam?
The SPAM data content has an array form with several subarrays. Let’s have a look at them:
Here, the script breaks up the post content by sentences. It inserts spam a minimum of one time up to a maximum of seven times, depending on multiple variables. It also alternates between adding concantenated spam or adding it to a new line. All in all, it’s creating paragraphs out of the content and creating wholly new content for the post.
So That’s it?
It might seem like a lot of work for a malware hacker to go through just to place some spam on a website, but we need to remember that their goal is to place this spam on thousands of websites and make it difficult for website owners to get rid of. In that way, the malware creator can reap rewards from their work for the longest interval possible. So, while that’s it for this spam incident, there is a greater lesson to learn here by looking at how much work the malware author put us through just to get to the root of the problem. And this is just spam. If they’ll go this far to make a few bucks on spam placement (actually, it could be quite a few bucks), then imagine the lengths they’d go to in order to steal your client’s credit card information or to place Trojans on your site that could eventually give them access to your visitors’ machines. The possibilities are endless.
From our point of view, what’s really important is that you, as a site owner, pay attention to your website. If you begin to see the tell-tale signs of malware, then reach out to us. Alternatively, proactively protect yourself from this problem. When you don’t do that, you put your site and your site’s visitors at risk.
6 comments
Nicely done. Thank you for the summary.
Yes, the malware authors are getting more and more deft at inserting code that looks just about correct. They use names with which we are most familiar and that seem just about right.
Ben’s find seems to be more sophisticated version of one I found over a year ago. It was very similar in that it was a hack embedded in the initialization events, in this case of the theme. It loaded from the options table and executed source code that was commented to look like “Hello Dolly” (never mind the fact that Hello Dolly does not belong stored in an option). That code was then the gateway to retrieving the payload from another site.
So the site had been cleaned up several times by the person working on the site before me. However, since that single line and the options record were never removed from the theme/database, the site would immediately get re-infected. All the cleanup did was cause the malware to download an updated payload.
Thanks for the great analysis …nice job
Good breakdown of how it works – they’re certainly getting more creative.
After independently finding this on a client’s WP install, the in-the-open decoy class was WP_Series_Widget_Support, so it is randomly generated. Something to watch out for. I arrived at the same conclusion as you did through a slightly different route, though I also figured it would be much simpler at first than it turned out to be.
0 google results for “class WP_Series_Widget_Support” was a big tell, as well.
Comments are closed.