mirror of
https://github.com/nmap/nmap.git
synced 2025-12-24 08:29:04 +00:00
Simplify and fix the logic surrounding the handling of host discovery
probes, especially IP protocol probes. Previously if IP protocol ping (-PO) was used anywhere in a host discovery scan, any response was treated as a protocol response. (The handlers for other response types had an explicit check for this.) This means that if you did nmap -PS -PO and got back a SYN/ACK in response to the -PS probe, it would be marked with a reason of proto-response rather than syn-ack. Now, because the IP protocol response handler matches so broadly, it is given the last chance at handling a response, only if no interpretation makes sense. Now the aforementioned scan will give a reason of syn-ack. The old behavior was not only misleading with respect to reasons, it had a minor and subtle bug. Consider the following packet trace: SENT (2.0990s) TCP 192.168.0.21:42205 > target:25 S ttl=40 id=39342 iplen=44 seq=114128202 win=1024 <mss 1460> SENT (2.2560s) TCP 192.168.0.21:42205 > target:53 S ttl=40 id=51247 iplen=44 seq=114128202 win=1024 <mss 1460> SENT (2.3280s) TCP 192.168.0.21:42206 > target:25 S ttl=37 id=31111 iplen=44 seq=114062667 win=2048 <mss 1460> RCVD (2.3530s) TCP target:53 > 192.168.0.21:42205 SA ttl=51 id=0 iplen=44 seq=4159224453 win=5840 ack=114128203 <mss 1460> ultrascan_host_probe_update called for machine target state UNKNOWN -> HOST_UP (trynum 1 time: 25123) Ultrascan DROPPED probe packet to target detected Changing ping technique for target to tcp to port 25; flags: S Why is the received packet marked as a drop? And why is the ping technique change to SYN to port 25 when the response came back from port 53? The reason is that the IP protocol response handler caught the probe and decided it was in response to one of the sent TCP probes--any of the TCP probes. It selected the probe to port 25 essentially at random and used that as the relevant probe. The result is that a drop is wrongly recorded (slowing down the scan), and a worse than useless ping probe is used (worse than useless because it will cause another drop any time it's used). I found this while trying to emulate PortBunny's default ping scan, which is -PS80,25,22,443,21,113,23,53,554,3389,445 -PA3333,11 -PE -PP -PU161,162 -PO51 though not in the same order Nmap uses.
This commit is contained in:
103
scan_engine.cc
103
scan_engine.cc
@@ -4078,33 +4078,6 @@ static int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
|
||||
if (bytes == 0)
|
||||
continue;
|
||||
|
||||
if (USI->ptech.rawprotoscan) {
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_addr.s_addr = ip->ip_src.s_addr;
|
||||
sin.sin_family = AF_INET;
|
||||
hss = USI->findHost((struct sockaddr_storage *) &sin);
|
||||
if (!hss) continue;
|
||||
setTargetMACIfAvailable(hss->target, &linkhdr, ip, 0);
|
||||
probeI = hss->probes_outstanding.end();
|
||||
listsz = hss->num_probes_outstanding();
|
||||
goodone = false;
|
||||
for(probenum = 0; probenum < listsz && !goodone; probenum++) {
|
||||
probeI--;
|
||||
probe = *probeI;
|
||||
|
||||
if (probe->protocol() == ip->ip_p) {
|
||||
/* if this is our probe we sent to localhost, then it doesn't count! */
|
||||
if (ip->ip_src.s_addr == ip->ip_dst.s_addr &&
|
||||
probe->ipid() == ntohs(ip->ip_id))
|
||||
continue;
|
||||
|
||||
newstate = HOST_UP;
|
||||
current_reason = ER_PROTORESPONSE;
|
||||
goodone = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* First check if it is ICMP, TCP, or UDP */
|
||||
if (ip->ip_p == IPPROTO_ICMP) {
|
||||
/* if it is our response */
|
||||
@@ -4120,7 +4093,7 @@ static int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
|
||||
current_reason = ping->code + ER_ICMPCODE_MOD;
|
||||
|
||||
/* Echo reply, Timestamp reply, or Address Mask Reply */
|
||||
if (ping->type == 0 || ping->type == 14 || ping->type == 18) {
|
||||
if (USI->ptech.rawicmpscan && (ping->type == 0 || ping->type == 14 || ping->type == 18)) {
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_addr.s_addr = ip->ip_src.s_addr;
|
||||
sin.sin_family = AF_INET;
|
||||
@@ -4172,7 +4145,7 @@ static int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
|
||||
}
|
||||
}
|
||||
// Destination unreachable, source quench, or time exceeded
|
||||
else if (ping->type == 3 || ping->type == 4 || ping->type == 11 || o.debugging) {
|
||||
else if (ping->type == 3 || ping->type == 4 || ping->type == 11) {
|
||||
struct ip *ip2 = (struct ip *) ((char *) ip + ip->ip_hl * 4 + 8);
|
||||
|
||||
requiredbytes = ip->ip_hl * 4 + 8U + ip2->ip_hl * 4 + 8U;
|
||||
@@ -4184,14 +4157,8 @@ static int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ip2->ip_p == IPPROTO_ICMP && !USI->ptech.rawprotoscan) {
|
||||
if (ip2->ip_p == IPPROTO_ICMP && USI->ptech.rawicmpscan) {
|
||||
/* The response was based on a ping packet we sent */
|
||||
if (!USI->ptech.rawicmpscan) {
|
||||
if (o.debugging)
|
||||
error("Got ICMP error referring to ICMP msg which we did not send");
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_addr.s_addr = ip2->ip_dst.s_addr;
|
||||
sin.sin_family = AF_INET;
|
||||
@@ -4223,13 +4190,8 @@ static int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
|
||||
/* Did we fail to find a probe? */
|
||||
if (probenum >= listsz)
|
||||
continue;
|
||||
} else if (ip2->ip_p == IPPROTO_TCP && !USI->ptech.rawprotoscan) {
|
||||
} else if (ip2->ip_p == IPPROTO_TCP && USI->ptech.rawtcpscan) {
|
||||
/* The response was based our TCP probe */
|
||||
if (!USI->ptech.rawtcpscan) {
|
||||
if (o.debugging)
|
||||
error("Got ICMP error referring to TCP msg which we did not send");
|
||||
continue;
|
||||
}
|
||||
struct tcp_hdr *tcp = (struct tcp_hdr *) (((char *) ip2) + 4 * ip2->ip_hl);
|
||||
/* Now ensure this host is even in the incomplete list */
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
@@ -4267,14 +4229,8 @@ static int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
|
||||
/* Did we fail to find a probe? */
|
||||
if (probenum >= listsz)
|
||||
continue;
|
||||
} else if (ip2->ip_p == IPPROTO_UDP && !USI->ptech.rawprotoscan) {
|
||||
} else if (ip2->ip_p == IPPROTO_UDP && USI->ptech.rawudpscan) {
|
||||
/* The response was based our UDP probe */
|
||||
if (!USI->ptech.rawudpscan) {
|
||||
if (o.debugging)
|
||||
error("Got ICMP error referring to UDP msg which we did not send");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((unsigned) ip2->ip_hl * 4 + 8 > bytes)
|
||||
continue;
|
||||
struct udp_hdr *udp = (struct udp_hdr *) ((u8 *) ip2 + ip2->ip_hl * 4);
|
||||
@@ -4319,7 +4275,12 @@ static int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
|
||||
/* Did we fail to find a probe? */
|
||||
if (probenum >= listsz)
|
||||
continue;
|
||||
} else if (USI->ptech.rawprotoscan) {
|
||||
} else if (o.debugging && !USI->ptech.rawprotoscan) {
|
||||
error("Got ICMP response to a packet which was not TCP, UDP, or ICMP");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!goodone && USI->ptech.rawprotoscan) {
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_addr.s_addr = ip2->ip_dst.s_addr;
|
||||
sin.sin_family = AF_INET;
|
||||
@@ -4352,10 +4313,6 @@ static int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
|
||||
/* Did we fail to find a probe? */
|
||||
if (probenum >= listsz)
|
||||
continue;
|
||||
} else {
|
||||
if (o.debugging)
|
||||
error("Got ICMP response to a packet which was not TCP, UDP, or ICMP");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ping->type == 3) {
|
||||
@@ -4388,10 +4345,7 @@ static int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
|
||||
log_write(LOG_STDOUT, "Got ICMP message type %d code %d\n", ping->type, ping->code);
|
||||
}
|
||||
}
|
||||
} else if (ip->ip_p == IPPROTO_TCP && !USI->ptech.rawprotoscan) {
|
||||
if (!USI->ptech.rawtcpscan) {
|
||||
continue;
|
||||
}
|
||||
} else if (ip->ip_p == IPPROTO_TCP && USI->ptech.rawtcpscan) {
|
||||
struct tcp_hdr *tcp = (struct tcp_hdr *) (((u8 *) ip) + 4 * ip->ip_hl);
|
||||
/* Check that the packet has useful flags. */
|
||||
if (!(tcp->th_flags & TH_RST)
|
||||
@@ -4467,10 +4421,7 @@ static int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
|
||||
if (o.debugging)
|
||||
log_write(LOG_STDOUT, "We got a TCP ping packet back from %s port %hi (trynum = %d)\n", inet_ntoa(ip->ip_src), ntohs(tcp->th_sport), trynum);
|
||||
}
|
||||
} else if (ip->ip_p == IPPROTO_UDP && !USI->ptech.rawprotoscan) {
|
||||
if (!USI->ptech.rawudpscan) {
|
||||
continue;
|
||||
}
|
||||
} else if (ip->ip_p == IPPROTO_UDP && USI->ptech.rawudpscan) {
|
||||
struct udp_hdr *udp = (struct udp_hdr *) (((char *) ip) + 4 * ip->ip_hl);
|
||||
/* Search for this host on the incomplete list */
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
@@ -4521,6 +4472,34 @@ static int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
|
||||
} else if (!USI->ptech.rawprotoscan && o.debugging) {
|
||||
error("Found whacked packet protocol %d in %s.", ip->ip_p, __func__);
|
||||
}
|
||||
|
||||
/* Check for a protocol reply */
|
||||
if (!goodone && USI->ptech.rawprotoscan) {
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_addr.s_addr = ip->ip_src.s_addr;
|
||||
sin.sin_family = AF_INET;
|
||||
hss = USI->findHost((struct sockaddr_storage *) &sin);
|
||||
if (!hss) continue;
|
||||
setTargetMACIfAvailable(hss->target, &linkhdr, ip, 0);
|
||||
probeI = hss->probes_outstanding.end();
|
||||
listsz = hss->num_probes_outstanding();
|
||||
goodone = false;
|
||||
for(probenum = 0; probenum < listsz && !goodone; probenum++) {
|
||||
probeI--;
|
||||
probe = *probeI;
|
||||
|
||||
if (probe->protocol() == ip->ip_p) {
|
||||
/* if this is our probe we sent to localhost, then it doesn't count! */
|
||||
if (ip->ip_src.s_addr == ip->ip_dst.s_addr &&
|
||||
probe->ipid() == ntohs(ip->ip_id))
|
||||
continue;
|
||||
|
||||
newstate = HOST_UP;
|
||||
current_reason = ER_PROTORESPONSE;
|
||||
goodone = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!goodone && !timedout);
|
||||
|
||||
if (goodone && newstate != HOST_UNKNOWN) {
|
||||
|
||||
Reference in New Issue
Block a user