1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-27 09:59:04 +00:00

Increase the base source port number on each run of ultra_scan.

Per-probe tryno and pingseq are encoded as offset from a the base source
port number. Previously this was fixed for all calls of ultra_scan,
which means that unrelated probes in different calls would use the same
source port number if they had the same tryno and pingseq. This could
cause erroneous results if a reply to a probe from a previous call was
delated and was received in the current call and interpreted as a legit
response.

This has no effect when o.magic_port_set is true (i.e., when -g or
--source-port is used).

http://seclists.org/nmap-dev/2012/q1/62
http://seclists.org/nmap-dev/2012/q3/589
This commit is contained in:
david
2012-08-28 13:07:54 +00:00
parent 5d809a2476
commit 39f42ef6d9

View File

@@ -118,6 +118,45 @@ using namespace std;
extern NmapOps o;
class UltraScanInfo;
/* We encode per-probe information like the tryno and pingseq in the source
port, for protocols that use ports. (Except when o.magic_port_set is
true--then we honor the requested source port.) The tryno and pingseq are
encoded as offsets from base_port, a base source port number (see
sport_encode and sport_decode). To avoid interpreting a late response from a
previous invocation of ultra_scan as a response for the same port in the
current invocation, we increase base_port by a healthy amount designed to be
greater than any offset likely to be used by a probe, each time ultra_scan is
run.
If we don't increase the base port, then there is the risk of something like
the following happening:
1. Nmap sends an ICMP echo and a TCP ACK probe to port 80 for host discovery.
2. Nmap receives an ICMP echo reply and marks the host up.
3. Nmap sends a TCP SYN probe to port 80 for port scanning.
4. Nmap finally receives a delayed TCP RST in response to its earlier ACK
probe, and wrongly marks port 80 as closed. */
static u16 base_port;
/* Clamp n to the range [min, max) in a modular fashion. */
static int mod_offset(int n, int min, int max) {
assert(min < max);
n = (n - min) % (max - min);
if (n < 0)
n += max - min;
return n + min;
}
/* Change base_port to a new number in a safe port range that is unlikely to
conflict with nearby past or future invocations of ultra_scan. */
static void increment_base_port() {
static bool initialized = false;
if (!initialized) {
base_port = mod_offset(get_random_uint(), 33000, 65536 - 256);
initialized = true;
} else {
base_port = mod_offset(base_port + 256, 33000, 65536 - 256);
}
}
/* A few extra performance tuning parameters specific to ultra_scan. */
struct ultra_scan_performance_vars : public scan_performance_vars {
/* When a successful ping response comes back, it counts as this many
@@ -2479,7 +2518,7 @@ static bool tcp_probe_match(const UltraScanInfo *USI, const UltraProbe *probe,
|| seq32_decode(USI, ntohl(tcp->th_seq), &tryno, &pingseq);
} else {
/* Get the values from the destination port (our source port). */
sport_decode(USI, o.magic_port, ntohs(tcp->th_dport), &tryno, &pingseq);
sport_decode(USI, base_port, ntohs(tcp->th_dport), &tryno, &pingseq);
goodseq = true;
}
@@ -3359,7 +3398,7 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
if (o.magic_port_set)
sport = o.magic_port;
else
sport = sport_encode(USI, o.magic_port, tryno, pingseq);
sport = sport_encode(USI, base_port, tryno, pingseq);
probe->tryno = tryno;
probe->pingseq = pingseq;
@@ -5264,7 +5303,7 @@ static int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
if (o.magic_port_set) {
trynum = probe->tryno;
} else {
sport_decode(USI, o.magic_port, ntohs(udp->uh_dport), &trynum, NULL);
sport_decode(USI, base_port, ntohs(udp->uh_dport), &trynum, NULL);
}
/* Sometimes we get false results when scanning localhost with
@@ -5678,6 +5717,8 @@ void ultra_scan(vector<Target *> &Targets, struct scan_lists *ports,
stype scantype, struct timeout_info *to) {
o.current_scantype = scantype;
increment_base_port();
init_payloads(); /* Load up _all_ payloads into a mapped table */
if (Targets.size() == 0) {