1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00

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.
This commit is contained in:
dmiller
2021-08-06 02:47:55 +00:00
parent 1ebd91fc0c
commit 9c97e008f7
5 changed files with 61 additions and 48 deletions

View File

@@ -28,6 +28,10 @@
# "source" keyword to specify a desired source port, but it is not # "source" keyword to specify a desired source port, but it is not
# honored by Nmap. # 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: # Example:
# udp 1234 "payloaddatapayloaddata" # udp 1234 "payloaddatapayloaddata"
# "payloaddatapayloaddata" # "payloaddatapayloaddata"

View File

@@ -267,6 +267,9 @@ static int load_payloads_from_file(FILE *fp) {
portPayload.data = payload_data; portPayload.data = payload_data;
portPayloadVector.push_back(portPayload); portPayloadVector.push_back(portPayload);
portPayloads[key] = portPayloadVector; 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 /* 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 a payload is returned, and for others a zero-length payload is returned. The
length is returned through the length pointer. */ 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 = ""; static const char *payload_null = "";
std::map<struct proto_dport, std::vector<struct payload> >::const_iterator portPayloadIterator; std::map<struct proto_dport, std::vector<struct payload> >::const_iterator portPayloadIterator;
std::vector<struct payload>::const_iterator portPayloadVectorIterator; std::vector<struct payload>::const_iterator portPayloadVectorIterator;
@@ -325,17 +328,17 @@ const char *udp_port2payload(u16 dport, size_t *length, u8 tryno) {
const std::vector<struct payload>& portPayloadVector = portPayloads.find(key)->second; const std::vector<struct payload>& portPayloadVector = portPayloads.find(key)->second;
portPayloadVectorSize = portPayloadVector.size(); portPayloadVectorSize = portPayloadVector.size();
tryno %= portPayloadVectorSize; index %= portPayloadVectorSize;
if (portPayloadVectorSize > 0) { if (portPayloadVectorSize > 0) {
portPayloadVectorIterator = portPayloadVector.begin(); portPayloadVectorIterator = portPayloadVector.begin();
while (tryno > 0 && portPayloadVectorIterator != portPayloadVector.end()) { while (index > 0 && portPayloadVectorIterator != portPayloadVector.end()) {
tryno--; index--;
portPayloadVectorIterator++; portPayloadVectorIterator++;
} }
assert (tryno == 0); assert (index == 0);
assert (portPayloadVectorIterator != portPayloadVector.end()); assert (portPayloadVectorIterator != portPayloadVector.end());
*length = portPayloadVectorIterator->data.size(); *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 returns the global random payload. Otherwise, for certain selected ports a
payload is returned, and for others a zero-length payload is returned. The payload is returned, and for others a zero-length payload is returned. The
length is returned through the length pointer. */ 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) { if (o.extra_payload != NULL) {
*length = o.extra_payload_length; *length = o.extra_payload_length;
return o.extra_payload; return o.extra_payload;
} else { } 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<struct proto_dport, std::vector<struct payload> >::const_iterator portPayloadIterator; std::map<struct proto_dport, std::vector<struct payload> >::const_iterator portPayloadIterator;
const proto_dport key(IPPROTO_UDP, dport); const proto_dport key(IPPROTO_UDP, dport);
size_t portPayloadVectorSize = 0; size_t portPayloadVectorSize = 0;

View File

@@ -66,9 +66,13 @@
#define PAYLOAD_FILENAME "nmap-payloads" #define PAYLOAD_FILENAME "nmap-payloads"
const char *get_udp_payload(u16 dport, size_t *length, u8 tryno); // Semi-arbitrary limit, but we use u8 for indexing/retrieval
const char *udp_port2payload(u16 dport, size_t *length, u8 tryno); // and we send all payloads at once and need to not overwhelm.
size_t udp_payload_count(u16 dport); #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); int init_payloads(void);
#endif /* PAYLOAD_H */ #endif /* PAYLOAD_H */

View File

@@ -2454,15 +2454,12 @@ static void doAnyOutstandingRetransmits(UltraScanInfo *USI) {
do { do {
probeI--; probeI--;
probe = *probeI; probe = *probeI;
if (probe->timedout && !probe->retransmitted && if (probe->retransmitted || probe->isPing()) {
(maxtries > probe->tryno || // Don't retransmit these
// We may exceed maxtries if this is UDP... continue;
((USI->udp_scan || (USI->ping_scan && USI->ptech.rawudpscan)) }
// ...and we haven't exceeded the manually-set max_retries // Retransmit if timed out and there are still tries remaining
&& USI->perf.tryno_cap > probe->tryno if (probe->timedout && maxtries > probe->tryno) {
// ...and there are more payloads we haven't tried.
&& udp_payload_count(probe->dport()) > probe->tryno)
) && !probe->isPing()) {
/* For rate limit detection, we delay the first time a new 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 */ is seen, as long as we are scanning at least 2 ports */
if (probe->tryno + 1 > (int) host->rld.max_tryno_sent && if (probe->tryno + 1 > (int) host->rld.max_tryno_sent &&

View File

@@ -1368,38 +1368,43 @@ UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
} else if (pspec->type == PS_UDP) { } else if (pspec->type == PS_UDP) {
const char *payload; const char *payload;
size_t payload_length; 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) { if (hss->target->af() == AF_INET) {
for (decoy = 0; decoy < o.numdecoys; decoy++) { for (decoy = 0; decoy < o.numdecoys; decoy++) {
packet = build_udp_raw(&((struct sockaddr_in *)&o.decoys[decoy])->sin_addr, hss->target->v4hostip(), packet = build_udp_raw(&((struct sockaddr_in *)&o.decoys[decoy])->sin_addr, hss->target->v4hostip(),
o.ttl, ipid, IP_TOS_DEFAULT, false, o.ttl, ipid, IP_TOS_DEFAULT, false,
o.ipoptions, o.ipoptionslen, o.ipoptions, o.ipoptionslen,
sport, pspec->pd.udp.dport, sport, pspec->pd.udp.dport,
(char *) payload, payload_length, (char *) payload, payload_length,
&packetlen); &packetlen);
if (decoy == o.decoyturn) { if (decoy == o.decoyturn) {
probe->setIP(packet, packetlen, pspec); probe->setIP(packet, packetlen, pspec);
probe->sent = USI->now; probe->sent = USI->now;
}
hss->probeSent(packetlen);
send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen);
free(packet);
} }
hss->probeSent(packetlen); } else if (hss->target->af() == AF_INET6) {
send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen); for (decoy = 0; decoy < o.numdecoys; decoy++) {
free(packet); 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,
} else if (hss->target->af() == AF_INET6) { (char *) payload, payload_length,
for (decoy = 0; decoy < o.numdecoys; decoy++) { &packetlen);
packet = build_udp_raw_ipv6(&((struct sockaddr_in6 *)&o.decoys[decoy])->sin6_addr, hss->target->v6hostip(), if (decoy == o.decoyturn) {
0, 0, o.ttl, sport, pspec->pd.tcp.dport, probe->setIP(packet, packetlen, pspec);
(char *) payload, payload_length, probe->sent = USI->now;
&packetlen); }
if (decoy == o.decoyturn) { hss->probeSent(packetlen);
probe->setIP(packet, packetlen, pspec); send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen);
probe->sent = USI->now; free(packet);
} }
hss->probeSent(packetlen);
send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen);
free(packet);
} }
} }
} else if (pspec->type == PS_SCTP) { } else if (pspec->type == PS_SCTP) {