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 + -
显示快捷键?