Tuesday, August 22, 2017

Reverse Analyzing PHP Malware

Hacking is a problem. Those who wish to damage things for personal benefit (or for fun) are really just bad people. Alas, hacking is a part of our world today and it is never going to go away. So we have to get smarter than the hackers, which means we have to understand how their code works and what it does. I'm sure they're doing this every day with Russian hackers. Personally, I think it's impressive what they're capable of.

But when you hack my mother's website, you've gone too far.
I've cleaned up a lot of crap from my mother's knitting website (Wordpress sucks, even with secure passwords, because one vulnerable plugin and RIP site) over the years. Sometimes things leak back in, and I have to deal with it. Really it's just a matter of finding the include statement and deleting it and the file it references. I can tell when it happens because it breaks the website.

So I found one this morning, and I'd like to reverse engineer it. So I downloaded the file and the include line to my computer to start reversing it. Sometimes when I did this, Windows Defender would remove the file because it actually recognized the file as a virus which I thought was interesting.

The include line looks like this (images to prevent copy paste):


Yikes, let's get those escape characters out.

There's really nothing special about this except for the fact that it's hidden in a comment. Really sneaky, if you ask me. Let's move on to the file it references.

This is more like it.

So this clearly consists of a base64 encoded string that will get evaluated once decoded. Most are like this. We don't need to decode this ourselves, however. We can make the code dump itself by replacing the eval line at the end with:

It came out well formated like this. I figured it'd be minified but whatever. Not all hackers are smart. It's kinda tricky to get a feel for what this code actually does, so we can actually run this and capture the output into an HTML file and see what it says. This is pretty risky. I don't advise doing this at all. Really. Don't. I've given the code a quick once over and it looks fine to me, but looks can be deceiving. Just because I got away with it doesn't mean you will too.

Running this code creates a folder called "options" and running it from a web browser creates a folder called "stats". This is looking more and more like a view counter, but we need to get the page to produce something in order to verify that.

It looks like we need to have a cookie or post field set where the value of the cookie is encrypted by its key.


So I took the encryption functions from the decrypted source file and I wrote my own cookie generator. It serializes a PHP array with the following fields:
  • ak - Authentication, must be equal to the cs_auth global set in the file
  • a - Function. Can be one of i, e, plugin
If the function is "i", then the program will print information about the environment it's running in. This the authentication token (for some reason), the PHP version, and the version of the code. If the function is "e", the program will execute and code in the "d" variable. If the function is "plugin", you can set "add" or "rem" for adding and removing the plugin named in "p", respectively. I'm not sure what that means in this context, so we can play around with it and see if we can make it dump more info.

Adding a plug in also takes a "d" parameter. That's when it clicked. This is a trojan horse and nothing more.

These "plugins" are actually just snippets of PHP code submitted and saved to disk. They're all run every time the code is run, even if there are no cookies provided. Let's try an example.

If we submit the code echo "The time is ".date("F j, Y, g:i a"); as a plugin, we should see that string every time we load the page, even without the cookie that allows this to happen.

So I wrote the following array to the cookie to see if it would take it:
array(5) {
  ["ak"]=>
  string(36) "6d9d99d0-1b54-41b5-8810-46b1c9f28720"
  ["a"]=>
  string(6) "plugin"
  ["sa"]=>
  string(3) "add"
  ["p"]=>
  string(8) "timehack"
  ["d"]=>
  string(42) "echo 'The time is '.date('F j, Y, g:i a')"
}

This request created a file in the stats directory that was encrypted. I'm assuming this is my code. But when I load the page with nothing special, I don't see anything. Why not? It looks like it's not decrypting my code correctly and just trying to eval the encrypted version. "syntax error, unexpected '��g��֭xX؂' (T_STRING) in /mnt/c/Users/Tucker/Downloads/blogpost/phpmal/defines.php(163) : eval()'d code(283) : eval()'d code on line " would make it seem that way.

I'm not really super into fixing this issue, but I did want to find what this code did. It's nothing more than a stupid trojan horse. That's it. It's a little disappointing that this one isn't a more complicated one, but I'll do another one of these if my mother's website gets cracked again before we move her off of WordPress. Seriously, a quarter of the world's internet runs on this software and it has these big security holes in its plugins. That's scary.

No comments:

Post a Comment