Date: Tue, 9 Feb 1999 20:53:34 -0500 From: miff Subject: sl0scan (ambiguous source portscanner) hello all, I hear that maybe nmap does something similar to this, but I'm posting it anyway to see if there is enough interest for me to continue developing it. This is based on some code that I have been evolving for a while now. sl0scan features: - you select which ports to scan using comma separated lists and ranges at runtime - *identical* scans sent from as many hosts as you like - random generation of dummy hosts, or it can read a file of desired fake scanning sources (or both). - choose at what sequence to insert the real scan (say, #500 out of 1000 scans) - status shown on screen also: - written in easily modifiable perl; all packet components are in variables sl0scan drawbacks: - you have to sniff the response. This really isnt so bad; you just do "tcpdump src " in a seperate window and look for the big "R" or "S" from each port. (S means the port was open). If there is interest, I'll fold in the packet capture function in the next release. - it can be slow depending on how you use it - tcp only at this release #!/usr/bin/perl # # sl0scan v0.1 # perl spoofer/scanner # based on lego # # written by miff Jan 1999 # # i wrote this in response to all the # email i got from lego saying: # "i'm not getting a response from the # portscan!!&^@#$" # # this version requests the following: # - which ports to scan # - how many fake hosts to use # - the "real" ip (any sniffable ip) # - an optional file of "real" fakes # - when to insert the real scan # # you are responsible for sniffing the response, # at this point. maybe that'll be automatic # in the future. # # shouts: b_, X, kubiak, shinex, xyg, ReDragon, #9mm # also: Clovis (where ya at h0mez?) # # best musical artist: mike patton. # use Socket; use strict qw(refs, subs); my $delay = 1; # delay in seconds between scans. its really important # not to end up with a synflood here, that will break the # scan. use a large real fake file to avoid DoS. my $input, $dummy; print "Welcome to sl0scan, the slowest scanner on the net.\n"; print "This program sends out a deluge of fake scans, and inserts \n"; print " a real scan somewhere in between. In this version, you \n"; print " must fire up a sniffer and watch for the responses to \n"; print " the real scan... Hope you know what to look for \n"; print "\n"; print "ready?\n"; $dummy = <>; print "good. here's where we axe you the 5 imp0tent questi0nz:\n\n"; print "1.) what is the IP ADDY or HOSTNAME of the target? \n"; $input = <>; chop $input; $target_box = $input; print "got $input.\n\n\n"; print "2.) what be the true source of the scan? (any sniffable ip will do) \n"; $input = <>; chop $input; $true_source = $input; print "got $input.\n\n\n"; print "3.) how many fakes should we dump on this homies fro? \n"; print "note: number of fakes will directly affect the sl0ness of the scan\n"; print " to the tune of at least 1 second per host. we don wanna dos here.. \n"; print " otoh, lots of fakes increase your invisibility \n"; $input = <>; chop $input; $num_fakes = $input; print "got $input. <-- hope that was a number...\n\n\n"; print "4.) which ports should we check? (IMPORTANT) \n"; print " i recommend as few as possible, as this will *really* slow shit down\n"; print "enter ports in the following format: COMMA DELIMITED, indicate ranges with dash\n"; print " example: i want to scan ports 22 23 25 80 and 130-140. i say: \n"; print "22,23,25,80,130-140\n"; print "avoid spaces and extra shit. save that for another time. \n"; $input = <>; chop $input; $portlist = $input; print "got $input. <-- if you screwed that up, bad shit is gonna happen.\n\n\n"; print "5.) At what sequence would you like the real scan inserted? \n"; print "note: this number must be <= the total number of fakes...\n"; $input = <>; chop $input; $real_seq = $input; $real_seq--; #gotta decrement; we start wit 0 print "got $input. <-- hope that was a number...\n\n\n"; print "6.) ok last one. Would you like to use a file of desired fakes?\n"; print "this gives you the advantage of choosing the fake ips, and \n"; print "avoiding the situation that all of the fake scans came from \n"; print "non-existent ips. i'd recommend using a large file here \n\n"; print "also, if you use all fake ips, even with the one second delay, \n"; print "you stand a greater chance of DOS'ing the target. which is bad.\n\n"; print "fyi, the format for the file is 1 ip or hostname per line, no extra shit. \n\n"; print " IF YOU WANT TO USE SUCH A FILE, enter the filename here:\n"; $input = <>; chop $input; $frofile = $input; print "got $input. <-- hope that was a real file...\n\n\n"; print "OK FOO, WE READY. YOU READY?\n"; $dummy = <>; my @frobobs; my $frocount = -1; # ok, first order of bidniss: lets get that file open if it exists: if ($frofile ne '') { if (-e $frofile) { #we got a file... open (FROFILE, $frofile) || die "cant open file, kid"; while ($input = ) { chop $input; $frocount++; @frobobs[$frocount] = $input; } close (FROFILE); # while we're at it, lets cal the percent of total fakes: $fro_percent = $frocount * 100 / $num_fakes; } } my $scancount = 0; my $src_box, $src_port; srand(time ^ $$); while ($scancount < $num_fakes) { # main driver routine if ($scancount == $real_seq) { #this is the real deal print "real scan!! (from $true_source) \n\n"; $src_box = $true_source; } else { # grab a random number between 0 and $num_fakes if ($randum > $frocount) { #create one my $rand1 = int(rand(230)) + 20; my $rand2 = int(rand(255)); my $rand3 = int(rand(255)); my $rand4 = int(rand(255)); $src_box = $rand1 . "." . $rand2 . "." . $rand3 . "." . $rand4; #for debugging: print "scan from $src_box \n"; } else { # use the array $randum = int(rand($num_fakes)); $src_box = @frobobs[$randum]; print "we gon fro from $src_box \n"; } } # now send the scan sc4n($target_box,$portlist,$src_box,$fake_port); # now sleep to avoid DoS: sleep($delay); $scancount++; } sub sc4n { my ($dest_host,$dest_ports,$src_host,$src_port) = @_; #print "in scan, got $dest_host,$dest_ports,$src_host,$src_port\n\n"; #set constants: my ($PROTO_RAW) = 255; # from /etc/protocols my ($PROTO_IP) = 0; #ditto my ($IP_HDRINCL) = 1; #we set the ip header, thanks #look up mah shit... $dest_host = (gethostbyname($dest_host))[4]; $src_host = (gethostbyname($src_host))[4]; #time to open a raw socket.... socket(S, AF_INET, SOCK_RAW, $PROTO_RAW) || die $!; #raw socket should be open... #now set the bad boy up... setsockopt(S, $PROTO_IP, $IP_HDRINCL, 1); # here we need to interpret the port list: my @ports1 = split (",",$dest_ports); my $psplit,$rcount,$range_low,$range_hi; my $p2count = 0; my @ports2; my @range; foreach $psplit (@ports1) { if ($psplit =~ '-') { # we have a range @range = split("-",$psplit); $range_low = @range[0]; $range_hi = @range[1]; $rcount = $range_low; while ($rcount <= $range_hi) { @ports2[$p2count] = $rcount; $p2count++; $rcount++; } } else { @ports2[$p2count] = $psplit; $p2count++; } } my $port; foreach $port (@ports2) { #build a tcp header: #vary the ports in here... $src_port = int(rand(60000)); my ($packet) = givehead($src_host, $src_port, $dest_host, $port, $data); #bust out the destination... my ($dest) = pack('S n a4 x8', AF_INET, $port, $dest_host); #send a fux0ring packet send (S,$packet,0, $dest); } } sub givehead { my ($src_host, $src_port, $dest_host, $dest_port, $data) = @_; #HERE WE PLAY WITH THE INSIDES OF THE TCP PIECE #AND CALC THE TCP HDR CHECKSUM. my $hdr_cksum = 0; # we set it to 0 so we can calculate it my $zero = 0; #might need a zero from time to time my $proto_tcp = 6; # the protocol number for tcp my ($tcplength) = 20; # 20 byte tcp hdr; no data # IF YOU ADD DATA, MAKE SURE TO ADD ITS PACKED LENGTH # TO THE TCPLENGTH HERE!!! # all of the source and destination infoz is passed to us # screw wit it in the parent routine... my $syn = 790047533; # random syn; try to keep it under 32 bits :) my $ack = 0; # zero ack; try to keep it under 32 bits :) my $tcp_4bit_hdrlen = "5"; # 5 * 32bit (4 byte) = 20 bytes my $tcp_4bit_reserved = 0; # reserved for 0 my $hdr_n_reserved = $tcp_4bit_hdrlen . $tcp_4bit_reserved; # pack them together my $tcp_urg_bit = 0; # URGENT POINTER BIT my $tcp_ack_bit = 0; # ACKNOWLEDGEMENT FIELD BIT my $tcp_psh_bit = 0; # PUSH REQUEST BIT my $tcp_rst_bit = 0; # RST (RESET CONNXION) BIT my $tcp_syn_bit = 1; # SYN FLAG BIT #its a syn!! my $tcp_fin_bit = 0; # FIN FLAG BIT # here we put together 2 reserved fields and the 6 flags to pack as binary. my $tcp_codebits = $zero . $zero . $tcp_urg_bit . $tcp_ack_bit . $tcp_psh_bit . $tcp_rst_bit . $tcp_syn_bit . $tcp_fin_bit; my $tcp_windowsize = 124; # default window size my $tcp_urgent_pointer = 0; # urgent pointer # the following is not a tcp header per se, but a pseudo header # used to calculate the tcp checksum. yes, its a pain in the ass. my ($pseudo_tcp) = pack ('a4 a4 C C n n n N N H2 B8 n v n', $src_host,$dest_host,$zero,$proto_tcp, $tcplength,$src_port,$dest_port, $syn,$ack, $hdr_n_reserved,$tcp_codebits, $tcp_windowsize,$zero,$tcp_urgent_pointer); my ($tcp_chksum) = &checkfro($pseudo_tcp); # PLAY WITH THE INNARDS OF THE IP PIECE HERE!!! my $ip_version = "4"; # (nybble) tcp/ip version number (current is 4) my $ip_hedlen = "5"; # (nybble) number of 32-bit words in ip header my $ver_n_hlen = $ip_version . $ip_hedlen; # we pack 2 nybbles together my $ip_tos = "00"; # (byte) ip type-of-service my ($totlength) = $tcplength + 20; #tcp + 20 byte ip hdr ## ## we'll pack totlength into 2 bytes in the packet my $ip_fragment_id = 31337; # 2 bytes as well. my $ip_3bit_flags = "010"; # ip fragmentation flags (3 bits) (frag, do not frag) my $ip_13bit_fragoffset = "0000000000000"; #fragment offset my $ip_flags_n_frags = $ip_3bit_flags . $ip_13bit_fragoffset; my $ip_ttl = 64; # 64 seconds / hops # we have proto_tcp from above... my $proto_tcp = 6; # we have hdr_checksum from above... # all source and destination infoz is passed to us (it # gets set in parent routine) # change $syn and $ack above in tcp section # in fact, everything else in the packet is set above. my ($hdr) = pack ('H2 H2 n n B16 C2 n a4 a4 n n N N H2 B8 n v n', $ver_n_hlen, $ip_tos, $totlength, $ip_fragment_id, $ip_flags_n_frags,$ip_ttl, $proto_tcp, $hdr_cksum, $src_host, $dest_host, # end of ip header, begin tcp header $src_port, $dest_port, $syn,$ack, $hdr_n_reserved,$tcp_codebits, $tcp_windowsize,$tcp_chksum,$tcp_urgent_pointer); return $hdr; } sub checkfro { #dis sekzhun robbed from someplace else.... my ( $msg # The message to checkfro ) = @_; my ($len_msg, # Length of the message $num_short, # The number of short words in the message $short, # One short word $chk # The checkfro ); $len_msg = length($msg); $num_short = $len_msg / 2; $chk = 0; foreach $short (unpack("S$num_short", $msg)) { $chk += $short; } # Add some lead $chk += unpack("C", substr($msg, $len_msg - 1, 1)) if $len_msg % 2; $chk = ($chk >> 16) + ($chk & 0xffff); # bust out mah fro pic return(~(($chk >> 16) + $chk) & 0xffff); # spray some jheri }