nessus_tcp_scanner.c

来自「漏洞扫描源码,可以扫描linux,windows,交换机路由器」· C语言 代码 · 共 1,859 行 · 第 1/4 页

C
1,859
字号
		}	    }#endif	  /*	   * Some randomness is added to the timeout so that not all 	   * scanners fire at the same time when several firewalled 	   * machines are scanned in parallel.	   */	  if (wait_sock_nb == 0)	    if (rtt_max[0] > 0 || ping_rtt > 0)	      {		int	y;	/* used for debug */		if (rtt_max[0] > 0)		  x = rtt_max[0];		else 		  /* MA 2006-09-22		   * starting with just ping_rtt is dangerous: all ports 		   * might be declared "filtered". We use a higher value 		   * if the remote target does not answer		   */		  if (dropped_ports_nb1 > 0)		    x = ping_rtt * 2;		  else		/* No filtered port yet */		    x = (ping_rtt * 3) / 2;		x = (x * 6) / 5;		if (x > MAX_SANE_RTT) x = MAX_SANE_RTT;		y = x;		/* for debug only */		if (doublecheck_flag)		  {		    x = 3 * x + 20000;		    if (x > MAX_SANE_RTT) x = MAX_SANE_RTT;		    debug_printf(pia, 2, "basic timeout increased from %g to %g because of \"double check\"\n", y/1e6, x/1e6);		  }		if (x > 1000000)	/* more that 1 s: add 100ms at most */		  x += (unsigned)(lrand48() & 0x7FFFFFFF) % 100000;		else if (x > 20000) /* between 20 ms and 1 s: add <= 50 ms */		  x += (unsigned)(lrand48() & 0x7FFFFFFF) % 50000;		else		/* less than 20 ms: add 20 ms at mos */		  x = 20000 + (unsigned)(lrand48() & 0x7FFFFFFF) % 20000;		timeout.tv_sec = x / 1000000;		timeout.tv_usec = x % 1000000;		debug_printf(pia, 3, "timeout=%g -> %g\n", y/1e6, x/1e6);	      }	    else		/* No estimated RTT */	      {		/* Max RTT = 2 s ? */		timeout.tv_sec = 2;		timeout.tv_usec = (unsigned)(lrand48() & 0x7FFFFFFF) % 250000;	      }	  else			/* wait_sock_nb > 0 */	    {	      timeout.tv_sec = read_timeout; /* * 2 ? */	      timeout.tv_usec = (unsigned)(lrand48() & 0x7FFFFFFF) % 500000;	    }	  if (rtt_max[0] > 0)	    debug_printf(pia, 2, "wait_sock_nb=%d - timeout=%u.%06u - RTT=%f/%f/%f/%f\n", wait_sock_nb, timeout.tv_sec, timeout.tv_usec, (double)rtt_min[0] / 1e6, rtt_sum[0] / 1e6 / (rtt_nb[0] > 0 ? rtt_nb[0] : 1), (double)rtt_max[0] / 1e6, (double)cnx_max[0] / 1e6);	  else	    debug_printf(pia, 2, "wait_sock_nb=%d - timeout=%u.%06u\n", wait_sock_nb, timeout.tv_sec, timeout.tv_usec);	  if (debug_level > 0) gettimeofday(&ti1, NULL);	  /*********	   * select	   *********/	  i = 0;	  do	    {	      x = select(imax + 1, &rfs, &wfs, NULL, &timeout);	      if (errno == EINTR)		debug_printf(pia, 1, "select interrupted (i=%d)\n", i);	    }	  while (i ++ < 10 && x < 0 && errno == EINTR);	  if (x < 0)		/* select: severe error */	    {	      perror("nessus_tcp_scanner->select");	      return -1;	    }	  else if (x == 0)	/* select: timeout */	    {	      debug_printf(pia, 2, "select: timeout on all (%d) sockets!\n", imax - 1);	      for (i = 0; i < open_sock_nb; i ++)		{		  if (sockets[i].fd > 0)		    {		      my_socket_close(sockets[i].fd);		      sockets[i].fd = -1;		      switch (sockets[i].state)			{			case  GRAB_SOCKET_OPENING:			  debug_printf(pia, 3, ">> %d: TIMEOUT\n", sockets[i].port);			  ports_states[sockets[i].port] = GRAB_PORT_SILENT;			  dropped_ports_nb ++; dropped_ports_nb1 ++;			  dropped_nb ++;			  untested_ports_nb --;			  break;			case GRAB_SOCKET_OPEN:			  debug_printf(pia, 3, ">> %d: NO BANNER\n", sockets[i].port);			  wait_sock_nb --;			  break;			}		    }		  sockets[i].state = GRAB_SOCKET_UNUSED;		}	    }	  else			/* select: something to do */	    {	      (void) gettimeofday(&ti, NULL);	      debug_printf(pia, 2, "select replied in %f s [time=%d.%06d]\n", DIFFTVu(ti, ti1) / 1e6, ti.tv_sec, ti.tv_usec);	      for (i = 0; i < open_sock_nb; i ++)		{		  if (sockets[i].fd > 0) {		    if (FD_ISSET(sockets[i].fd, &wfs))		      {			opt = 0; optsz = sizeof(opt);			if (getsockopt(sockets[i].fd, SOL_SOCKET, SO_ERROR, &opt, &optsz) < 0)			  {			    perror("nessus_tcp_scanner->getsockopt");			    return -1;			  }			x = DIFFTVu(ti, sockets[i].tictac);			debug_printf(pia, 3, "RTT to %s:%d: %g s\n", 				pia ? inet_ntoa(*pia):"ipv6", sockets[i].port, x / 1e6);			if (opt != 0)			  {			    errno = opt;			    if (debug_level > 2)			      perror("nessus_tcp_scanner->getsockopt(SO_ERROR)");			    if (x > cnx_max[2]) cnx_max[2] = x;			    if (x < rtt_min[2]) rtt_min[2] = x;			    if (is_sane_rtt(x, sockets[i].fd, &congestion))			      {				if (x > rtt_max[2]) rtt_max[2] = x;#if defined COMPUTE_RTT				rtt_nb[2] ++;				rtt_sum[2] += (double)x;				rtt_sum2[2] += (double)x * (double)x;#endif			      }			    my_socket_close(sockets[i].fd);			    sockets[i].fd = -1;			    sockets[i].state = GRAB_SOCKET_UNUSED;			    untested_ports_nb --;			    switch (opt)			      {			      case ENETUNREACH:			      case EHOSTUNREACH:				ports_states[sockets[i].port] = GRAB_PORT_REJECTED;				rejected_ports_nb ++;				debug_printf(pia, 3, ">> %d: FILTERED\n", sockets[i].port);				break;			      case ECONNREFUSED:			      default:				ports_states[sockets[i].port] = GRAB_PORT_CLOSED;				closed_ports_nb ++;				closed_ports_nb1 ++;				debug_printf(pia, 3, ">> %d: CLOSED\n", sockets[i].port);				break;			      }			  }			else	/* getsockopt(SOL_SOCKET, SO_ERROR) = 0 */			  {			    sockets[i].state = GRAB_SOCKET_OPEN;			    debug_printf(pia, 3, ">> %d: OPEN\n", sockets[i].port);			    if (x > cnx_max[1]) cnx_max[1] = x;			    if (x < rtt_min[1]) rtt_min[1] = x;			    if (is_sane_rtt(x, sockets[i].fd, &congestion))			      {				if (x > rtt_max[1]) rtt_max[1] = x;#if defined COMPUTE_RTT				rtt_nb[1] ++;				rtt_sum[1] += (double)x;				rtt_sum2[1] += (double)x * (double)x;#endif			      }			    open_ports_nb ++;			    open_ports_nb1 ++;			    untested_ports_nb --;			    ports_states[sockets[i].port] = GRAB_PORT_OPEN;			    scanner_add_port(desc, sockets[i].port, "tcp");			    wait_sock_nb ++;			    snprintf(kb, sizeof(kb), "TCPScanner/CnxTime1000/%d", sockets[i].port);			    plug_set_key(desc, kb, ARG_INT, (void*)(x/1000));			    snprintf(kb, sizeof(kb), "TCPScanner/CnxTime/%d", sockets[i].port);			    plug_set_key(desc, kb, ARG_INT, (void*)((x + 500000) / 1000000));			    sockets[i].tictac = ti;			  } /* if (opt != 0) */			/* Adjust RTT */			if (x > cnx_max[0]) cnx_max[0] = x;			if (x < rtt_min[0]) rtt_min[0] = x;			if (is_sane_rtt(x, sockets[i].fd, &congestion))			  {			    if (x > rtt_max[0]) rtt_max[0] = x;#if defined COMPUTE_RTT			    rtt_nb[0] ++;			    rtt_sum[0] += (double)x;			    rtt_sum2[0] += (double)x * (double)x;#endif			  }		      }		    else if (FD_ISSET(sockets[i].fd, &rfs))		      {			x = read(sockets[i].fd, buf, sizeof(buf)-1);			if (x > 0)			  {			    char	buf2[sizeof(buf)*2+1];			    int y, flag = 0;			    bzero(buf2, sizeof(buf2));			    for (y = 0; y < x; y ++)			      {				snprintf(buf2 + 2*y, sizeof(buf2) - (2*y), "%02x", (unsigned char) buf[y]);				if (buf[y] == '\0') flag = 1;			      }			    if (flag)			      {				snprintf(kb, sizeof(kb),  "BannerHex/%d", sockets[i].port);				plug_set_key(desc, kb, ARG_STRING, buf2);			      }			    buf[x] = '\0';			    snprintf(kb, sizeof(kb), "Banner/%d", sockets[i].port);			    plug_set_key(desc, kb, ARG_STRING, buf);			    debug_printf(pia, 3, "Banner for port %d: %s", sockets[i].port, buf);			    x = DIFFTVu(ti, sockets[i].tictac) / 1000;			    snprintf(kb, sizeof(kb), "TCPScanner/RwTime1000/%d", sockets[i].port);			    plug_set_key(desc, kb, ARG_INT, (void*) x);			    snprintf(kb, sizeof(kb), "TCPScanner/RwTime/%d", sockets[i].port);			    plug_set_key(desc, kb, ARG_INT, (void*)((x + 500) / 1000));			  }			else			  if (debug_level > 0)			    perror("nessus_tcp_scanner->read");			wait_sock_nb --;			my_socket_close(sockets[i].fd);			sockets[i].fd = -1;			sockets[i].state = GRAB_SOCKET_UNUSED;		      }		  }		}	    } /* select */	  /************************	   * Check "stale" sockets	   ************************/	  (void) gettimeofday(&ti, NULL);	  for (i = 0; i < open_sock_nb; i ++)	    if (sockets[i].fd >= 0 && DIFFTV(ti, sockets[i].tictac) >= read_timeout)	      {		debug_printf(pia, 2, "pass #%d: timeout on port %d: %ld\n", pass, sockets[i].port, DIFFTV(ti, sockets[i].tictac));		switch(sockets[i].state)		  {		  case GRAB_SOCKET_OPEN:		    debug_printf(pia, 3, ">> %d: NO BANNER\n", sockets[i].port);		    timeout_nb ++;		    wait_sock_nb --;		    snprintf(kb, sizeof(kb), "/tmp/NoBanner/%d", sockets[i].port);		    plug_set_key(desc, kb, ARG_INT, (void *) 1);		    break;		  case GRAB_SOCKET_OPENING:		    debug_printf(pia, 3, ">> %d: TIMEOUT\n", sockets[i].port);		    ports_states[sockets[i].port] = GRAB_PORT_SILENT;		    dropped_ports_nb ++; dropped_ports_nb1 ++;		    dropped_nb ++;		    untested_ports_nb --;		    break;		  default:		    fprintf(stderr, "nesssus_tcp_scanner: Unhandled case %d at %s:%d\n", sockets[i].state, __FILE__, __LINE__);		    break;		  }		my_socket_close(sockets[i].fd); 		sockets[i].fd = -1;		sockets[i].state = GRAB_SOCKET_UNUSED;	      }	  /***********************************	   * Manage congestion, firewall...	   ***********************************/	  old_open_sock_max = open_sock_max;	  debug_printf(pia, 2, "open_sock_max=%d timeout_nb=%d dropped_nb=%d\n", open_sock_max, timeout_nb, dropped_nb);	  done_ports_nb = open_ports_nb + closed_ports_nb + dropped_ports_nb + rejected_ports_nb;	  if (done_ports_nb > 0 && total_ports_nb > 0 && debug_level > 1)	    {	      int	dt = time(NULL) - start_time_1pass;	      debug_printf(pia, 2, "pass #%d: time spent so far = %d s - estimated total time = %d s - estimated time remaining = %d s\n", 			   pass, dt,			   dt * total_ports_nb / done_ports_nb,			   dt * (total_ports_nb - done_ports_nb) / done_ports_nb);	    }	  if (! (flags & NET_CONGESTION_OPT) && congestion)	    {	      debug_printf(pia, 1, "operating system reports congestion. Ignored\n");	      congestion = 0;	    }	  if (dropped_nb > 0 && ! congestion &&	      dropped_nb >= (open_sock_nb * 9) / 10 && 	      (flags & DETECT_FIREWALL_OPT) &&#if 0	      /* voodoo test disabled */	      (dropped_nb < rejected_ports_nb + dropped_ports_nb 	       || dropped_nb > open_ports_nb + closed_ports_nb) &&#endif	      dropped_flag > 3)	    {	      /* firewalled machine? */	      debug_printf(pia, 2, "%d/%d connections dropped. Firewall?\n", dropped_nb, open_sock_nb);	      open_sock_max += (dropped_nb + 1) / 2;	      open_sock_max2 ++;	    }	  else if (dropped_nb > 0)	    {	      dropped_flag ++;	      if (open_sock_max > min_cnx)		x = dropped_nb + 1;	      else 		x = 2;	      /* Limit the decrease	       * otherwise, the firewall detection code would be nearly 	       * useless and the scanner would be very slow  */	      if (! doublecheck_flag && closed_ports_nb1 == 0)		x /= 2;	      if (x > open_sock_max / 2) x = open_sock_max / 2;	      if (x < 1) x = 1;	      open_sock_max -= x;	      if (open_sock_max < 1)		open_sock_max = 1;	      else		debug_printf(pia, 1, "%d connections dropped %s. Slowing down - min_cnx=%d - open_sock_nb=%d - open_sock_max=%d->%d - open_sock_max2=%d\n", 			     dropped_nb, 			     congestion ? "and congestion reported by OS" : "",			     min_cnx, open_sock_nb, old_open_sock_max, open_sock_max, open_sock_max2);	      open_sock_max2 = (open_sock_max  + 3 * open_sock_max2) / 4;	    }	  else if (congestion)	/* Nothing dropped, but OS complains */	    {	      open_sock_max --; open_sock_max2 --;	      if (open_sock_max < 1) open_sock_max = 1;	      if (open_sock_max2 < 1) open_sock_max2 = 1;	      debug_printf(pia, 1, "no connection dropped but OS reported congestion. Slowing down open_sock_max=%d->%d - open_sock_max2=%d\n", old_open_sock_max, open_sock_max, open_sock_max2);	    }	  else if (dropped_nb == 0 && dropped_flag > 0)	    {	      /* re-increase number of open sockets */	      if (++ open_sock_max > open_sock_max2) open_sock_max2 ++;	      debug_printf(pia, 1,"re-increasing open_sock_max from %d to %d\n", old_open_sock_max, open_sock_max);	      dropped_flag --;#if 0	      open_sock_max2 ++;#endif	    }	  else	    {	      open_sock_max += timeout_nb + 1;	      if (open_sock_max > open_sock_max2)		open_sock_max2 ++;	    }	  /* Set to minimum / maximum allowed values */	  if (open_sock_max2 > max_cnx) open_sock_max2 = max_cnx;	  if (open_sock_max > open_sock_max2) open_sock_max = open_sock_max2;	  if (open_sock_max < 1) open_sock_max = 1;	  if (open_sock_max2 < min_cnx) open_sock_max2 = min_cnx;	  debug_printf(pia, 3, "open_sock_max = %d -> %d\n", old_open_sock_max, open_sock_max);	  if (old_open_sock_max != open_sock_max && debug_level < 3)	    debug_printf(pia, 2, "open_sock_max=%d (old value %d)\n", open_sock_max, old_open_sock_max);	  /************************************	   * House work on the "sockets" array	   ************************************/	  for (i = 0; i < open_sock_nb; )	    if (sockets[i].state == GRAB_SOCKET_UNUSED || sockets[i].fd < 0)	      {		for (j = i +1;  		     j < open_sock_nb && (sockets[j].state == GRAB_SOCKET_UNUSED || sockets[j].fd < 0);		     j ++)		  ;		if (j < open_sock_nb)		  memmove(sockets+i, sockets+j, sizeof(*sockets) * (max_cnx - j));		open_sock_nb -= j - i;	      }	    else	      i ++;	} /* while (scanned_port_nb < total_ports_nb) */      /* End of the secondary loop*/    end:      end_time = time(NULL);      diff_time1 = end_time - start_time_1pass;      diff_time = end_time - start_time;      debug_printf(pia, 1, "pass #%d ran in %ld s - dropped_ports_nb=%d rejected_ports_nb=%d closed_ports_nb=%d open_ports_nb=%d\n", pass, diff_time1, dropped_ports_nb, rejected_ports_nb, closed_ports_nb, open_ports_nb);      /**************************************       * Check if we should run another pass.       * RST rate limitation is tested here.       **************************************/      old_doublecheck = doublecheck_flag;      if (dropped_flag ||	  (pass == 1 && dropped_ports_nb > 10 && closed_ports_nb > 10) ||	  (pass > 1 && dropped_ports_nb > 0) )	{	  if (doublecheck_flag && rst_rate_limit_flag && open_ports_nb == old_opened)	    {	      debug_printf(pia, 1, "Same number of open ports! Stopping now\n");	      break;	    }	  debug_printf(pia, 1, "pass #%d: old_opened=%d open_ports_nb=%d doublecheck_flag=%d rst_rate_limit_flag=%d\n", pass, old_opened, open_ports_nb, doublecheck_flag, rst_rate_limit_flag);	  debug_printf(pia, 1, "pass #%d: Suspicious number of dropped ports (%d) or closed ports (%d) - old_filtered=%d - running another time?\n", pass, dropped_ports_nb, closed_ports_nb, old_filtered);	  /* We don't want to simply compare dropped_ports_nb in case the 	   * target is rejecting our connections with rate-limited ICMP */	  if (dropped_ports_nb + rejected_ports_nb == old_filtered)	    if (open_ports_nb > 0 || doublecheck_flag)	      {		debug_printf(pia, 1, "Same number of filtered ports! Stopping now\n");		break;	      }	    else	      {		debug_printf(pia, 1, "No open port found!\n");		if ((untested_ports_nb = double_check_std_ports(ports_states, NULL)) == 0)		  {		    debug_printf(pia, 1, "pass #%d - No filtered standard ports - stopping\n", pass);		    break;		  }		debug_printf(pia, 1, "pass #%d - %d filtered standard ports - double-checking\n", pass, untested_ports_nb);		doublecheck_flag = 1;	      }	  else if (flags & RST_RATE_LIMIT_OPT) /* Look for RST rate limitation */	    {	      doublecheck_flag = 0;	      if (pass <= 1)		debug_printf(pia, 1, "RST rate limitation not tested on first pass\n");	      else if (! (open_ports_nb1 == 0 && closed_ports_nb1 >= min_cnx))		debug_printf(pia, 1, "RST rate limitation not tested - Found too many open ports (open_ports_nb1=%d>0) or not enough closed ports (closed_ports_nb1=%d < min_cnx=%d)\n",			     open_ports_nb1, closed_ports_nb1, min_cnx);	      else if (! (closed_ports_nb1 >= (diff_time1 + 1) * 10 && 			  closed_ports_nb1 < (diff_time1 + 1) * 201 && 			  closed_ports_nb >= (diff_time + 1) * 10 && 			  closed_ports_nb < (diff_time + 1) * 201) )		debug_printf(pia, 1, "RST test failed - %ld <= %d < %ld && %ld <= %d < %ld\n",			(diff_time1 + 1) * 10, closed_ports_nb1, (diff_time1 + 1) * 201, (diff_time + 1) * 10, closed_ports_nb, (diff_time + 1) * 201);	      if (pass > 1 && open_ports_nb1 == 0 && 		  closed_ports_nb1 >= min_cnx && 		  /*		   * Default value is 100 RST per second on OpenBSD, 		   * 200 on FreeBSD and 40 on Solaris 

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?