Wednesday, July 8, 2009

Perl Tutorial on Setting up a server monitoring bot.

There are two bot's both are based off the example on the example from the cpan page for POE::Component::IRC. The first is made to show your servers to load, external, and internal IP addresses(Using the Commands: load, ipadd, and exadd). The second one is more mischevious and runs any command you wish on the server by saying in the private channel the word system and then the command as in:system cat /etc/passwd . The second one can also run the slow loris DOS attack which affects versions of apache below 2.2.8 and some versions of squid proxy server. This DOS attack can take down small servers with only one machine running them, the second bot will not be revealed in this post but the next post. They both sign in to a password protected channel, however be aware that password is stored within the perl file which by it's nature makes it insecure. There are plans to add a diffrent authentication method in the future.

sudo cpan
at cpan shell:
install POE::Component::IRC

NOTE: This install from cpan did not work in my out of the box Fedora installation(and I did not have time to troubleshoot because I am trying to get this out so I can work on music until I get my new album out.), However it worked fine on both my Cent0S install and my Mac install.

It may ask you if you want to install dependencies and you do(it may ask more than once). It may also ask you to run tests, choose yes. This may take a while.

If you do not have cpan, install, install via yum or apt-get.
ie yum install cpan or apt-get install cpan

If you have not run cpan before you will need to set it up. That is beyond the scope of this post, however you tend to be ok with defaults.

After that while still in the cpan shell:
install LWP::Simple

It's a library in perl for pulling down webpages, the bot will use it to find your external ip.

Now copy or download the script to file. I did:
vi filename.pl
Then I hit the letter i
then I pasted the file

***Note, you will need to change $channel, $password, and $server, to your server channel and password. Otherwise you will end up on my server ^.^**

For linux(CentOS, cmds may vary) use:


use strict;
use warnings;
use POE qw(Component::IRC);
use LWP::Simple;

my $nickname = 'PoeIrcBot' . $$;
my $ircname = 'PoeIrcServerBot';
my $server = 'irc.malvager.com';
my $channel = "#channel";
my $password = "password";

my @channels = ('');

# We create a new PoCo-IRC object
my $irc = POE::Component::IRC->spawn(
nick => $nickname,
ircname => $ircname,
server => $server,
) or die "Oh noooo! $!";

POE::Session->create(
package_states => [
main => [ qw(_default _start irc_001 irc_public) ],
],
heap => { irc => $irc },
);

$poe_kernel->run();

sub _start {
my $heap = $_[HEAP];

# retrieve our component's object from the heap where we stashed it
my $irc = $heap->{irc};

$irc->yield( register => 'all' );
$irc->yield( connect => { } );
return;
}

sub irc_001 {
my $sender = $_[SENDER];

# Since this is an irc_* event, we can get the component's object by
# accessing the heap of the sender. Then we register and connect to the
# specified server.
my $irc = $sender->get_heap();

print "Connected to ", $irc->server_name(), "\n";

# we join our channels
$irc->yield( join => $_ ) for @channels;
$irc->yield( join => "$channel $password");
return;
}

sub irc_public {
my ($sender, $who, $where, $what) = @_[SENDER, ARG0 .. ARG2];
my $nick = ( split /!/, $who )[0];
my $channel = $where->[0];

if ( my ($loadWord) = $what =~ /^load/ ) {
my $uptime = `uptime`;
my $cpuUsagetwo = qr/(load average: \d+\.\d+, \d+\.\d+, \d+\.\d+)/;
if ($uptime =~ $cpuUsagetwo){
$irc->yield( privmsg => $channel => "$nick: $&" );
}
}
if ( my ($ipWord) = $what =~ /^ipadd/ ) {
my @ifconfig = `ifconfig`;
my $inetter = qr/(inet addr:\d+\.\d+\.\d+.\d+)/;
foreach (@ifconfig) {
my $line = $_;
if ($line =~ $inetter){
$irc->yield( privmsg => $channel => "$nick: $&" );
}
}
}

if ( my ($ipWordtwp) = $what =~ /^exadd/ ) {
my $whyip = qr/(Your IP address is \d+\.\d+\.\d+.\d+)/;
my $content = get("http://whatismyipaddress.com");
if($content =~ $whyip){
$irc->yield( privmsg => $channel => "$nick: $&" );
}
}

return;
}

# We registered for all events, this will produce some debug info.
sub _default {
my ($event, $args) = @_[ARG0 .. $#_];
my @output = ( "$event: " );

for my $arg (@$args) {
if ( ref $arg eq 'ARRAY' ) {
push( @output, '[' . join(', ', @$arg ) . ']' );
}
else {
push ( @output, "'$arg'" );
}
}
print join ' ', @output, "\n";
return 0;
}



For Mac use:


use strict;
use warnings;
use POE qw(Component::IRC);
use LWP::Simple;
#for mac
my $nickname = 'PoeIrcBot' . $$;
my $ircname = 'Flibble the Sailor Bot';
my $server = 'irc.malvager.com';
my $channel = "#channel";
my $password ="password";

my @channels = ('');

# We create a new PoCo-IRC object
my $irc = POE::Component::IRC->spawn(
nick => $nickname,
ircname => $ircname,
server => $server,
) or die "Oh noooo! $!";

POE::Session->create(
package_states => [
main => [ qw(_default _start irc_001 irc_public) ],
],
heap => { irc => $irc },
);

$poe_kernel->run();

sub _start {
my $heap = $_[HEAP];

# retrieve our component's object from the heap where we stashed it
my $irc = $heap->{irc};

$irc->yield( register => 'all' );
$irc->yield( connect => { } );
return;
}

sub irc_001 {
my $sender = $_[SENDER];

# Since this is an irc_* event, we can get the component's object by
# accessing the heap of the sender. Then we register and connect to the
# specified server.
my $irc = $sender->get_heap();

print "Connected to ", $irc->server_name(), "\n";

# we join our channels
$irc->yield( join => $_ ) for @channels;
$irc->yield( join => "$channel $password");
return;
}

sub irc_public {
my ($sender, $who, $where, $what) = @_[SENDER, ARG0 .. ARG2];
my $nick = ( split /!/, $who )[0];
my $channel = $where->[0];

if ( my ($loadWord) = $what =~ /^load/ ) {
my $uptime = `uptime`;
my $cpuUsagetwo = qr/(load averages: \d+\.\d+ \d+\.\d+ \d+\.\d+)/;
if ($uptime =~ $cpuUsagetwo){
$irc->yield( privmsg => $channel => "$nick: $&" );
}
}
if ( my ($ipWord) = $what =~ /^ipadd/ ) {
my @ifconfig = `ifconfig`;
my $inetter = qr/(inet \d+\.\d+\.\d+.\d+)/;
foreach (@ifconfig) {
my $line = $_;
if ($line =~ $inetter){
$irc->yield( privmsg => $channel => "$nick: $&" );
}
}
}

if ( my ($ipWordtwp) = $what =~ /^exadd/ ) {
my $whyip = qr/(Your IP address is \d+\.\d+\.\d+.\d+)/;
my $content = get("http://whatismyipaddress.com");
if($content =~ $whyip){
$irc->yield( privmsg => $channel => "$nick: $&" );
}
}

return;
}

# We registered for all events, this will produce some debug info.
sub _default {
my ($event, $args) = @_[ARG0 .. $#_];
my @output = ( "$event: " );

for my $arg (@$args) {
if ( ref $arg eq 'ARRAY' ) {
push( @output, '[' . join(', ', @$arg ) . ']' );
}
else {
push ( @output, "'$arg'" );
}
}
print join ' ', @output, "\n";
return 0;
}



Then to run it just type:perl filename.pl , and that should have you set.
*If you do no use perl filename.pl you will need to put a shebang at the top of the file(i.e #!/usr/bin/perl) with your particular path to perl.

If you liked this you will probably like:
Half finished windows IRC bot trojan/zombie
Getting External IP in Perl

No comments: