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
# 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"

View File

@@ -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<struct proto_dport, std::vector<struct payload> >::const_iterator portPayloadIterator;
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;
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<struct proto_dport, std::vector<struct payload> >::const_iterator portPayloadIterator;
const proto_dport key(IPPROTO_UDP, dport);
size_t portPayloadVectorSize = 0;

View File

@@ -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 */

View File

@@ -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 &&

View File

@@ -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) {