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:
@@ -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"
|
||||||
|
|||||||
19
payload.cc
19
payload.cc
@@ -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;
|
||||||
|
|||||||
10
payload.h
10
payload.h
@@ -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 */
|
||||||
|
|||||||
@@ -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 &&
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user