
/*
    ISNprint.c - display ISN numbers of a server

Recently, attacks against TCP/IP Initial Sequence Numbers were published :
 - CERT Advisory CA-2001-09 "Statistical Weaknesses in TCP/IP Initial 
   Sequence Numbers" - http://www.cert.org/advisories/CA-2001-09.html
 - Michal Zalewski "Strange Attractors and TCP/IP Sequence Number Analysis"
   http://razor.bindview.com/publish/papers/tcpseq.html

To predict ISN, there are two steps :
 - obtain the serie of generated ISN values
 - predict the next ISN which may be used by the server

This program achieves the first step by displaying ISN numbers of a server :
# ./ISNprint www.server.com 80
            ISN
     0 : 4213610146
     1 : 1433396694     [diff -2780213452]
     2 : 2342587356     [diff +0909190662]
     3 : 3904132205     [diff +1561544849]
     4 : 1742387478     [diff -2161744727]
     5 : 3486208657     [diff +1743821179]
     6 : 3263927723     [diff -0222280934]
     7 : 3514925853     [diff +0250998130]
     8 : 0729418132     [diff -2785507721]
     9 : 2770073670     [diff +2040655538]
    10 : 1643678857     [diff -1126394813]
    11 : 1658572002     [diff +0014893145]
    12 : 1871339414     [diff +0212767412]

The second step, the statistical prediction, is not done in this
program. If you are a statistical expert, you may want to complete
this program and publish it.


To compile :
# gcc -o ISNprint ISNprint.c -llcrzo -lpcap

The library lcrzo is needed :
  http://www.laurentconstantin.com/us/lcrzo/lcrzo/     [main server]
  http://go.to/laurentconstantin/us/lcrzo/lcrzo/       [backup server]
  http://laurentconstantin.est-la.com/us/lcrzo/lcrzo/  [backup server]
*/


/* include the library headers */
#include <lcrzo.h>
#if ! defined _POSIX_SOURCE
 #define _POSIX_SOURCE 1
#endif
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

/*-------------------------------------------------------------*/
/* function declarations */
void isn_sig_received1(int i);
void isn_sig_received2(int i);
int isn_sendsyn(lcrzo_device device,
		lcrzo_etha clientetha,
		lcrzo_etha destetha,
		lcrzo_ipl clientipl, 
		lcrzo_ipl serveripl, 
		lcrzo_uint16 serverport,
		lcrzo_uint16 startingclientport,
		lcrzo_uint32 startingclientseqnum);
int isn_print(lcrzo_device device,
	      lcrzo_etha clientetha,
	      lcrzo_etha destetha,
	      lcrzo_ipl clientipl, 
	      lcrzo_ipl serveripl, 
	      lcrzo_uint16 serverport,
	      lcrzo_uint16 startingclientport,
	      lcrzo_uint32 startingclientseqnum);
int isn_printseqnum(lcrzo_data sniffdata,
		    lcrzo_int32 sniffdatasize,
		    lcrzo_etha clientetha,
		    lcrzo_etha destetha,
		    lcrzo_ipl clientipl, 
		    lcrzo_ipl serveripl, 
		    lcrzo_uint16 serverport,
		    lcrzo_uint16 startingclientport,
		    lcrzo_uint32 startingclientseqnum);

/*-------------------------------------------------------------*/
/* global variables */
int isn_pid;
lcrzo_spoof isn_spoof;
lcrzo_sniff isn_sniff;

/*-------------------------------------------------------------*/
int main(int argc, char *argv[])
{ lcrzo_etha clientetha, destetha;
  lcrzo_ipl clientipl, serveripl;
  lcrzo_device device;
  lcrzo_uint16 serverport, startingclientport;
  lcrzo_uint32 startingclientseqnum;

  if ( argc<3 )
  { /* print usage */
    printf("Usage :   %s server port\n", argv[0]);
    printf("Example : %s 1.2.3.4 80\n", argv[0]);
    return(LCRZO_ERR_BULCRZOEXBADUSAGE);
  }

  /* set server information */
  lcrzo_epr(lcrzo_ipl_init_hs(argv[1], &serveripl));
  lcrzo_epr(lcrzo_uint16_init_text(argv[2], &serverport));

  /* obtain device and Ethernet addresses */
  lcrzo_epr(lcrzo_conf_route_to_host(serveripl, device,
				     clientetha, destetha,
				     &clientipl, NULL));

  /* determine starting values */
  lcrzo_epr(lcrzo_uint16_rand(5000, 30000, &startingclientport));
  lcrzo_epr(lcrzo_uint32_rand(0, 0xEFFFFFFFU, &startingclientseqnum));

  isn_pid=fork();
  if (isn_pid<0) return(LCRZO_ERR_FUFORK);
  if (isn_pid==0)
  { /* this process sends a SYN (we left to our computer the job to send
       a RST) */
    /* in case we receive a signal */
    signal(SIGINT, isn_sig_received1);
    lcrzo_epr(isn_sendsyn(device, clientetha, destetha,
			  clientipl, serveripl, serverport,
			  startingclientport, startingclientseqnum));
    /*never reatched*/
  }
  else
  { /* this process sniff and prints sequence numbers */
    /* in case we receive a signal */
    signal(SIGINT, isn_sig_received2);
    lcrzo_epr(isn_print(device, clientetha, destetha,
			clientipl, serveripl, serverport,
			startingclientport, startingclientseqnum));
    /*never reatched*/
  }
  /* never reatched */
  return (0);
}

/*-------------------------------------------------------------*/
void isn_sig_received1(int i)
{ int language;

  lcrzo_global_get_language(&language);
  if ( language==LCRZO_GLOBAL_FRLANG )
    printf("Fermeture du spoof (recu : SIG%d)\n", i);
  else
    printf("Closing spoof (received : SIG%d)\n", i);
  lcrzo_spoof_close(&isn_spoof);
  raise(SIGTERM);
}

/*-------------------------------------------------------------*/
void isn_sig_received2(int i)
{ int status, language;

  lcrzo_global_get_language(&language);
  if ( language==LCRZO_GLOBAL_FRLANG )
    printf("Fermeture du sniff (recu : SIG%d)\n", i);
  else
    printf("Closing sniff (received : SIG%d)\n", i);
  kill(isn_pid, SIGINT);
  waitpid(isn_pid, &status, 0);
  lcrzo_sniff_close(&isn_sniff);
  raise(SIGTERM);
}

/*-------------------------------------------------------------*/
int isn_sendsyn(lcrzo_device device,
		lcrzo_etha clientetha,
		lcrzo_etha destetha,
		lcrzo_ipl clientipl, 
		lcrzo_ipl serveripl, 
		lcrzo_uint16 serverport,
		lcrzo_uint16 startingclientport,
		lcrzo_uint32 startingclientseqnum)
{ lcrzo_hdrleth hdrleth;
  lcrzo_hdrlip hdrlip;
  lcrzo_hdrltcp hdrltcp;
  lcrzo_uint16 clientport;
  lcrzo_uint32 clientseqnum;

  /* initialize Ethernet header */
  lcrzo_epr(lcrzo_hdrleth_initdefault(&hdrleth));
  memcpy(hdrleth.src, clientetha, LCRZO_ETHA_MAXBYTES);
  memcpy(hdrleth.dst, destetha, LCRZO_ETHA_MAXBYTES);

  /* initialize IP header */
  lcrzo_epr(lcrzo_hdrlip_initdefault(&hdrlip));
  hdrlip.saddr=clientipl;
  hdrlip.daddr=serveripl;

  /* initialize TCP header */
  lcrzo_epr(lcrzo_hdrltcp_initdefault(&hdrltcp));
  hdrltcp.dport=serverport;
  hdrltcp.syn=1;
  clientport=startingclientport;
  clientseqnum=startingclientseqnum;

  /* spoof */
  lcrzo_epr(lcrzo_spoof_init(&isn_spoof));
  while(1)
  { lcrzo_epr(lcrzo_spoof_ethipopttcpoptdata(&isn_spoof, device, hdrleth,
					     hdrlip, NULL, 0,
					     hdrltcp, NULL, 0,
					     NULL, 0));
    hdrltcp.sport=clientport++;
    hdrltcp.seqnum=clientseqnum; clientseqnum+=10;
    /* you may want to remove this sleep, if you own the server */
    lcrzo_epr(lcrzo_time_sleep(100000));
  }
  /*never reatched*/
  return(LCRZO_ERR_IEINTERNALERROR);
}

/*-------------------------------------------------------------*/
int isn_print(lcrzo_device device,
	      lcrzo_etha clientetha,
	      lcrzo_etha destetha,
	      lcrzo_ipl clientipl, 
	      lcrzo_ipl serveripl, 
	      lcrzo_uint16 serverport,
	      lcrzo_uint16 startingclientport,
	      lcrzo_uint32 startingclientseqnum)
{ lcrzo_uint32 mtu;
  lcrzo_data sniffdata;
  lcrzo_int32 sniffdatasize;
  int ret;

  /* init sniff */
  lcrzo_epr(lcrzo_mtu_init_device(device, &mtu));
  lcrzo_epr(lcrzo_sniff_init(device, mtu, "", &isn_sniff));

  /* main loop */
  ret=lcrzo_sniff_nextm(&isn_sniff, LCRZO_TRUE, 
			LCRZO_SNIFF_TYPE_NORMAL, &sniffdata, &sniffdatasize);
  while (ret==LCRZO_ERR_OK)
  { /* decode TCP and print seqnum */
    lcrzo_epr(isn_printseqnum(sniffdata, sniffdatasize,
			      clientetha, destetha,
			      clientipl, serveripl, serverport,
			      startingclientport, 
			      startingclientseqnum));
    lcrzo_data_free(sniffdata);
    /* sniff next packet */
    ret=lcrzo_sniff_nextm(&isn_sniff, LCRZO_TRUE,
			  LCRZO_SNIFF_TYPE_NORMAL, &sniffdata, &sniffdatasize);
  }

  /* close everything */
  raise(SIGINT);
  /*never reatched*/
  return(LCRZO_ERR_IEINTERNALERROR);
}

/*-------------------------------------------------------------*/
int isn_printseqnum(lcrzo_data sniffdata,
		    lcrzo_int32 sniffdatasize,
		    lcrzo_etha clientetha,
		    lcrzo_etha destetha,
		    lcrzo_ipl clientipl, 
		    lcrzo_ipl serveripl, 
		    lcrzo_uint16 serverport,
		    lcrzo_uint16 startingclientport,
		    lcrzo_uint32 startingclientseqnum)
{ static lcrzo_uint32 oldseqnum;
 lcrzo_hdrleth hdrleth;
  lcrzo_hdrlip hdrlip;
  lcrzo_hdrltcp hdrltcp;
  int ret;
  lcrzo_uint32 diff1, diff2;

  /* try to decode it */
  ret=lcrzo_packet_decodem_ethipopttcpoptdata(sniffdata, sniffdatasize,
					      &hdrleth, &hdrlip, NULL, NULL,
					      &hdrltcp, NULL, NULL,
					      NULL, NULL);
  if ( ret!=LCRZO_ERR_OK )
    return(LCRZO_ERR_OK);
  /* only count synack */
  if ( ! (hdrltcp.syn && hdrltcp.ack) )
    return(LCRZO_ERR_OK);
  /* check if the addresses are the one we are looking for */
  if ( ! lcrzo_etha_equal(hdrleth.src, destetha) )
    return(LCRZO_ERR_OK);
  if ( ! lcrzo_etha_equal(hdrleth.dst, clientetha) )
    return(LCRZO_ERR_OK);
  if ( ! lcrzo_ipl_equal(hdrlip.saddr, serveripl) )
    return(LCRZO_ERR_OK);
  if ( ! lcrzo_ipl_equal(hdrlip.daddr, clientipl) )
    return(LCRZO_ERR_OK);
  /* check server port */
  if ( hdrltcp.sport!=serverport )
    return(LCRZO_ERR_OK);

  /* now this seems ok, but we verify with starting values */
  diff1=hdrltcp.dport-startingclientport;
  diff2=(hdrltcp.acknum-1-startingclientseqnum)/10;
  if ( diff1!=diff2 )
    return(LCRZO_ERR_OK);

  /* now, it's OK, so we print the seqnum */
  printf("% 6ld : %.10lu\t[diff ", diff1, hdrltcp.seqnum);
  if (hdrltcp.seqnum>=oldseqnum)
    printf("+%.10lu]\n", hdrltcp.seqnum-oldseqnum);
  else
    printf("-%.10lu]\n", oldseqnum-hdrltcp.seqnum);
  oldseqnum=hdrltcp.seqnum;
 
  return(LCRZO_ERR_OK);
}
