DD-WRT Fuzzing and Monitoring

We recently got a request for a vendor who has taken upon itself to add some interesting stuff to the DD-WRT router to provide him with some form of monitoring that would integrate with our beSTORM fuzzer.

Regular monitoring inherently built into beSTORM which include ARP, ICMP Echo, UDP/TCP Ping and remote debugging weren’t quite up to it – ARP, ICMP Echo and UDP/TCP ping could not tell the vendor when the router was expecting heavy load due to our test which was one of the criteria he has defined inside beSTORM as being an exception (a vulnerability).

Our typical backup option is a gdb-style remote debugger, but the DD-WRT’s debugger doesn’t easily provide that information, therefore we have built a simple monitoring agent that can connect to the DD-WRT web interface and query the load value of the router. When a certain value (above a certain number) is reached an exception is reported back to beSTORM.

This little neat trick allowed the vendor to identify several strange packets that can cause his modified router to become unresponsive (take more than a few seconds to respond), as well as detect when the router was responsive but the load on it was unusually high.

The script is now bundled with the full version of beSTORM, feel free to get the latest version and look into it. A trial is always available here. It’s also available below:

#!/usr/bin/perl
# Copyright Beyond Security 2011
# beSTORM support: support@beyondsecurity.com

use strict;
use Getopt::Long;
use LWP::UserAgent;
use IO::Socket;

my @children;
my $beSTORM_port = “6969″;
my $beSTORM_ip = “192.168.1.2″;
my $router_ip = “192.168.1.1″;
my $router_username = “root”;
my $router_password = “admin”;

my $pingTimeout = 1; #ping every x seconds
my $bContinue = 1; #Stay in loop.

#Install signal handlers
$SIG{ABRT} = \&signaled;
$SIG{INT} = \&signaled;
$SIG{HUP} = \&signaled;

my $options = { };
GetOptions(
‘host=s’ => \$options->{‘bH’},
‘port=i’ => \$options->{‘bP’},
“router=s” => \$options->{‘rH’},
“username=s” => \$options->{‘rU’},
“password=s” => \$options->{‘rP’},
);

#Sanity check
my $bPrintUsage = 0;
if (! $options->{‘bH’} ) {
$bPrintUsage = 1;
print “No host value has been provided\n”;
}
if (! $options->{‘rH’} ) {
$bPrintUsage = 1;
print “No router value has been provided\n”;
}

if ($bPrintUsage) {
usage();
exit 0;
}

$beSTORM_ip = $options->{‘bH’};
$beSTORM_port = $options->{‘bP’};
if (not defined $beSTORM_port) {
$beSTORM_port = 6969;
}

$router_ip = $options->{‘rH’};
$router_username = $options->{‘rU’};
if (not defined $router_username) {
$router_username = “root”;
}

$router_password = $options->{‘rP’};
if (not defined $router_password) {
$router_password = “admin”;
}

while ($bContinue) {
my $ua = LWP::UserAgent->new;
$ua->timeout(2);

my $URL = “http://$router_username:$router_password\@$router_ip” . “/Status_Router.live.asp”;
print “Connecting to: $URL\n”;
my $response = $ua->get($URL);

my $content = “”;
if ($response->is_success) {
$content = $response->decoded_content; # or whatever
}
else {
send_notification($beSTORM_ip, $beSTORM_port, “Failed to receive response from router’s web server: “.$response->status_line);
}

my $load = “”;
if($content =~ /, load average: ([^}]+)\}/gs) {
$load = $1;
} else {
print “Failed to find load average inside content: [$content]\n”;
send_notification($beSTORM_ip, $beSTORM_port, “Failed to locate load average value”);
}

print “$load\n”;
sleep(1);
}

###
#
sub send_notification {
my $Host = shift;
my $Port = shift;
my $Exception = shift;
print STDERR “\n\nSending to $Host:$Port this exception: [$Exception]\n\n\n”;

my $sock = IO::Socket::INET->new(
Proto => ‘udp’,
PeerPort => $Port,
PeerAddr => $Host,
) or die “Could not create socket: $!\n”;

print STDERR “Exception: [$Exception]\n”;
$sock->send($Exception) or die “Send error: $!\n”;

$bContinue = 0;
}

sub usage
{
print “\nUsage: $0 –host [--port ] –router \n\n”;
print “\t–host beSTORM client host\n”;
print “\t–port beSTORM client UDP port for exception information (default 6969)\n”;
print “\t–router the Router being monitored\n”;
print “\t–username used by the router to authenticate (root)\n”;
print “\t–password used by the router to authenticate (admin)\n”;
}

#Ping beSTORM host that we are alive every $timeout
sub start_notifier
{
my $timeout = shift;
if (! defined $beSTORM_ip) {return; };

my $pid= fork();
if ($pid < 0)
{
die "Could not fork\n";
}
if ($pid > 0)
{
push @children, $pid;
}
#Child
if ($pid == 0)
{
print “Starting beSTORM notifier. Will send heartbeat to $beSTORM_ip every $timeout second(s)\n”;
while ($bContinue)
{
my $sock = IO::Socket::INET->new(Proto => ‘udp’,
PeerAddr => $beSTORM_ip,
PeerPort => ’6970′,
Type => SOCK_DGRAM,
) or die “socket: $@”;
print $sock “NOOP”;
close $sock;
sleep($timeout);
}
print “beSTORM notifier Stopped\n”;
exit 0;
}
}

sub stop_notifier
{
my $sig = shift;
print “Shutting down beSTORM notifier (it may take up to 5 seconds to stop)\n”;
if (@children)
{
print “Signaling: (@children) with sig $sig\n”;
kill $sig, @children;
}
}

sub signaled
{
my $sig = shift;
print “Recieved signal $sig. Shutting down\n”;
stop_notifier($sig);
$bContinue = 0;
}

#The end

Share