One of the things I do at DreamHost is help with hacked sites. This means when WP is hacked, I look at it, figure out how, and explain to the person how to fix it, or how to tell their tech folks what needs doing. There are occasions where I’ll delete things for them, but usually that happens when there’s a folder or file with weird permissions.
We have a lot of tricks with what we look for, like
base64, but recently I started to find files that missed my scan, but not my “Hey, wait, wp-mai1.php isn’t a WordPress file…” check. Files like this:
$a51a0e6bb0e53a=str_rot13('tmhapbzcerff');$a51a0e6bb0e5e4=str_rot13(strrev('rqbp rq_46rfno')); eval($a51a0e6bb0e53a($a51a0e6bb0e5e4('eF6dWFtv6kYQ/it9qMQ5UlWBCVGtKg+JWozQaSrcU9+qKvIlBIGh6BBCyK/[...]'))); eval($a51a0e6bb0e53a($a51a0e6bb0e5e4('eF7tW1uvotqW/ivnYSe1d85JignSvcxJPXgDtQCXKNdO50TAJSqop7xw6fR/7zHm1CUqqGW91EMnK1FgzHG/[...]')));
Now obviously I can just add
str_rot13 to my checklist (nothing in WordPress core uses it), but .. how do I look for those eval strings?
grep -R --exclude-dir="\.svn" --exclude="*.js" "eval" .
That gets me a lot of files, though, and I don’t want to parse what I don’t need to. By the way, there’s one and only one file in all of WP that uses eval() in a ‘nefarious’ way, and that’s
./wp-admin/js/revisions-js.php, which is the WordPress easter egg. That’s also the only place you’ll see
p,a,c,k,e,r code. But clearly I want to look for
eval( or even
eval($ because that’s more exact, and that should give me a better result.
This is a two edged sword, of course. If I’m too precise, I will miss some of their shenanigans. If I’m not close enough to what I’m looking for, I get too much. And worst of all, I don’t always know what I’m looking for. Quite a lot of finding new hacks is a world where “I’ll know it when I see it.” So let’s take it down and say I want to find no JS, nothing in .svn, and anything with eval and a paren:
grep -R --exclude-dir="\.svn" --exclude="*.js" -e 'eval(' .
That’s a lot better, and in fact, this is a good start! But it’s hard to read because of how long the lines are:
Okay, lets get smarter!
grep -R --exclude-dir="\.svn" --exclude="*.js" -e 'eval(' .|cut -c -80
Now I’m telling it to cut up after 80 characters, because it’s easier to pick out the bad with just that much. Look:
Part of the reason this works is I know what I’m looking for. WordPress, in general, doesn’t encrypt content. Passwords and security stuff, yes, but when it does that, it uses variables so you would get
eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');, which remains totally human readable. By that I mean I can see clear words that are easy to search for in a doc, or via grep or awk without being forced to copy/paste. I can remember “PCLZIP underscore CB…”
Those random characters are not human readable at all. That’s how I know they’re bad. Of course, if someone got clever-er, they would start naming those variables things that ‘make sense’ in the world of WP, and I have a constant fear that by pointing out how I can tell this is a hack, I give them ideas on how to do evil-er things to us.
It’s for reasons like this that I, when faced with a hack or asked to clean one up, always perform Scorched Earth Security. I delete everything and reinstall it. I look for PHP and JS files in wp-content/uploads, or .htaccess files anywhere they shouldn’t be (in clean WP, you have two at most: at the root of your site and in akismet). I make sure I download my themes and plugins from known clean locations. I’m careful. And I always change my passwords. Heck, I don’t even know what mine are right now!
But none of this is static enough for me to say “This is the fix forever and ever” or “this is how you will always find the evil…” By the time we’ve codified and discussed best methods, the hackers have moved on. The logic of what to look for now may not last long, but the basic concept of looking for wrong and how to search for it should remain a good starting point for a while yet.
Do you have special tricks you use to find the evil? Like what Topher did to clean up a hack?