📄 nessus_tcp_scanner.c
字号:
const int read_timeout, const int min_cnx, const int max_cnx, struct arglist *globals, struct arglist *desc, struct arglist *hostinfos, const int flags){ char buf[2048], kb[64]; int s, tcpproto, pass; struct protoent *proto; fd_set rfs, wfs, efs; struct timeval timeout, ti; struct sockaddr_in sa;#ifdef IPV6_SUPPORT struct sockaddr_in6 sa6;#endif int port = 23; int imax, i, j, x, opt; unsigned int optsz; int minport; int open_sock_nb, open_sock_max, open_sock_max2; int dropped_ports_nb, rejected_ports_nb; int dropped_nb, timeout_nb; int open_ports_nb, closed_ports_nb, untested_ports_nb; int scanned_port_nb = 0, total_ports_nb =0; int done_ports_nb = 0; /* debug */ struct timeval ti1; /* debug */ int cnx_max[3], rtt_max[3], rtt_min[3], ping_rtt = 0;#if defined COMPUTE_RTT double rtt_sum[3], rtt_sum2[3]; int rtt_nb[3]; static const char *rtt_type[] = {"unfiltered", "open", "closed" };#endif time_t start_time = time(NULL), start_time_1pass, end_time; long diff_time, diff_time1; int rst_rate_limit_flag = 0, doublecheck_flag = 0, old_doublecheck = 0;#if defined COMPUTE_RTT double mean, sd = -1.0, emax = -1.0;#endif /* Big variables are kept on the heap for broken OS * No need to free on function exit in the current architecture */ unsigned char *ports_states = emalloc(65536 * sizeof(ports_states[0])); grab_socket_t *sockets = emalloc((max_cnx+1) * sizeof(sockets[0])); debug_printf(pia, 1, "portrange=%s read_timeout=%dmin_cnx=%d max_cnx=%d flags=0x%x\n", portrange, read_timeout, min_cnx, max_cnx, flags); proto = getprotobyname("tcp"); if (proto == NULL) { perror("nessus_tcp_scanner->getprotobyname(\"tcp\")"); return -1; } tcpproto = proto->p_proto; for (i = 0; i < 65536; i ++) ports_states[i] = GRAB_PORT_NOT_TESTED; for (i = 0; i < 3; i ++) {#if defined COMPUTE_RTT rtt_sum[i] = rtt_sum2[i] = 0.0; rtt_nb[i] = 0;#endif rtt_max[i] = cnx_max[i] = 0; rtt_min[i] = MAXINT; } ping_rtt = get_ping_rtt(pia, desc); if ((untested_ports_nb = get_port_range((char*)portrange, ports_states)) < 0) { debug_printf(pia, 0, "nessus_tcp_scanner: get_port_range(%s) returns NULL. Fix your Nessus installation!\n", portrange); } for (i = 0; i < max_cnx; i ++) { sockets[i].state = GRAB_SOCKET_UNUSED; sockets[i].fd = -1; } open_sock_nb = 0; open_sock_max2 = max_cnx; open_ports_nb = closed_ports_nb = dropped_ports_nb = rejected_ports_nb = 0; /************************************************************************* * The main loop: we redo passes until the number of filtered ports reaches * zero, or do not change from the old pass. * We stop after MAX_SANE_RTT to protect us against pathological cases, like * a firewalled machine that returns (rate limited) ICMP *************************************************************************/ for (pass = 1; pass <= MAX_PASS_NB; pass ++) { int open_ports_nb1 = 0, closed_ports_nb1 = 0, dropped_ports_nb1 = 0; int old_open_sock_max = -1; int old_filtered = -1, old_opened = -1, old_untested_ports_nb; int wait_sock_nb = 0; int prev_scanned_port_nb = 0; int ipcced = 0; int err; int dropped_flag = 0; open_sock_max = pass == 1 || doublecheck_flag ? 1 : min_cnx / pass; if (open_sock_max < 1) open_sock_max = 1; if (open_sock_max2 <= open_sock_max) open_sock_max2 = open_sock_max * 2; if (open_sock_max2 > max_cnx) open_sock_max2 = max_cnx; old_untested_ports_nb = untested_ports_nb; /* recount ports & reset filtered ports */ recount_ports(ports_states, ! doublecheck_flag, /* standard filtered ports were already reset by double_check_std_ports */ &open_ports_nb, &closed_ports_nb, &dropped_ports_nb, &rejected_ports_nb, &untested_ports_nb); scanned_port_nb = open_ports_nb + closed_ports_nb + dropped_ports_nb + rejected_ports_nb; total_ports_nb = scanned_port_nb + untested_ports_nb; if (pass > 1) { if (doublecheck_flag) old_filtered = old_untested_ports_nb + rejected_ports_nb; else old_filtered = rejected_ports_nb + untested_ports_nb; old_opened = open_ports_nb; } minport = 1; start_time_1pass = time(NULL); debug_printf(pia, 1, "pass #%d: open_sock_max=%d open_sock_max2=%d max_cnx=%d\n", pass, open_sock_max, open_sock_max2, max_cnx); FD_ZERO(&rfs); FD_ZERO(&wfs); imax = -1; /******************************************************************** * The secondary loop: we test each port until everything is scanned ********************************************************************/ while (scanned_port_nb < total_ports_nb) { int congestion = 0; scanned_port_nb = open_ports_nb + closed_ports_nb + dropped_ports_nb + rejected_ports_nb; if (scanned_port_nb > prev_scanned_port_nb + 99) { if ( globals != NULL ) comm_send_status(globals, arg_get_value(hostinfos, "NAME"),"portscan", scanned_port_nb, total_ports_nb); prev_scanned_port_nb = scanned_port_nb; } x = open_ports_nb + closed_ports_nb + dropped_ports_nb + rejected_ports_nb; debug_printf(pia, 2, "%d / %d = %02d%% - %d ports remaining\n", x, total_ports_nb, (x * 100) / (total_ports_nb > 0 ? total_ports_nb : 1), untested_ports_nb);#if 1 if (open_sock_max > max_cnx) /* Bug! */ { debug_printf(pia, 0, "open_sock_max=%d > max_cnx=%d\n", open_sock_max, max_cnx); return -1; }#endifagain: while (open_sock_nb < open_sock_max) { static const int primes[] = { /* Those primes numbers are common service ports */ 23, 53, 113, 37, 3389, 1433, 587, 563, 443, 389, 139, 79, 7, 13, 17, 19 }; if (ipcc() != 0) { ipcced ++; goto select; }#define N_PRIMES (sizeof(primes) / sizeof(primes[0])) int i, multip = primes[pass % N_PRIMES]; for (i = minport; i < 65536; i ++) { if (flags & RANDOMIZE_PORTS_OPT) port = (i * multip) % 65536; else port = i; if (ports_states[port] == GRAB_PORT_UNKNOWN) break; } if (i > 65535) /* all ports done */ break; minport = i; /************************************************** * Open socket & set TCP/IP options **************************************************/ ports_states[port] = GRAB_PORT_TESTING; debug_printf(pia, 3, "Trying TCP:%d\n", port);#ifdef IPV6_SUPPORT s = socket(pia != NULL ? PF_INET:PF_INET6, SOCK_STREAM, tcpproto);#else s = socket(PF_INET, SOCK_STREAM, tcpproto);#endif /* Error at this point are rather bad */ if (s < 0) { if (errno == ENFILE) /* File table overflow */ { open_sock_max = open_sock_max2 = open_sock_nb / 2 - 1; /* NB: if open_sock_max2 < 0, the scanner aborts */ if (debug_level > 0) /* DEBUG: otherwise, we print a less frigthtening message */ perror("nessus_tcp_scanner->socket"); debug_printf(pia, 1, "Reducing the number of maximum open connections to %d [ENFILE]\n", open_sock_max); continue; } else if (errno == EMFILE) /* Too many open files */ { x = open_sock_nb / 16; /* 6.25% */ open_sock_max = open_sock_max2 = open_sock_nb - (x > 0 ? x : 1); /* NB: if open_sock_max2 < 0, the scanner aborts */ if (debug_level > 0) /* DEBUG: otherwise, we print a less frigthtening message */ perror("nessus_tcp_scanner->socket"); debug_printf(pia, 1, "Reducing the number of maximum open connections to %d [EMFILE]\n", open_sock_max); continue; } else { perror("nessus_tcp_scanner->socket"); return -1; } }#if defined FD_SETSIZE if (s >= FD_SETSIZE) { open_sock_max --; open_sock_max2 --; debug_printf(pia, 1, "socket=%d > FD_SETSIZE=%d - reducing the number of maximum open connections to %d\n", s, FD_SETSIZE, open_sock_max); if (close(s) < 0) perror("nessus_tcp_scanner->close"); continue; }#endif set_socket_source_addr(s, 0); if (set_nonblock(s) < 0) { debug_printf(pia, 0, "Could not set O_NONBLOCK. Aborting!\n"); return -1; } /* SMB only accepts one incoming connection. * It is safer to close the connection in foreground so that * if these ports are hit at the end of the scan, there is no * conflict if the next plugin tries to connect to SMB */ if (port != 139 && port != 445) set_so_linger(s); set_ip_tos(s); /* Things like TCP_QUICKACK or TCP_NODELAY are probably useless */ /*************************** * Connect the socket ***************************/ if (pia != NULL) { sa.sin_addr = *pia; sa.sin_family = AF_INET; sa.sin_port = htons(port); }#ifdef IPV6_SUPPORT else if (pia6 != NULL) { sa6 = *pia6; sa6.sin6_port = htons(port); }#endif ipci(); err = 0; if (pia != NULL) { if (! cct(*pia, port)) { err = -1; errno = ECONNREFUSED; } } if (err == 0) {#ifdef IPV6_SUPPORT err = connect(s, pia != NULL ? (struct sockaddr*)&sa:(struct sockaddr*)&sa6, pia != NULL ? sizeof(sa):sizeof(sa6));#else err = connect(s, (struct sockaddr*)&sa, sizeof(sa));#endif } if (err < 0) { switch (errno) { case EINPROGRESS: case EALREADY: sockets[open_sock_nb].fd = s; sockets[open_sock_nb].port = port; sockets[open_sock_nb].state = GRAB_SOCKET_OPENING; (void) gettimeofday(&sockets[open_sock_nb].tictac, NULL); open_sock_nb ++; FD_SET(s, &wfs); if (s > imax) imax = s; break; case EAGAIN: x = open_sock_nb / 16; /* 6.25% */ open_sock_max = open_sock_max2 = open_sock_nb - (x > 0 ? x : 1); /* If open_sock_max2 < 0, the scanner aborts */ debug_printf(pia, 1, "Reducing the number of maximum open connections to %d [EAGAIN]\n", open_sock_max); continue; /* As the socket is in asynchronous mode, connect() * should only return EINPROGRESS or EAGAIN * But against 127/8, this call is synchronous */ case ECONNREFUSED: ports_states[port] = GRAB_PORT_CLOSED; debug_printf(pia, 3, ">>> %d: CLOSED\n", port); my_socket_close(s); closed_ports_nb ++; closed_ports_nb1 ++; untested_ports_nb --; continue; case ENETUNREACH: case EHOSTUNREACH: ports_states[port] = GRAB_PORT_REJECTED; debug_printf(pia, 3, ">>> %d: FILTERED\n", port); my_socket_close(s); rejected_ports_nb ++; untested_ports_nb --; continue; default: perror("nessus_tcp_scanner->connect"); return -1; } } else /* This should only happen against 127/8 */ { sockets[open_sock_nb].fd = s; sockets[open_sock_nb].port = port; sockets[open_sock_nb].state = GRAB_SOCKET_OPEN; debug_printf(pia, 3, ">>> %d: OPEN\n", port); (void) gettimeofday(&sockets[open_sock_nb].tictac, NULL); open_sock_nb ++; ports_states[port] = GRAB_PORT_OPEN; open_ports_nb ++; open_ports_nb1 ++; wait_sock_nb ++; untested_ports_nb --; scanner_add_port(desc, port, "tcp"); } if (imax >= 0) /* imax is the biggest file descriptor */ { timeout.tv_sec = timeout.tv_usec = 0; if (select(imax + 1, NULL, &wfs, NULL, &timeout) > 0) { debug_printf(pia, 2, "select! Breaking loop (open_sock_nb=%d / %d)\n", open_sock_nb, open_sock_max); break; } } } /* while(open_sock_nb < open_sock_max) */ if (open_sock_max2 <= 0) { debug_printf(pia, 0, "file table is full. Aborting\n"); return -1; } if (open_sock_nb == 0) { debug_printf(pia, 1, "No more open socket\n"); goto end; } /****************** * Init fd_sets ******************/ select: FD_ZERO(&rfs); FD_ZERO(&wfs); FD_ZERO(&efs); imax = -1; for (i = 0; i < open_sock_nb; i ++) { if (sockets[i].fd >= 0) { switch (sockets[i].state) { case GRAB_SOCKET_OPEN: FD_SET(sockets[i].fd, &rfs); break; case GRAB_SOCKET_OPENING: FD_SET(sockets[i].fd, &wfs); break; default: debug_printf(pia, 0, "BUG! Bad status %d - s=%d\n", sockets[i].state, sockets[i].fd); break; } if (sockets[i].fd > imax) imax = sockets[i].fd; } } if (imax < 0) { if (untested_ports_nb > 0) { if (ipcced != 0) continue; debug_printf(pia, 0, "No socket! %d ports remaining\n", untested_ports_nb); return -1; } else { debug_printf(pia, 1, "No socket! No port remaining\n"); goto end; } } /***************************** * Estimate RTT & set timeout *****************************/ timeout_nb = 0; dropped_nb = 0; #if defined COMPUTE_RTT if (rtt_nb[0] > 1) { /* All values are in micro-seconds */ int em, moy; mean = rtt_sum[0] / (double)rtt_nb[0]; if ((double)rtt_max[0] > mean) { sd = sqrt((rtt_sum2[0] / rtt_nb[0] - mean * mean) * (double)rtt_nb[0] / (rtt_nb[0] - 1)); emax = mean + 3 * sd; em = floor(emax + 0.5); moy = floor(rtt_sum[0] / rtt_nb[0] + 0.5); if (em <= moy) { debug_printf(pia, 1, "arithmetic overflow: %g -> %d\n", emax, em); em = moy; } if (rtt_max[0] > em) { debug_printf(pia, 2, "rtt_nb=%d rtt_max = %g > %g (M=%g, SD=%g)\n", rtt_nb[0], (double)rtt_max[0] / 1e6, emax / 1e6, mean / 1e6, sd / 1e6); rtt_max[0] = em; } else debug_printf(pia, 3, "rtt_nb=%d rtt_max = %g < %g\n", rtt_nb[0], (double)rtt_max[0] / 1e6, emax / 1e6); } if (rtt_max[0] < rtt_min[0]) { debug_printf(pia, 2, "absurdly low rtt_max=%g < rtt_min = %g\n", (double)rtt_max[0] / 1e6, (double)rtt_min[0] / 1e6); rtt_max[0] = rtt_min[0];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -