#!/usr/bin/perl -Tw # Copyright (c) 2002, Jon Hart # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # * Neither the name of the organization nor the names of its contributors may # be used to endorse or promote products derived from this software without # specific prior written permission. # # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ################################# # 9/21/01 # # Send packets with various settings from # any apparent source/port to any source/port. # # Requires: Net::RawIP (www.cpan.org) # root # !egress filtering # # Todo: # watch the traffic that comes back # # Bugs, or things you may bitch about: # # Some of the randomness is funky. For example, the TTL and window # are set to semi-random values when _each_ packet is sent. In normal # operation, the TTL/window will generally remain constant. Mine doesn't. # Then again, I only ever send a single packet from a unique source/dest # port, so its ok that the various TCP stuffs change. # # The formatting is rediculous. # # Some of the options can contradict themselves. I.e., setting a protocol # other than TCP but still setting the TCP flags. The packet will get sent # as usual, but the receiving end may be confused (however, simply analyzing # said packet as tcp will work). # # Using "--rrdest" will completely hose your system. The route cache # will fill up, plop will die, and you'll get messages in your logs. # Yay. # # (jhart@ccs.neu.edu) work/school # and/or # (warchild@spoofed.org) home/play # # Disclaimers: # I take no moral, legal, ethical, or financial responsibility for this tool. # Understand what it does and act responsibly. ################################# require 5.6.0; use strict; use diagnostics; use locale; use Socket; use Net::RawIP; use Getopt::Long; use Time::localtime; $ENV{'PATH'} = "/usr/bin:/bin"; delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # some variables that I need to keep global my $saddr; # source address my $daddr; # destination address my @sports; # source port(s) my @dports; # destination port(s) my $delay; # delay between each packet (seconds) my $flags; # flags to set my $num; my $packet = new Net::RawIP; # the packet object; # get our options in place GetOptions( "src=s" => \(my $opt_saddr), "dest=s" => \(my $opt_daddr), "rdest" => \(my $opt_rdest), "rrdest" => \(my $opt_rrdest), "rsrc" => \(my $opt_rsrc), "rrsrc" => \(my $opt_rrsrc), "src_net=s" => \(my $opt_src_net), "dest_net=s" => \(my $opt_dest_net), "srcp=s" => \(my $opt_srcp), "destp=s" => \(my $opt_destp), "delay=i" => \(my $opt_delay), "rflags" => \(my $opt_rflags), "flags=s" => \(my $opt_flags), "data=s" => \(my $opt_data), "fdata=s" => \(my $opt_fdata), "mult" => \(my $opt_mult), "death" => \(my $opt_death), "ttl=i" => \(my $opt_ttl), "id=i", => \(my $opt_id), "version=i" => \(my $opt_version), "window=i" => \(my $opt_window), "ack=i" => \(my $opt_ack), "urg=i" => \(my $opt_urg), "proto=i" => \(my $opt_proto), "tos=i" => \(my $opt_tos), "help" => \(my $opt_help), "num=i", => \(my $opt_num), "test" => \(my $opt_test), "debug" => \(my $opt_debug)) or die "$!\n"; if (defined($opt_help)) { print << "EOF" ; Send tcp packets to a desired host using random tcp headers. Optionally spoof the source address, and wreak havok. REQUIRED: # one of --dest --rdest --rrdest OPTIONS: --dest --rdest (pick a random destination for session) --rrdest (pick a random destination for each packet) --dest_net (pick a dest IP from here) --src (default: random) --rsrc (pick a random source IP) --rrsrc (pick a random source IP for each packet) --src_net (pick a src IP from here) --srcp (default: 1024-65535 randomized) --destp (default: 1-1024 randomized) --delay (default: 2) --flags <1|2|a|f|p|s|u> (default: s) --rflags (pick random tcp flags) --data (default: none) --fdata (default: none) --test (don't actually send the packet(s) -- use w/ debug --debug (Print constructed packet) --help (This message) FOR THE DARING: --num (default: duh. 1) --death (ignore all the rules) --mult (keep sending until your src ports are exhausted) --version (default: 4) --window (default: carefully random) --tos (default: 0) --ttl (default: 200-255) --id (default: rand 16-bit) --proto (default: 6 (tcp)) Examples: ./plop --dest 2.10.116.200 --destp 22 --delay 0 --data "foo" ./plop --rrdest --dest_net 12.10.1-254.2-50 --flags as --data \ "uid=0(root)" --destp 22,23,25,80 ./plop --dest 1.10.116.1 --destp 7 --delay 0 --data "echo" \ --proto 17 --srcp 1-65535 --mult --src_net 1.2.3.4-250 --rrsrc EOF exit; } # setup the options needed before a packet is sent. if (!(defined($opt_daddr) || defined($opt_rdest) || defined($opt_rrdest))) { print "Try ./scan --help for options\n"; exit; } else { if (!defined($opt_delay)) { $delay = 2; } else { $delay = $opt_delay; } if (!defined($opt_num)) { $num = 1; } else { $num = $opt_num; } # see if they gave us flags if ($opt_flags) { my %seen; $opt_flags =~ tr/12AFPRSUafprsu//dsc; my @uniq_flags = grep { ! $seen{$_} ++ } split(//,$opt_flags); foreach (@uniq_flags) { $flags .= $_; } } # make all the ports before starting (speed++) if ($opt_srcp) { # use their ports @sports = &make_ports($opt_srcp); } else { @sports = &make_ports("1024-65535"); } # see above if (defined($opt_destp)) { @dports = &make_ports($opt_destp); } else { @dports = &make_ports("0-1024"); } &gen_dest; &gen_src; &gen; } ############################# # acquire the source address ############################# sub gen_src { # 1.) Use the default source address # 2.) Use the provided source address # 3.) Pick a random source address # no source address provided, and no source randomness desired if (!defined($opt_saddr) && !(defined($opt_rsrc) || defined($opt_rrsrc))) { $saddr = ${ifaddrlist()}{rdev($daddr)}; } # source address provided, no source randomness desired elsif (defined($opt_saddr) && !(defined($opt_rsrc) || defined($opt_rrsrc))) { if ($opt_saddr =~ /^([\d.\w-]+)$/) { my $packedip = gethostbyname($1) or die "Can't resolve $1: $!\n"; $saddr = inet_ntoa($packedip); } else { die "Couldn't determine source host format, wtf!\n"; } } # no source address provided. pick a random source instead. elsif (!defined($opt_saddr) && (defined($opt_rsrc) || defined($opt_rrsrc))) { srand(); $saddr = &rand_src; } else { die "Couldn't determine source address!\n"; } } ############################# # acquire the destination address ############################# sub gen_dest { # 1.) Use the provided destination address # 2.) Pick a random destination address if(defined($opt_daddr) && !(defined($opt_rdest) || defined($opt_rrdest))) { if ($opt_daddr =~ /^([\d.\w-]+)$/) { my $packedip = gethostbyname($1) or die "Can't resolve $1: $!\n"; $daddr = inet_ntoa($packedip); } else { die "Couldn't determine dest host format, wtf!\n"; } } if(!defined($opt_daddr) && (defined($opt_rdest) || defined($opt_rrdest))) { srand(); $daddr = &rand_dest; } } ############################# # control how/when each packet is sent ############################# sub gen { my @large_ports; my @small_ports; if ($#sports > $#dports && defined($opt_mult)) { # *sigh*, they want to exhaust their source ports # what this means is that you can do something like # --srcp 1-1000 --destp 22 and send 1000 packets to port # 22. Fun, but whatever. for(my $i = 0; $i <= $#sports; $i++) { &send($saddr, pop(@sports), $daddr, $dports[$#sports % ($#dports+1)]); sleep($delay); $i--; # if they wanted a really random source/dest, check that now and # pick another address if (defined($opt_rrsrc)) { $saddr = &rand_src; } if (defined($opt_rrdest)) { $daddr = &rand_dest; } } } else { for(my $i = 0; $i <= $#dports; $i++) { &send($saddr, $sports[$#dports % ($#sports+1)], $daddr, pop(@dports)); sleep($delay); $i--; # if they wanted a really random source/dest, check that now and # pick another address if (defined($opt_rrsrc)) { $saddr = &rand_src; } if (defined($opt_rrdest)) { $daddr = &rand_dest; } } } } ################################# # generate each packet based on user input and defaults. send. ################################# sub send { my %ip_hdr; my %tcp_hdr; $ip_hdr{saddr} = shift; $tcp_hdr{source} = shift; $ip_hdr{daddr} = shift; $tcp_hdr{dest} = shift; if (defined($opt_version)) { $ip_hdr{version} = $opt_version; } else { $ip_hdr{version} = 4; } if (defined($opt_tos)) { $ip_hdr{tos} = $opt_tos; } else { $ip_hdr{tos} = 0; } if (defined($opt_id)) { $ip_hdr{id} = $opt_id; } else { $ip_hdr{id} = int rand(2**16); } # either use their ttl or pick one that won't be appear forged # the 2.4 linux kernel defaults to 64, other OSs default to something else. if (defined($opt_ttl)) { $ip_hdr{ttl} = $opt_ttl; } else { $ip_hdr{ttl} = 200 + int rand(55); } # default to tcp, but give 'em the option if (defined($opt_proto)) { $ip_hdr{protocol} = $opt_proto; } else { $ip_hdr{protocol} = 6; } if (defined($opt_data)) { $tcp_hdr{data} = $opt_data; } elsif (defined($opt_fdata)) { # remember, you are root here. careful. # but if you want to shoot yourself in the foot, be my guest. open(FDATA, "$opt_fdata") || die "Couldn't open packet data: $!"; while() { $tcp_hdr{data} .= $_; } close(FDATA) || die "Couldn't close packet data: $!"; } # not setting a window causes Net::RawIP to use 65535 as the window # size. This sticks out like a sore thumb, so pick a carefully random # number instead. if (defined($opt_window)) { $tcp_hdr{window} = $opt_window; } else { $tcp_hdr{window} = 5000 + int rand(2000); } # take care of the flags if (defined($flags)) { # they want to set their own flags foreach (split(//,$flags)) { # these two reserved fields are really a single # 6-bit field as per the rfc if (/1/) { $tcp_hdr{res1} = 1; } if (/2/) { $tcp_hdr{res2} = 1; } if (/a/ || /A/) { $tcp_hdr{ack} = 1; } if (/f/ || /F/) { $tcp_hdr{fin} = 1; } if (/p/ || /P/) { $tcp_hdr{psh} = 1; } if (/r/ || /R/) { $tcp_hdr{rst} = 1; } if (/s/ || /S/) { $tcp_hdr{syn} = 1; } if (/u/ || /U/) { $tcp_hdr{urg} = 1; } } } elsif (defined($opt_rflags)) { # they want random flags (good luck) $tcp_hdr{ack} = int rand(2); $tcp_hdr{fin} = int rand(2); $tcp_hdr{psh} = int rand(2); $tcp_hdr{rst} = int rand(2); $tcp_hdr{syn} = int rand(2); $tcp_hdr{urg} = int rand(2); if (defined($opt_death)) { $tcp_hdr{res1} = int rand(4); $tcp_hdr{res2} = int rand(4); } } else { # default to a connect() $tcp_hdr{syn} = 1; } # set the rest of the packet based on the flags unless (defined($opt_death)) { if (defined($tcp_hdr{syn}) && $tcp_hdr{syn} == 1) { $tcp_hdr{seq} = int rand(2**32); } if (defined($tcp_hdr{ack}) && $tcp_hdr{ack} == 1) { if (defined($opt_ack)) { $tcp_hdr{ack_seq} = $opt_ack; } else { $tcp_hdr{ack_seq} = int rand(2**32); } unless(defined($tcp_hdr{seq})) { $tcp_hdr{seq} = int rand(2**32); } } if (defined($tcp_hdr{rst}) && $tcp_hdr{rst} == 1) { $tcp_hdr{seq} = int rand(2**32); } if (defined($tcp_hdr{urg}) && $tcp_hdr{urg} == 1) { $tcp_hdr{urg_ptr} = int rand(2**32); } } # make the packet real $packet->set({ip => \%ip_hdr, tcp => \%tcp_hdr}); # spew to the screen if (defined($opt_debug)) { print "_______________________\n"; printf "%d:%d:%d %d/%d/%d\n", localtime->hour, localtime->min, localtime->sec, localtime->mon + 1, localtime->mday, localtime->year + 1900; print "Source: $ip_hdr{'saddr'}:$tcp_hdr{'source'}\n"; print "Dest: $ip_hdr{'daddr'}:$tcp_hdr{'dest'}\n"; print "Flags: "; print "A" if(defined($tcp_hdr{'ack'}) && $tcp_hdr{'ack'} == 1); print "F" if(defined($tcp_hdr{'fin'}) && $tcp_hdr{'fin'} == 1); print "P" if(defined($tcp_hdr{'psh'}) && $tcp_hdr{'psh'} == 1); print "R" if(defined($tcp_hdr{'rst'}) && $tcp_hdr{'rst'} == 1); print "S" if(defined($tcp_hdr{'syn'}) && $tcp_hdr{'syn'} == 1); print "U" if(defined($tcp_hdr{'urg'}) && $tcp_hdr{'urg'} == 1); print " R1=$tcp_hdr{'res1'} " if(defined($tcp_hdr{'res1'})); print " R2=$tcp_hdr{'res2'} " if(defined($tcp_hdr{'res2'})); print "\n"; print "-----------------------\n"; } # kapow. unless (defined($opt_test)) { $packet->send; } } ###################################### # take a range of ports and hack 'em up into something useable ###################################### sub make_ports { my @ports; foreach (split(/,/, shift)) { if (/(\d+)-(\d+)/) { for (my $i = $1; $i <= $2; $i++) { push(@ports, $i); } } elsif (/(\d+)/) { push(@ports, $_); } else { die "Incorrect port specification!\n"; } } # randomize the array my $array = \@ports; for (my $i = @$array; --$i; ) { my $j = int rand ($i+1); next if $i == $j; @$array[$i,$j] = @$array[$j,$i]; } return @ports; } ########################### # generate a random IP (0-255.0-255.0-255.0-255) ########################### sub rand_ip { # this has caused "issues" when the random address turns out to be a multicast one. return (1 + int rand(239)).".".(int rand(256)).".".(int rand(256)).".".(int rand(256)); } sub rand_src { my @rand_net; if (defined($opt_src_net)) { my @src_net = split(/\./, $opt_src_net); foreach (0..3) { if(!defined($src_net[$_])){ die "Invalid src_net\n"; } else { # it's a nice range of numbers if ($src_net[$_] =~ /(\d+)-(\d+)/) { $rand_net[$_] = $1 + int rand($2-$1); } elsif ($src_net[$_] =~ /(\d+)/) { $rand_net[$_] = $1; } else { die "Invalid src net\n"; } } } return $rand_net[0] .".". $rand_net[1] .".". $rand_net[2] .".". $rand_net[3]; } else { return &rand_ip; } } sub rand_dest { my @rand_net; my @dest_net = split(/\./, $opt_dest_net); if (defined($opt_dest_net)) { foreach (0..3) { if(!defined($dest_net[$_])){ die "Invalid dest_net\n"; } else { # it's a nice range of numbers if ($dest_net[$_] =~ /(\d+)-(\d+)/) { $rand_net[$_] = $1 + int rand($2-$1); } elsif ($dest_net[$_] =~ /(\d+)/) { $rand_net[$_] = $1; } else { die "Invalid src net\n"; } } } return $rand_net[0] .".". $rand_net[1] .".". $rand_net[2] .".". $rand_net[3]; } else { return &rand_ip; } }