📄 service_scan.cc
字号:
void ServiceNFO::addToServiceFingerprint(const char *probeName, const u8 *resp, int resplen) { int spaceleft = servicefpalloc - servicefplen; int servicewrap=74; // Wrap after 74 chars / line int respused = MIN(resplen, (o.debugging)? 1300 : 900); // truncate to reasonable size // every char could require \xHH escape, plus there is the matter of // "\nSF:" for each line, plus "%r(probename,probelen,"") Oh, and // the SF-PortXXXX-TCP stuff, etc int spaceneeded = respused * 5 + strlen(probeName) + 128; int srcidx; struct tm *ltime; time_t timep; char buf[128]; int len; assert(resplen); assert(probeName); if (servicefplen > (o.debugging? 10000 : 2200)) return; // it is large enough. if (spaceneeded >= spaceleft) { spaceneeded = MAX(spaceneeded, 512); // No point in tiny allocations spaceneeded += servicefpalloc; servicefp = (char *) safe_realloc(servicefp, spaceneeded); servicefpalloc = spaceneeded; } spaceleft = servicefpalloc - servicefplen; if (servicefplen == 0) { timep = time(NULL); ltime = localtime(&timep); servicefplen = Snprintf(servicefp, spaceleft, "SF-Port%hu-%s:V=%s%s%%I=%d%%D=%d/%d%%Time=%X%%P=%s", portno, proto2ascii(proto, true), NMAP_VERSION, (tunnel == SERVICE_TUNNEL_SSL)? "%T=SSL" : "", o.version_intensity, ltime->tm_mon + 1, ltime->tm_mday, (int) timep, NMAP_PLATFORM); } // Note that we give the total length of the response, even though we // may truncate len = Snprintf(buf, sizeof(buf), "%%r(%s,%X,\"", probeName, resplen); addServiceString(buf, servicewrap); // Now for the probe response itself ... for(srcidx=0; srcidx < respused; srcidx++) { // A run of this can take up to 8 chars: "\n \x20" assert( servicefpalloc - servicefplen > 8); if (isalnum((int)resp[srcidx])) addServiceChar((char) resp[srcidx], servicewrap); else if (resp[srcidx] == '\0') { /* We need to be careful with this, because if it is followed by an ASCII number, PCRE will treat it differently. */ if (srcidx + 1 >= respused || !isdigit(resp[srcidx + 1])) addServiceString("\\0", servicewrap); else addServiceString("\\x00", servicewrap); } else if (strchr("\\?\"[]().*+$^|", resp[srcidx])) { addServiceChar('\\', servicewrap); addServiceChar(resp[srcidx], servicewrap); } else if (ispunct((int)resp[srcidx])) { addServiceChar((char) resp[srcidx], servicewrap); } else if (resp[srcidx] == '\r') { addServiceString("\\r", servicewrap); } else if (resp[srcidx] == '\n') { addServiceString("\\n", servicewrap); } else if (resp[srcidx] == '\t') { addServiceString("\\t", servicewrap); } else { addServiceChar('\\', servicewrap); addServiceChar('x', servicewrap); Snprintf(buf, sizeof(buf), "%02x", resp[srcidx]); addServiceChar(*buf, servicewrap); addServiceChar(*(buf+1), servicewrap); } } addServiceChar('"', servicewrap); addServiceChar(')', servicewrap); assert(servicefpalloc - servicefplen > 1); servicefp[servicefplen] = '\0';}// Get the service fingerprint. It is NULL if there is none, such// as if there was a match before any other probes were finished (or// if no probes gave back data). Note that this is plain// NUL-terminated ASCII data, although the length is optionally// available anyway. This function terminates the service fingerprint// with a semi-colonconst char *ServiceNFO::getServiceFingerprint(int *flen) { if (servicefplen == 0) { if (flen) *flen = 0; return NULL; } // Ensure we have enough space for the terminating semi-colon and \0 if (servicefplen + 2 > servicefpalloc) { servicefpalloc = servicefplen + 20; servicefp = (char *) safe_realloc(servicefp, servicefpalloc); } if (flen) *flen = servicefplen + 1; // We terminate with a semi-colon, which is never wrapped. servicefp[servicefplen] = ';'; servicefp[servicefplen + 1] = '\0'; return servicefp;}ServiceProbe *ServiceNFO::currentProbe() { if (probe_state == PROBESTATE_INITIAL) { return nextProbe(true); } else if (probe_state == PROBESTATE_NULLPROBE) { assert(AP->nullProbe); return AP->nullProbe; } else if (probe_state == PROBESTATE_MATCHINGPROBES || probe_state == PROBESTATE_NONMATCHINGPROBES) { return *current_probe; } return NULL;}// computes the next probe to test, and ALSO CHANGES currentProbe() to// that! If newresp is true, the old response info will be lost and// invalidated. Otherwise it remains as if it had been received by// the current probe (useful after a NULL probe).ServiceProbe *ServiceNFO::nextProbe(bool newresp) {bool dropdown = false;// This invalidates the probe response string if any if (newresp) { if (currentresp) free(currentresp); currentresp = NULL; currentresplen = 0; } if (probe_state == PROBESTATE_INITIAL) { probe_state = PROBESTATE_NULLPROBE; // This is the very first probe -- so we try to use the NULL probe // but obviously NULL probe only works with TCP if (proto == IPPROTO_TCP && AP->nullProbe) return AP->nullProbe; // No valid NULL probe -- we'll drop to the next state } if (probe_state == PROBESTATE_NULLPROBE) { // There can only be one (or zero) NULL probe. So now we go through the // list looking for matching probes probe_state = PROBESTATE_MATCHINGPROBES; dropdown = true; current_probe = AP->probes.begin(); } if (probe_state == PROBESTATE_MATCHINGPROBES) { if (!dropdown && current_probe != AP->probes.end()) current_probe++; while (current_probe != AP->probes.end()) { // For the first run, we only do probes that match this port number if ((proto == (*current_probe)->getProbeProtocol()) && (*current_probe)->portIsProbable(tunnel, portno)) { // This appears to be a valid probe. Let's do it! return *current_probe; } current_probe++; } // Tried all MATCHINGPROBES -- now we must move to nonmatching probe_state = PROBESTATE_NONMATCHINGPROBES; dropdown = true; current_probe = AP->probes.begin(); } if (probe_state == PROBESTATE_NONMATCHINGPROBES) { if (!dropdown && current_probe != AP->probes.end()) current_probe++; while (current_probe != AP->probes.end()) { // The protocol must be right, it must be a nonmatching port ('cause we did those), // and we better either have no soft match yet, or the soft service match must // be available via this probe. Also, the Probe's rarity must be <= to our // version detection intensity level. if ((proto == (*current_probe)->getProbeProtocol()) && !(*current_probe)->portIsProbable(tunnel, portno) && (*current_probe)->getRarity() <= o.version_intensity && (!softMatchFound || (*current_probe)->serviceIsPossible(probe_matched))) { // Valid, probe. Let's do it! return *current_probe; } current_probe++; } // Tried all NONMATCHINGPROBES -- we're finished probe_state = (softMatchFound)? PROBESTATE_FINISHED_SOFTMATCHED : PROBESTATE_FINISHED_NOMATCH; return NULL; } fatal("%s called for probe in state (%d)", __func__, (int) probe_state); return NULL;} // Resets the probes back to the first one. One case where this is useful is // when SSL is detected -- we redo all probes through SSL. If freeFP, any // service fingerprint is freed too.void ServiceNFO::resetProbes(bool freefp) { if (currentresp) free(currentresp); if (freefp) { if (servicefp) { free(servicefp); servicefp = NULL; } servicefplen = servicefpalloc = 0; } currentresp = NULL; currentresplen = 0; probe_state = PROBESTATE_INITIAL;}int ServiceNFO::currentprobe_timemsleft(const struct timeval *now) { int timeused, timeleft; if (now) timeused = TIMEVAL_MSEC_SUBTRACT(*now, currentprobe_exec_time); else { struct timeval tv; gettimeofday(&tv, NULL); timeused = TIMEVAL_MSEC_SUBTRACT(tv, currentprobe_exec_time); } timeleft = currentProbe()->totalwaitms - timeused; return (timeleft < 0)? 0 : timeleft;}void ServiceNFO::appendtocurrentproberesponse(const u8 *respstr, int respstrlen) { currentresp = (u8 *) safe_realloc(currentresp, currentresplen + respstrlen); memcpy(currentresp + currentresplen, respstr, respstrlen); currentresplen += respstrlen;}// Get the full current response string. Note that this pointer is // INVALIDATED if you call appendtocurrentproberesponse() or nextProbe()u8 *ServiceNFO::getcurrentproberesponse(int *respstrlen) { *respstrlen = currentresplen; return currentresp;}ServiceGroup::ServiceGroup(vector<Target *> &Targets, AllProbes *AP) { unsigned int targetno; ServiceNFO *svc; Port *nxtport; int desired_par; struct timeval now; num_hosts_timedout = 0; gettimeofday(&now, NULL); for(targetno = 0 ; targetno < Targets.size(); targetno++) { nxtport = NULL; if (Targets[targetno]->timedOut(&now)) { num_hosts_timedout++; continue; } while((nxtport = Targets[targetno]->ports.nextPort(nxtport, TCPANDUDP, PORT_OPEN))) { svc = new ServiceNFO(AP); svc->target = Targets[targetno]; svc->portno = nxtport->portno; svc->proto = nxtport->proto; svc->port = nxtport; services_remaining.push_back(svc); } } /* Use a whole new loop for PORT_OPENFILTERED so that we try all the known open ports first before bothering with this speculative stuff */ for(targetno = 0 ; targetno < Targets.size(); targetno++) { nxtport = NULL; if (Targets[targetno]->timedOut(&now)) { continue; } while((nxtport = Targets[targetno]->ports.nextPort(nxtport, TCPANDUDP, PORT_OPENFILTERED))) { svc = new ServiceNFO(AP); svc->target = Targets[targetno]; svc->portno = nxtport->portno; svc->proto = nxtport->proto; svc->port = nxtport; services_remaining.push_back(svc); } } SPM = new ScanProgressMeter("Service scan"); desired_par = 1; if (o.timing_level == 3) desired_par = 10; if (o.timing_level == 4) desired_par = 15; if (o.timing_level >= 5) desired_par = 20; // TODO: Come up with better ways to determine ideal_services ideal_parallelism = box(o.min_parallelism, o.max_parallelism? o.max_parallelism : 100, desired_par);}ServiceGroup::~ServiceGroup() { list<ServiceNFO *>::iterator i; for(i = services_finished.begin(); i != services_finished.end(); i++) delete *i; for(i = services_in_progress.begin(); i != services_in_progress.end(); i++) delete *i; for(i = services_remaining.begin(); i != services_remaining.end(); i++) delete *i; delete SPM;}/* Called if data is read for a service or a TCP connection made. If the port state is currently PORT_UNFILTERED, changes to PORT_OPEN. */static void adjustPortStateIfNeccessary(ServiceNFO *svc) { char host[128]; if (svc->port->state == PORT_OPENFILTERED) { svc->target->ports.addPort(svc->portno, svc->proto, NULL, PORT_OPEN); if (svc->proto == IPPROTO_TCP) svc->target->ports.setStateReason(svc->portno, svc->proto, ER_TCPRESPONSE, 0, 0); if (svc->proto == IPPROTO_UDP) svc->target->ports.setStateReason(svc->portno, svc->proto, ER_UDPRESPONSE, 0, 0); if (o.verbose || o.debugging > 1) { svc->target->NameIP(host, sizeof(host)); log_write(LOG_STDOUT, "Discovered open|filtered port %hu/%s on %s is actually open\n", svc->portno, proto2ascii(svc->proto), host); log_flush(LOG_STDOUT); } } return;} // Sends probe text to an open connection. In the case of a NULL probe, there // may be no probe text static int send_probe_text(nsock_pool nsp, nsock_iod nsi, ServiceNFO *svc, ServiceProbe *probe) { const u8 *probestring; int probestringlen; assert(probe);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -