Homemade TCP Packets

by miff

The code presented here is a subset of my alpha Perl spoofer, slapfro, which is available from 9mm.com/philez.html.  I thought it would be nice to see something other than a knockoff of a knockoff of a spoofer for once and maybe give some more people the ability to play with the insides of TCP/IP.

Greetz, boys and gurliez.  Today, we play with the insides of TCP/IP.  In particular, we'll be building a TCP spoofer in Perl (Yeah, you can do ICMP or UDP tooo if ya want).  We'll call this one - umm - lego.  All we really wanna do with lego is build our own packets.  This can be useful if you like to set the source address to something arbitrary, or if you want to experiment with flags or some shit.  We're not going to do TCP connection spoofing, because that would be too big in scope for our purposes.  At this point we'll just send out some TCP packets with increasing port numbers, sort of like the way a half-opened port scan would look.

If lots of people begin to use this, we get the added benefit of making uptight sysadmins look silly, and finally teaching them that port scanning is neither harmful, intrusive, nor necessarily evidence that anything at all came from the apparent source of the scan.  Ahem.

There are three main sections of code that we will use to create our packet: the first sets up things like source and destination address, ports, number of packets, and any looping and shit that we might use to send lots of packets or to vary the packets, say, by incrementing the destination port each time we send.  The second section is the guts: we figure out what our IP and TCP headers will look like, then we put the packet together.  The third section calculates a checksum for the packet - used to tell the receiving machine that the packet didn't get mangled in transit.  I admit, I ripped off the checksum code from Net::Ping.  Shit, who wants to write checksum code when its already there for you?  The three sections are nested 1, 2, 3 - they each use the next as a subroutine.

A Quick Tour

The first point of interest is the specifications of target box, source box and ports.  If your ambition is low, and all you want to do is watch some home-brewed TCP packets fly, just put in some valid source and destination addresses, run a sniffer, and enjoy.  For the slightly more motivated, you could take these five items as parameters from the command line.

tcpsp00f Routine

This is the first main routine - we do things like convert our hostname or IP address into something usable (gethostbyname) and set a few constants that we will use to indicate what we are building and how much of it we're responsible for (typically, the OS will do things like set the source address for you).  We open our socket here and get ready to send the packet - we start the port incrementing loop, because we wanna send one packet to each port in the range $dest_port_low -> $dest_port_hi.  The only thing we need now is the packet.  our givehead routine, which used to be used only for headers, will construct the entire packet for us.  At this point, we put no data in the packet (don't need any) but if you wanna add some, just append it.  Make sure you account for the increased packet length in your assorted length vars to come.  Once we're done sending packets, we chill and have a 40, and our packet maker tells us that the scan is complete.

givehead routine

This is the big baby Jesus routine of the program.  I've taken the liberty of sticking literally everything in variables, so it will be hard to screw up.  givehead does two things: first we create a TCP pseudo-header on which to calculate the TCP checksum.  We do a lot of the setup of the TCP portion of the packet at this time, even though the IP header parts actually come first.  We use the Perl "pack" command to put each variable into the precise format that we need it in (see O'Reilly's Programming Perl for a reasonable but not great explanation of the pack statement).  At this point, it would also be wicked handy to know what a TCP packet looks like - get TCP/IP Illustrated, Vol 1.  It's the best.  Otherwise you can browse the RFCs or find little charts from networking classes or something.  Just understand the size, meaning, and ordering of all of the fields in a TCP packet.

O.K., nuff preachie.  Here is where our more ambitious readers can really get loose.  Take note of the $tcp_variables, and later the ip_variables.  Want to set a SYN, FIN, and RST in the same packet?  Switch these to "1".  Wanna screw with sequence and acknowledgment numbers?  Go ahead - even put in a little routine to increment them if you like.  Make the packet length wicked long and send no data.  Fool with the urgent flag and pointer (remember the OOB attack?), etc., etc.

Oh yeah - the second step, after we've got the TCP checksum, is to put it all together along with the IP header.  This is a good place to set fragmentation options, type of service, time to live, even IP version.  You should be able to build just about any TCP looking packet that you can imagine just by messing with the variables.  Note to selves: do not put an unfriendly data type in a variable.  Example: do not put a "2" in a bit field.  Thanks for playing.

The last routine is the checksum routine, and like I said, i stole it.(I re-commented it for aesthetic purposes).  At least it ain't from ping.c

peace and enjoy

[ Built and tested in Linux 2.0.28, Perl v5.03. ]

#!/usr/bin/perl 
#
#  lego
#   perl spoofer demo prog
#   written for 2600
#
#  based on slapfro, alpha version 
#  written by miff
#
#  TCP fake portscan only.
#
#  shout outs:  shinex.
#

use Socket;
use strict	qw(refs, subs);

#SOURCE AND DESINTATION PARAMETERS
# MUST CHANGE THESE.
my $target_box = "chrome.9mm.com";
my $target_low_port = "23";
my $target_hi_port = "23";
my $source_box = "funhouse.9mm.com";
my $source_starting_port = "10000";

tcpsp00f($target_box,$target_low_port,$target_hi_port,$source_box,$source_starting_port);

sub tcpsp00f  {
	my ($dest_host,$dest_port_low,$dest_port_hi,$src_host,$src_port) = @_;

	#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);  

	my ($port) = $dest_port_low;

	print "\n INITIATING FAKE PORTSCAN \n\n";
	while ($port <= $dest_port_hi) {
		$src_port++; 
		#build a tcp header:
		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);
		$port++;
	}
	print "\n portscan sent, beeyatch \n\n ";

}

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
}

Code lego.pl

Return to $2600 Index