mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
Adjust how timeouts are handled with labeling services tcpwrapped. Fixes #39
This commit is contained in:
@@ -29,6 +29,11 @@ o Solve a crash on Windows (reported on Windows 8.1 on Surface Pro 3) caused by
|
|||||||
passing a NULL pointer to a WinPcap function that then tries to write an
|
passing a NULL pointer to a WinPcap function that then tries to write an
|
||||||
error message to it. [Peter Malecka]
|
error message to it. [Peter Malecka]
|
||||||
|
|
||||||
|
o Enhance Nmap's tcpwrapped service detection by using a shorter timeout for
|
||||||
|
the tcpwrapped designation. This prevents falsely labeling services as
|
||||||
|
tcpwrapped which merely have a read timeout shorter than 6 seconds. Full
|
||||||
|
discussion: http://issues.nmap.org/39 [nnposter, Daniel Miller]
|
||||||
|
|
||||||
o Integrated all of your IPv6 OS fingerprint submissions from June 2013 to
|
o Integrated all of your IPv6 OS fingerprint submissions from June 2013 to
|
||||||
April 2015 (only 97 of them!). We are steadily improving the IPv6 database,
|
April 2015 (only 97 of them!). We are steadily improving the IPv6 database,
|
||||||
but we need your submissions. The classifier added 9 new groups, bringing the
|
but we need your submissions. The classifier added 9 new groups, bringing the
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ Probe TCP NULL q||
|
|||||||
# smtp services have lately been instituting an artificial pause (see
|
# smtp services have lately been instituting an artificial pause (see
|
||||||
# FEATURE('greet_pause') in Sendmail, for example)
|
# FEATURE('greet_pause') in Sendmail, for example)
|
||||||
totalwaitms 6000
|
totalwaitms 6000
|
||||||
|
# If the service closes the connection before 3 seconds, it's probably
|
||||||
|
# tcpwrapped. Adjust up or down depending on your false-positive rate.
|
||||||
|
tcpwrappedms 3000
|
||||||
|
|
||||||
match 1c-server m|^S\xf5\xc6\x1a{| p/1C:Enterprise business management server/
|
match 1c-server m|^S\xf5\xc6\x1a{| p/1C:Enterprise business management server/
|
||||||
|
|
||||||
|
|||||||
@@ -218,6 +218,9 @@ public:
|
|||||||
// when SSL is detected -- we redo all probes through SSL. If freeFP, any
|
// when SSL is detected -- we redo all probes through SSL. If freeFP, any
|
||||||
// service fingerprint is freed too.
|
// service fingerprint is freed too.
|
||||||
void resetProbes(bool freefp);
|
void resetProbes(bool freefp);
|
||||||
|
// Number of milliseconds used so far to complete the present probe. Timeval
|
||||||
|
// can omitted, it is just there as an optimization in case you have it handy.
|
||||||
|
int probe_timemsused(const ServiceProbe *probe, const struct timeval *now = NULL);
|
||||||
// Number of milliseconds left to complete the present probe, or 0 if
|
// Number of milliseconds left to complete the present probe, or 0 if
|
||||||
// the probe is already expired. Timeval can omitted, it is just there
|
// the probe is already expired. Timeval can omitted, it is just there
|
||||||
// as an optimization in case you have it handy.
|
// as an optimization in case you have it handy.
|
||||||
@@ -235,6 +238,9 @@ public:
|
|||||||
// INVALIDATED if you call appendtocurrentproberesponse() or nextProbe()
|
// INVALIDATED if you call appendtocurrentproberesponse() or nextProbe()
|
||||||
u8 *getcurrentproberesponse(int *respstrlen);
|
u8 *getcurrentproberesponse(int *respstrlen);
|
||||||
AllProbes *AP;
|
AllProbes *AP;
|
||||||
|
// Is it possible this service is tcpwrapped? Not if a probe times out or
|
||||||
|
// gets a real response.
|
||||||
|
bool tcpwrap_possible;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Adds a character to servicefp. Takes care of word wrapping if
|
// Adds a character to servicefp. Takes care of word wrapping if
|
||||||
@@ -1044,6 +1050,7 @@ ServiceProbe::ServiceProbe() {
|
|||||||
probename = NULL;
|
probename = NULL;
|
||||||
probestring = NULL;
|
probestring = NULL;
|
||||||
totalwaitms = DEFAULT_SERVICEWAITMS;
|
totalwaitms = DEFAULT_SERVICEWAITMS;
|
||||||
|
tcpwrappedms = DEFAULT_TCPWRAPPEDMS;
|
||||||
probestringlen = 0; probeprotocol = -1;
|
probestringlen = 0; probeprotocol = -1;
|
||||||
// The default rarity level for a probe without a rarity
|
// The default rarity level for a probe without a rarity
|
||||||
// directive - should almost never have to be relied upon.
|
// directive - should almost never have to be relied upon.
|
||||||
@@ -1314,6 +1321,11 @@ void parse_nmap_service_probe_file(AllProbes *AP, char *filename) {
|
|||||||
if (waitms < 100 || waitms > 300000)
|
if (waitms < 100 || waitms > 300000)
|
||||||
fatal("Error on line %d of nmap-service-probes file (%s): bad totalwaitms value. Must be between 100 and 300000 milliseconds", lineno, filename);
|
fatal("Error on line %d of nmap-service-probes file (%s): bad totalwaitms value. Must be between 100 and 300000 milliseconds", lineno, filename);
|
||||||
newProbe->totalwaitms = waitms;
|
newProbe->totalwaitms = waitms;
|
||||||
|
} else if (strncmp(line, "tcpwrappedms ", 12) == 0) {
|
||||||
|
long waitms = strtol(line + 12, NULL, 10);
|
||||||
|
if (waitms < 100 || waitms > 300000)
|
||||||
|
fatal("Error on line %d of nmap-service-probes file (%s): bad tcpwrappedms value. Must be between 100 and 300000 milliseconds", lineno, filename);
|
||||||
|
newProbe->tcpwrappedms = waitms;
|
||||||
} else if (strncmp(line, "match ", 6) == 0 || strncmp(line, "softmatch ", 10) == 0) {
|
} else if (strncmp(line, "match ", 6) == 0 || strncmp(line, "softmatch ", 10) == 0) {
|
||||||
newProbe->addMatch(line, lineno);
|
newProbe->addMatch(line, lineno);
|
||||||
} else if (strncmp(line, "Exclude ", 8) == 0) {
|
} else if (strncmp(line, "Exclude ", 8) == 0) {
|
||||||
@@ -1564,6 +1576,7 @@ ServiceNFO::ServiceNFO(AllProbes *newAP) {
|
|||||||
softMatchFound = false;
|
softMatchFound = false;
|
||||||
servicefplen = servicefpalloc = 0;
|
servicefplen = servicefpalloc = 0;
|
||||||
servicefp = NULL;
|
servicefp = NULL;
|
||||||
|
tcpwrap_possible = true;
|
||||||
memset(¤tprobe_exec_time, 0, sizeof(currentprobe_exec_time));
|
memset(¤tprobe_exec_time, 0, sizeof(currentprobe_exec_time));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1816,9 +1829,8 @@ void ServiceNFO::resetProbes(bool freefp) {
|
|||||||
probe_state = PROBESTATE_INITIAL;
|
probe_state = PROBESTATE_INITIAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ServiceNFO::probe_timemsused(const ServiceProbe *probe, const struct timeval *now) {
|
||||||
int ServiceNFO::probe_timemsleft(const ServiceProbe *probe, const struct timeval *now) {
|
int timeused;
|
||||||
int timeused, timeleft;
|
|
||||||
|
|
||||||
if (now)
|
if (now)
|
||||||
timeused = TIMEVAL_MSEC_SUBTRACT(*now, currentprobe_exec_time);
|
timeused = TIMEVAL_MSEC_SUBTRACT(*now, currentprobe_exec_time);
|
||||||
@@ -1832,7 +1844,16 @@ int ServiceNFO::probe_timemsleft(const ServiceProbe *probe, const struct timeval
|
|||||||
// probe == currentProbe(). Check that this remains the case.
|
// probe == currentProbe(). Check that this remains the case.
|
||||||
assert(probe == currentProbe());
|
assert(probe == currentProbe());
|
||||||
|
|
||||||
timeleft = probe->totalwaitms - timeused;
|
return timeused;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ServiceNFO::probe_timemsleft(const ServiceProbe *probe, const struct timeval *now) {
|
||||||
|
|
||||||
|
// Historically this function was always called with the assumption that
|
||||||
|
// probe == currentProbe(). Check that this remains the case.
|
||||||
|
assert(probe == currentProbe());
|
||||||
|
|
||||||
|
int timeleft = probe->totalwaitms - probe_timemsused(probe, now);
|
||||||
return (timeleft < 0)? 0 : timeleft;
|
return (timeleft < 0)? 0 : timeleft;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2154,7 +2175,7 @@ static void end_svcprobe(nsock_pool nsp, enum serviceprobestate probe_state, Ser
|
|||||||
std::list<ServiceNFO *>::iterator member;
|
std::list<ServiceNFO *>::iterator member;
|
||||||
Target *target = svc->target;
|
Target *target = svc->target;
|
||||||
|
|
||||||
svc->probe_state = probe_state;
|
svc->probe_state = svc->tcpwrap_possible ? PROBESTATE_FINISHED_TCPWRAPPED : probe_state;
|
||||||
member = find(SG->services_in_progress.begin(), SG->services_in_progress.end(),
|
member = find(SG->services_in_progress.begin(), SG->services_in_progress.end(),
|
||||||
svc);
|
svc);
|
||||||
if (member != SG->services_in_progress.end()) {
|
if (member != SG->services_in_progress.end()) {
|
||||||
@@ -2378,9 +2399,11 @@ static void servicescan_read_handler(nsock_pool nsp, nsock_event nse, void *myda
|
|||||||
assert(type == NSE_TYPE_READ);
|
assert(type == NSE_TYPE_READ);
|
||||||
|
|
||||||
if (svc->target->timedOut(nsock_gettimeofday())) {
|
if (svc->target->timedOut(nsock_gettimeofday())) {
|
||||||
|
svc->tcpwrap_possible = false;
|
||||||
end_svcprobe(nsp, PROBESTATE_INCOMPLETE, SG, svc, nsi);
|
end_svcprobe(nsp, PROBESTATE_INCOMPLETE, SG, svc, nsi);
|
||||||
} else if (status == NSE_STATUS_SUCCESS) {
|
} else if (status == NSE_STATUS_SUCCESS) {
|
||||||
// w00p, w00p, we read something back from the port.
|
// w00p, w00p, we read something back from the port.
|
||||||
|
svc->tcpwrap_possible = false;
|
||||||
readstr = (u8 *) nse_readbuf(nse, &readstrlen);
|
readstr = (u8 *) nse_readbuf(nse, &readstrlen);
|
||||||
adjustPortStateIfNecessary(svc); /* A response means PORT_OPENFILTERED is really PORT_OPEN */
|
adjustPortStateIfNecessary(svc); /* A response means PORT_OPENFILTERED is really PORT_OPEN */
|
||||||
svc->appendtocurrentproberesponse(readstr, readstrlen);
|
svc->appendtocurrentproberesponse(readstr, readstrlen);
|
||||||
@@ -2466,6 +2489,7 @@ static void servicescan_read_handler(nsock_pool nsp, nsock_event nse, void *myda
|
|||||||
// move on to the next probe. If this was a NULL probe, we can simply
|
// move on to the next probe. If this was a NULL probe, we can simply
|
||||||
// send the new probe text immediately. Otherwise we make a new connection.
|
// send the new probe text immediately. Otherwise we make a new connection.
|
||||||
|
|
||||||
|
svc->tcpwrap_possible = false;
|
||||||
readstr = svc->getcurrentproberesponse(&readstrlen);
|
readstr = svc->getcurrentproberesponse(&readstrlen);
|
||||||
if (readstrlen > 0)
|
if (readstrlen > 0)
|
||||||
svc->addToServiceFingerprint(svc->currentProbe()->getName(), readstr,
|
svc->addToServiceFingerprint(svc->currentProbe()->getName(), readstr,
|
||||||
@@ -2477,14 +2501,15 @@ static void servicescan_read_handler(nsock_pool nsp, nsock_event nse, void *myda
|
|||||||
// If this was during the NULL probe, let's (for now) assume
|
// If this was during the NULL probe, let's (for now) assume
|
||||||
// the port is TCP wrapped. Otherwise, we'll treat it as a nomatch
|
// the port is TCP wrapped. Otherwise, we'll treat it as a nomatch
|
||||||
readstr = svc->getcurrentproberesponse(&readstrlen);
|
readstr = svc->getcurrentproberesponse(&readstrlen);
|
||||||
if (readstrlen > 0)
|
if (readstrlen > 0) {
|
||||||
svc->addToServiceFingerprint(svc->currentProbe()->getName(), readstr,
|
svc->addToServiceFingerprint(svc->currentProbe()->getName(), readstr,
|
||||||
readstrlen);
|
readstrlen);
|
||||||
if (probe->isNullProbe() && readstrlen == 0) {
|
svc->tcpwrap_possible = false;
|
||||||
|
}
|
||||||
|
if (svc->tcpwrap_possible && probe->isNullProbe() && readstrlen == 0 && svc->probe_timemsused(probe) < probe->tcpwrappedms) {
|
||||||
// TODO: Perhaps should do further verification before making this assumption
|
// TODO: Perhaps should do further verification before making this assumption
|
||||||
end_svcprobe(nsp, PROBESTATE_FINISHED_TCPWRAPPED, SG, svc, nsi);
|
end_svcprobe(nsp, PROBESTATE_FINISHED_TCPWRAPPED, SG, svc, nsi);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Perhaps this service didn't like the particular probe text.
|
// Perhaps this service didn't like the particular probe text.
|
||||||
// We'll try the next one
|
// We'll try the next one
|
||||||
startNextProbe(nsp, nsi, SG, svc, true);
|
startNextProbe(nsp, nsi, SG, svc, true);
|
||||||
@@ -2498,7 +2523,7 @@ static void servicescan_read_handler(nsock_pool nsp, nsock_event nse, void *myda
|
|||||||
// BSD sometimes gives it
|
// BSD sometimes gives it
|
||||||
case ECONNABORTED:
|
case ECONNABORTED:
|
||||||
// Jerk hung up on us. Probably didn't like our probe. We treat it as with EOF above.
|
// Jerk hung up on us. Probably didn't like our probe. We treat it as with EOF above.
|
||||||
if (probe->isNullProbe()) {
|
if (svc->tcpwrap_possible && probe->isNullProbe() && svc->probe_timemsused(probe) < probe->tcpwrappedms) {
|
||||||
// TODO: Perhaps should do further verification before making this assumption
|
// TODO: Perhaps should do further verification before making this assumption
|
||||||
end_svcprobe(nsp, PROBESTATE_FINISHED_TCPWRAPPED, SG, svc, nsi);
|
end_svcprobe(nsp, PROBESTATE_FINISHED_TCPWRAPPED, SG, svc, nsi);
|
||||||
} else {
|
} else {
|
||||||
@@ -2520,6 +2545,7 @@ static void servicescan_read_handler(nsock_pool nsp, nsock_event nse, void *myda
|
|||||||
case EHOSTUNREACH:
|
case EHOSTUNREACH:
|
||||||
// That is funny. The port scanner listed the port as open. Maybe it got unplugged, or firewalled us, or did
|
// That is funny. The port scanner listed the port as open. Maybe it got unplugged, or firewalled us, or did
|
||||||
// something else nasty during the scan. Shrug. I'll give up on this port
|
// something else nasty during the scan. Shrug. I'll give up on this port
|
||||||
|
svc->tcpwrap_possible = false;
|
||||||
end_svcprobe(nsp, PROBESTATE_INCOMPLETE, SG, svc, nsi);
|
end_svcprobe(nsp, PROBESTATE_INCOMPLETE, SG, svc, nsi);
|
||||||
break;
|
break;
|
||||||
#ifdef ENOPROTOOPT
|
#ifdef ENOPROTOOPT
|
||||||
@@ -2559,6 +2585,7 @@ static void servicescan_read_handler(nsock_pool nsp, nsock_event nse, void *myda
|
|||||||
} else if (status == NSE_STATUS_KILL) {
|
} else if (status == NSE_STATUS_KILL) {
|
||||||
/* User probably specified host_timeout and so the service scan is
|
/* User probably specified host_timeout and so the service scan is
|
||||||
shutting down */
|
shutting down */
|
||||||
|
svc->tcpwrap_possible = false;
|
||||||
end_svcprobe(nsp, PROBESTATE_INCOMPLETE, SG, svc, nsi);
|
end_svcprobe(nsp, PROBESTATE_INCOMPLETE, SG, svc, nsi);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -141,6 +141,7 @@
|
|||||||
|
|
||||||
/********************** DEFINES/ENUMS ***********************************/
|
/********************** DEFINES/ENUMS ***********************************/
|
||||||
#define DEFAULT_SERVICEWAITMS 5000
|
#define DEFAULT_SERVICEWAITMS 5000
|
||||||
|
#define DEFAULT_TCPWRAPPEDMS 2000 // connections closed after this timeout are not considered "tcpwrapped"
|
||||||
#define DEFAULT_CONNECT_TIMEOUT 5000
|
#define DEFAULT_CONNECT_TIMEOUT 5000
|
||||||
#define DEFAULT_CONNECT_SSL_TIMEOUT 8000 // includes connect() + ssl negotiation
|
#define DEFAULT_CONNECT_SSL_TIMEOUT 8000 // includes connect() + ssl negotiation
|
||||||
#define SERVICEMATCH_REGEX 1
|
#define SERVICEMATCH_REGEX 1
|
||||||
@@ -264,6 +265,8 @@ class ServiceProbe {
|
|||||||
// probe (e.g. an SMTP probe would commonly identify port 25)
|
// probe (e.g. an SMTP probe would commonly identify port 25)
|
||||||
// Amount of time to wait after a connection succeeds (or packet sent) for a responses.
|
// Amount of time to wait after a connection succeeds (or packet sent) for a responses.
|
||||||
int totalwaitms;
|
int totalwaitms;
|
||||||
|
// If the connection succeeds but closes before this time, it's tcpwrapped.
|
||||||
|
int tcpwrappedms;
|
||||||
|
|
||||||
// Parses the "probe " line in the nmap-service-probes file. Pass the rest of the line
|
// Parses the "probe " line in the nmap-service-probes file. Pass the rest of the line
|
||||||
// after "probe ". The format better be:
|
// after "probe ". The format better be:
|
||||||
|
|||||||
Reference in New Issue
Block a user