From 3f1ad0742e04cd994435adfe46e24d65222e02eb Mon Sep 17 00:00:00 2001 From: dmiller Date: Fri, 9 Dec 2016 04:19:45 +0000 Subject: [PATCH] New option --defeat-icmp-ratelimit. Closes #353, Fixes #216 --- CHANGELOG | 5 +++++ NmapOps.cc | 7 ++++++- NmapOps.h | 5 +++++ docs/refguide.xml | 19 +++++++++++++++++++ nmap.cc | 4 ++++ output.cc | 3 +++ scan_engine.cc | 22 +++++++++++++++++++++- 7 files changed, 63 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e3a4c851f..ff9ce2351 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,10 @@ # Nmap Changelog ($Id$); -*-text-*- +o [GH#353] New option --defeat-icmp-ratelimit dramatically reduces UDP scan + times in exchange for labeling unresponsive (and possibly open) ports as + "closed|filtered". Ports which give a UDP protocol response to one of Nmap's + scanning payloads will be marked "open". [Sergey Khegay] + o [NSE] Script cics-enum enumerates CICS transaction IDs, mapping to screens in TN3270 services. [Soldier of Fortran] diff --git a/NmapOps.cc b/NmapOps.cc index 6e9e2b686..1f6ffe3fa 100644 --- a/NmapOps.cc +++ b/NmapOps.cc @@ -323,6 +323,7 @@ void NmapOps::Initialize() { open_only = false; scanflags = -1; defeat_rst_ratelimit = 0; + defeat_icmp_ratelimit = 0; resume_ip.s_addr = 0; osscan_limit = 0; osscan_guess = 0; @@ -554,7 +555,11 @@ dialog where you can start NPF if you have administrator privileges."; servicescan = 0; if (defeat_rst_ratelimit && !synscan) { - fatal("Option --defeat-rst-ratelimit works only with a SYN scan (-sS)"); + fatal("Option --defeat-rst-ratelimit works only with a SYN scan (-sS)"); + } + + if (defeat_icmp_ratelimit && !udpscan) { + fatal("Option --defeat-icmp-ratelimit works only with a UDP scan (-sU)"); } if (resume_ip.s_addr && generate_random_ips) diff --git a/NmapOps.h b/NmapOps.h index c4de002a1..ba376dd7c 100644 --- a/NmapOps.h +++ b/NmapOps.h @@ -304,6 +304,11 @@ class NmapOps { slow against it. If we don't distinguish between closed and filtered ports, we can get the list of open ports very fast */ + int defeat_icmp_ratelimit; /* If a host rate-limits ICMP responses, then scanning + is very slow against it. This option prevents Nmap to adjust timing + when it changes the port's state because of ICMP response, as the latter + might be rate-limited. Doing so we can get scan results faster. */ + struct in_addr resume_ip; /* The last IP in the log file if user requested --restore . Otherwise restore_ip.s_addr == 0. Also diff --git a/docs/refguide.xml b/docs/refguide.xml index 6c05742cc..683c8eb54 100644 --- a/docs/refguide.xml +++ b/docs/refguide.xml @@ -2940,6 +2940,25 @@ worth the extra time. + + + + + +Similar to , the + option trades accuracy for speed, + increasing UDP scanning speed against hosts that rate-limit ICMP error + messages. Because this option causes Nmap to not delay in order to receive + the port unreachable messages, a non-responsive port will be labeled + closed|filtered instead of the default + open|filtered. This has the effect of only treating ports + which actually respond via UDP as open. Since many UDP + services do not respond in this way, the chance for inaccuracy is greater + with this option than with . + + + + diff --git a/nmap.cc b/nmap.cc index 0f61049e6..28215cefb 100644 --- a/nmap.cc +++ b/nmap.cc @@ -585,6 +585,8 @@ void parse_options(int argc, char **argv) { {"scanflags", required_argument, 0, 0}, {"defeat_rst_ratelimit", no_argument, 0, 0}, {"defeat-rst-ratelimit", no_argument, 0, 0}, + {"defeat_icmp_ratelimit", no_argument, 0, 0}, + {"defeat-icmp-ratelimit", no_argument, 0, 0}, {"host_timeout", required_argument, 0, 0}, {"host-timeout", required_argument, 0, 0}, {"scan_delay", required_argument, 0, 0}, @@ -835,6 +837,8 @@ void parse_options(int argc, char **argv) { delayed_options.pre_scan_delay = l; } else if (optcmp(long_options[option_index].name, "defeat-rst-ratelimit") == 0) { o.defeat_rst_ratelimit = 1; + } else if (optcmp(long_options[option_index].name, "defeat-icmp-ratelimit") == 0) { + o.defeat_icmp_ratelimit = 1; } else if (optcmp(long_options[option_index].name, "max-scan-delay") == 0) { l = tval2msecs(optarg); if (l < 0) diff --git a/output.cc b/output.cc index 69f7a81ce..04135b736 100644 --- a/output.cc +++ b/output.cc @@ -2543,6 +2543,9 @@ void printfinaloutput() { log_write(LOG_PLAIN, "OS detection performed. Please report any incorrect results at https://nmap.org/submit/ .\n"); else if (o.servicescan) log_write(LOG_PLAIN, "Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .\n"); + else if (o.udpscan && o.defeat_icmp_ratelimit) + log_write(LOG_PLAIN, "WARNING: Some ports marked closed|filtered may actually be open. For more accurate results, do not use --defeat-icmp-ratelimit .\n"); + } log_write(LOG_STDOUT | LOG_SKID, diff --git a/scan_engine.cc b/scan_engine.cc index cdb586548..42077dc78 100644 --- a/scan_engine.cc +++ b/scan_engine.cc @@ -865,7 +865,8 @@ static void set_default_port_state(std::vector &targets, stype scantyp (*target)->ports.setDefaultPortState(IPPROTO_TCP, PORT_OPENFILTERED); break; case UDP_SCAN: - (*target)->ports.setDefaultPortState(IPPROTO_UDP, PORT_OPENFILTERED); + (*target)->ports.setDefaultPortState(IPPROTO_UDP, + o.defeat_icmp_ratelimit ? PORT_CLOSEDFILTERED : PORT_OPENFILTERED); break; case IPPROT_SCAN: (*target)->ports.setDefaultPortState(IPPROTO_IP, PORT_OPENFILTERED); @@ -2125,6 +2126,25 @@ void ultrascan_port_probe_update(UltraScanInfo *USI, HostScanStats *hss, adjust_timing = false; adjust_ping = false; } + /* Do not slow down if + 1) we are in --defeat-icmp-ratelimit mode + 2) the new state is closed or filtered + 3) this is a UDP scan + We don't want to adjust timing when we get ICMP response, as the host might + be ratelimiting them. E.g. the port is actually closed, but the host ratelimiting + ICMP responses so we had to retransmit the probe several times in order to + match the (slow) rate limit that the target is using for responses. We + do not want to waste time on such ports. + On the other hand if the port is detected to be open it is a good idea to + adjust timing as we could have done retransmissions due to conjested network */ + if (rcvdtime != NULL + && o.defeat_icmp_ratelimit + && (newstate == PORT_CLOSED || newstate == PORT_FILTERED) + && USI->udp_scan) { + if (probe->tryno > 0) + adjust_timing = false; + adjust_ping = false; + } if (adjust_timing) { ultrascan_adjust_timing(USI, hss, probe, rcvdtime);