#
# This script was written by Noam Rathaus <noamr@securiteam.com>
#
# See the Nessus Scripts License for details
#
# Changes by rd : issue an alert only if some relation
# has been found.
#

if(description)
{
 script_id(10201);
 script_version ("$Revision: 1.24 $");
 name["english"] = "Relative IP Identification number change";
 script_name(english:name["english"]);
 
 desc["english"] = "
The remote host uses non-random IP IDs, that is, it is
possible to predict the next value of the ip_id field of
the ip packets sent by this host.

An attacker may use this feature to determine traffic patterns
within your network.   A few examples (not at all exhaustive) are:
 
1. A remote attacker can determine if the remote host sent a packet 
in reply to another request.  Specifically, an attacker can use your 
server as an unwilling participant in a blind portscan of another 
network.  

2. A remote attacker can roughly determine server requests at certain 
times of the day.  For instance, if the server is sending much more 
traffic after business hours, the server may be a reverse proxy or 
other remote access device.  An attacker can use this information to
concentrate his/her efforts on the more critical machines.

3. A remote attacker can roughly estimate the number of requests that 
a web server processes over a period of time.


Solution : Contact your vendor for a patch
Risk factor : Low";


 script_description(english:desc["english"]);
 
 summary["english"] = "Relative IP Identification number change";
 script_summary(english:summary["english"]);
 
 script_category(ACT_GATHER_INFO);
 
 script_copyright(english:"This script is Copyright (C) 1999 SecuriTeam");
 family["english"] = "General";
 script_family(english:family["english"]);
 script_dependencies("os_fingerprint.nasl", "snmp_sysDesc.nasl");
 
 exit(0);
}

#
# The script code starts here
#

include('global_settings.inc');

# localhost results are bogus
if(islocalhost())exit(0);

if ( report_paranoia == 0 ) exit(0);


os = get_kb_item("Host/OS/icmp");
if(os)
{
 if(egrep(pattern:"Solaris|Linux Kernel 2\.4", string:os, icase:TRUE))exit(0); 
}
else
{
 os = get_kb_item("SNMP/sysDesc");
 if(os)
 {
 if(egrep(pattern:"SunOS|Linux 2\.4", string:os))exit(0);
 }
}


srcaddr = this_host();
dstaddr = get_host_ip();

IPH = 20;
IP_LEN = IPH; 

ip = forge_ip_packet(   ip_v : 4,
			ip_hl : 5,
			ip_tos : 0,
			ip_len : IP_LEN, 
		        ip_id : 0xABA,
			ip_p : IPPROTO_TCP,
			ip_ttl : 255,
		        ip_off : 0,
			ip_src : srcaddr,
			ip_dst : dstaddr);

port = get_host_open_port();
if(!port)port = 137;

soc = open_sock_tcp(port);
if ( ! soc ) exit(0);
close ( soc );
 
tcpip = forge_tcp_packet(    ip       : ip,
                             th_sport : port,
                             th_dport : port,
                             th_flags : 0,
                             th_seq   : 0xF1C,
                             th_ack   : 0,
                             th_x2    : 0,
                             th_off   : 5,
                             th_win   : 512,
                             th_urp   : 0);

filter = string("tcp and src host ", dstaddr, " and dst host ", srcaddr, " and dst port ", port, " and src port ", port); 



relative = "-1";  
answer_count = 0;
for(i=0;i<10;i=i+1){
	r[i]="";
	o[i]="";
	}
for (packet_count = 0; packet_count < 10; packet_count = packet_count + 1)  
{
 result = send_packet(tcpip, pcap_active:TRUE, pcap_filter:filter);
 if ((packet_count > 3) && (answer_count == 0))
 {
  exit(0);
 }

 if (result)
 {
  ip_id = get_ip_element(ip:result, element:"ip_id");
  if(ip_id != 0 )
  {
   answer_count = answer_count + 1;
   if (relative == "-1")
   {
    relative = ip_id;
   }
   else
   {
   if(ip_id > relative){
   	max = ip_id;
	min = relative;
	}
   else {
   	max = relative;
	min = ip_id;
	}
   relative = max - min;
   r[answer_count-1] = relative;
   o[answer_count-1] = ip_id;
   relative = ip_id;
   }
  }
 }
}

ok = 1;

if(answer_count)
{


#
# Added by rd :
#

#
# if the ids are relative, then, we have a relation such as :
#
# 
#  n      =  n   +  m
#   i + 1      i
#
#
# with n   = i'th ip_id
#       i 
#
#
#
# so, we have :
# 
#  n      = n   + k*m
#   i + k    i 
#
#
# So it's pretty easy to find if ip_ids are relatives or not.
#

ni = 0;
m  = 0;
start = 0;
for(i=0;i<10;i=i+1)
{
 if(o[i]){
 	start = i;
	ni = o[i];
	i = 10;
	}
}

for(i=start+1;i<10;i=i+1)
{
 if(o[i])
 	{
	 if(o[i] > ni)
	  {
	   mx = o[i];
	   mn = ni;
	  }
	 else
	  {
	   mx = ni;
	   mn = o[i];
	  }
	  
	  m = mx - mn;
	  start = i;
	  i = 10;
	 }
}

ok = 1;
for(i=start+1;i<10;i=i+1)
{
 if(o[i])
 {
   if(o[i] > ni)
	  {
	   mx = o[i];
	   mn = ni;
	  }
	 else
	  {
	   mx = ni;
	   mn = o[i];
	  }
	  
	  km = mx - mn;
	  
	  #
	  # n  = n  + k x m
	  #  k    i 
	  #
	  # This implies that km % m = 0
	  # 
	  if(km % m){
	  	ok = 0;
		i = 1000;
		}
	 }
 }

#
#  end of rd's addition
#  
#



if(ok)security_warning(0);

}
