From 9c97e008f7bc28c263119c04b796bb900b199023 Mon Sep 17 00:00:00 2001 From: dmiller Date: Fri, 6 Aug 2021 02:47:55 +0000 Subject: [PATCH] Fix #2293: assertion failed probe->tryno == maxtries When tying UDP payloads to tryno, we were exceeding the maxtries in order to send all available payloads, leading to assertion failures. Currently there are not more than 4 payloads for any given port; most have none, many have 1, very few have more. So we will send them all at the same time with the same source port/tryno. --- nmap-payloads | 4 +++ payload.cc | 19 +++++++++------ payload.h | 10 +++++--- scan_engine.cc | 15 +++++------- scan_engine_raw.cc | 61 +++++++++++++++++++++++++--------------------- 5 files changed, 61 insertions(+), 48 deletions(-) diff --git a/nmap-payloads b/nmap-payloads index ee897d7e2..d1bd50518 100644 --- a/nmap-payloads +++ b/nmap-payloads @@ -28,6 +28,10 @@ # "source" keyword to specify a desired source port, but it is not # honored by Nmap. # +# Multiple payloads may be defined for a single protocol and port, in which +# case they will be all be sent concurrently. There is a limit of 255 payloads +# per port. +# # Example: # udp 1234 "payloaddatapayloaddata" # "payloaddatapayloaddata" diff --git a/payload.cc b/payload.cc index c48090dbe..b8145ced9 100644 --- a/payload.cc +++ b/payload.cc @@ -267,6 +267,9 @@ static int load_payloads_from_file(FILE *fp) { portPayload.data = payload_data; portPayloadVector.push_back(portPayload); portPayloads[key] = portPayloadVector; + if (portPayloadVector.size() > MAX_PAYLOADS_PER_PORT) { + fatal("Number of UDP payloads for port %u exceeds the limit of %u.\n", ports[p], MAX_PAYLOADS_PER_PORT); + } } } @@ -312,7 +315,7 @@ int init_payloads(void) { /* Get a payload appropriate for the given UDP port. For certain selected ports a payload is returned, and for others a zero-length payload is returned. The length is returned through the length pointer. */ -const char *udp_port2payload(u16 dport, size_t *length, u8 tryno) { +const char *udp_port2payload(u16 dport, size_t *length, u8 index) { static const char *payload_null = ""; std::map >::const_iterator portPayloadIterator; std::vector::const_iterator portPayloadVectorIterator; @@ -325,17 +328,17 @@ const char *udp_port2payload(u16 dport, size_t *length, u8 tryno) { const std::vector& portPayloadVector = portPayloads.find(key)->second; portPayloadVectorSize = portPayloadVector.size(); - tryno %= portPayloadVectorSize; + index %= portPayloadVectorSize; if (portPayloadVectorSize > 0) { portPayloadVectorIterator = portPayloadVector.begin(); - while (tryno > 0 && portPayloadVectorIterator != portPayloadVector.end()) { - tryno--; + while (index > 0 && portPayloadVectorIterator != portPayloadVector.end()) { + index--; portPayloadVectorIterator++; } - assert (tryno == 0); + assert (index == 0); assert (portPayloadVectorIterator != portPayloadVector.end()); *length = portPayloadVectorIterator->data.size(); @@ -354,16 +357,16 @@ const char *udp_port2payload(u16 dport, size_t *length, u8 tryno) { returns the global random payload. Otherwise, for certain selected ports a payload is returned, and for others a zero-length payload is returned. The length is returned through the length pointer. */ -const char *get_udp_payload(u16 dport, size_t *length, u8 tryno) { +const char *get_udp_payload(u16 dport, size_t *length, u8 index) { if (o.extra_payload != NULL) { *length = o.extra_payload_length; return o.extra_payload; } else { - return udp_port2payload(dport, length, tryno); + return udp_port2payload(dport, length, index); } } -size_t udp_payload_count(u16 dport) { +u8 udp_payload_count(u16 dport) { std::map >::const_iterator portPayloadIterator; const proto_dport key(IPPROTO_UDP, dport); size_t portPayloadVectorSize = 0; diff --git a/payload.h b/payload.h index ab1cba146..1f1577c70 100644 --- a/payload.h +++ b/payload.h @@ -66,9 +66,13 @@ #define PAYLOAD_FILENAME "nmap-payloads" -const char *get_udp_payload(u16 dport, size_t *length, u8 tryno); -const char *udp_port2payload(u16 dport, size_t *length, u8 tryno); -size_t udp_payload_count(u16 dport); +// Semi-arbitrary limit, but we use u8 for indexing/retrieval +// and we send all payloads at once and need to not overwhelm. +#define MAX_PAYLOADS_PER_PORT 0xff + +const char *get_udp_payload(u16 dport, size_t *length, u8 index); +const char *udp_port2payload(u16 dport, size_t *length, u8 index); +u8 udp_payload_count(u16 dport); int init_payloads(void); #endif /* PAYLOAD_H */ diff --git a/scan_engine.cc b/scan_engine.cc index 886ba484f..cba978000 100644 --- a/scan_engine.cc +++ b/scan_engine.cc @@ -2454,15 +2454,12 @@ static void doAnyOutstandingRetransmits(UltraScanInfo *USI) { do { probeI--; probe = *probeI; - if (probe->timedout && !probe->retransmitted && - (maxtries > probe->tryno || - // We may exceed maxtries if this is UDP... - ((USI->udp_scan || (USI->ping_scan && USI->ptech.rawudpscan)) - // ...and we haven't exceeded the manually-set max_retries - && USI->perf.tryno_cap > probe->tryno - // ...and there are more payloads we haven't tried. - && udp_payload_count(probe->dport()) > probe->tryno) - ) && !probe->isPing()) { + if (probe->retransmitted || probe->isPing()) { + // Don't retransmit these + continue; + } + // Retransmit if timed out and there are still tries remaining + if (probe->timedout && maxtries > probe->tryno) { /* For rate limit detection, we delay the first time a new tryno is seen, as long as we are scanning at least 2 ports */ if (probe->tryno + 1 > (int) host->rld.max_tryno_sent && diff --git a/scan_engine_raw.cc b/scan_engine_raw.cc index 4d6790216..48fdd6fa1 100644 --- a/scan_engine_raw.cc +++ b/scan_engine_raw.cc @@ -1368,38 +1368,43 @@ UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss, } else if (pspec->type == PS_UDP) { const char *payload; size_t payload_length; + u8 numpayloads = udp_payload_count(pspec->pd.udp.dport); + // Even if no payloads, we can send with null payload + numpayloads = MAX(numpayloads, 1); - payload = get_udp_payload(pspec->pd.udp.dport, &payload_length, tryno); + for (u8 i=0; i < numpayloads; i++) { + payload = get_udp_payload(pspec->pd.udp.dport, &payload_length, i); - if (hss->target->af() == AF_INET) { - for (decoy = 0; decoy < o.numdecoys; decoy++) { - packet = build_udp_raw(&((struct sockaddr_in *)&o.decoys[decoy])->sin_addr, hss->target->v4hostip(), - o.ttl, ipid, IP_TOS_DEFAULT, false, - o.ipoptions, o.ipoptionslen, - sport, pspec->pd.udp.dport, - (char *) payload, payload_length, - &packetlen); - if (decoy == o.decoyturn) { - probe->setIP(packet, packetlen, pspec); - probe->sent = USI->now; + if (hss->target->af() == AF_INET) { + for (decoy = 0; decoy < o.numdecoys; decoy++) { + packet = build_udp_raw(&((struct sockaddr_in *)&o.decoys[decoy])->sin_addr, hss->target->v4hostip(), + o.ttl, ipid, IP_TOS_DEFAULT, false, + o.ipoptions, o.ipoptionslen, + sport, pspec->pd.udp.dport, + (char *) payload, payload_length, + &packetlen); + if (decoy == o.decoyturn) { + probe->setIP(packet, packetlen, pspec); + probe->sent = USI->now; + } + hss->probeSent(packetlen); + send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen); + free(packet); } - hss->probeSent(packetlen); - send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen); - free(packet); - } - } else if (hss->target->af() == AF_INET6) { - for (decoy = 0; decoy < o.numdecoys; decoy++) { - packet = build_udp_raw_ipv6(&((struct sockaddr_in6 *)&o.decoys[decoy])->sin6_addr, hss->target->v6hostip(), - 0, 0, o.ttl, sport, pspec->pd.tcp.dport, - (char *) payload, payload_length, - &packetlen); - if (decoy == o.decoyturn) { - probe->setIP(packet, packetlen, pspec); - probe->sent = USI->now; + } else if (hss->target->af() == AF_INET6) { + for (decoy = 0; decoy < o.numdecoys; decoy++) { + packet = build_udp_raw_ipv6(&((struct sockaddr_in6 *)&o.decoys[decoy])->sin6_addr, hss->target->v6hostip(), + 0, 0, o.ttl, sport, pspec->pd.tcp.dport, + (char *) payload, payload_length, + &packetlen); + if (decoy == o.decoyturn) { + probe->setIP(packet, packetlen, pspec); + probe->sent = USI->now; + } + hss->probeSent(packetlen); + send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen); + free(packet); } - hss->probeSent(packetlen); - send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen); - free(packet); } } } else if (pspec->type == PS_SCTP) {