📄 service_scan.cc
字号:
// This function takes a template string (tmpl) which can have// placeholders in it such as $1 for substring matches in a regexp// that was run against subject, and subjectlen, with the 'nummatches'// matches in ovector. The NUL-terminated newly composted string is// placed into 'newstr', as long as it doesn't exceed 'newstrlen'// bytes. Trailing whitespace and commas are removed. Returns zero for successstatic int dotmplsubst(const u8 *subject, int subjectlen, int *ovector, int nummatches, char *tmpl, char *newstr, int newstrlen) { int newlen; char *srcstart=tmpl, *srcend; char *dst = newstr; char *newstrend = newstr + newstrlen; // Right after the final char if (!newstr || !tmpl) return -1; if (newstrlen < 3) return -1; // fuck this! while(*srcstart) { // First do any literal text before '$' srcend = strchr(srcstart, '$'); if (!srcend) { // Only literal text remain! while(*srcstart) { if (dst >= newstrend - 1) return -1; *dst++ = *srcstart++; } *dst = '\0'; while (--dst >= newstr) { if (isspace(*dst) || *dst == ',') *dst = '\0'; else break; } return 0; } else { // Copy the literal text up to the '$', then do the substitution newlen = srcend - srcstart; if (newlen > 0) { if (newstrend - dst <= newlen - 1) return -1; memcpy(dst, srcstart, newlen); dst += newlen; } srcstart = srcend; newlen = substvar(srcstart, &srcend, dst, newstrend - dst, subject, subjectlen, ovector, nummatches); if (newlen == -1) return -1; dst += newlen; srcstart = srcend; } } if (dst >= newstrend - 1) return -1; *dst = '\0'; while (--dst >= newstr) { if (isspace(*dst) || *dst == ',') *dst = '\0'; else break; } return 0;}// Use the six version templates and the match data included here// to put the version info into the given strings, (as long as the sizes// are sufficient). Returns zero for success. If no template is available// for a string, that string will have zero length after the function// call (assuming the corresponding length passed in is at least 1)int ServiceProbeMatch::getVersionStr(const u8 *subject, int subjectlen, int *ovector, int nummatches, char *product, int productlen, char *version, int versionlen, char *info, int infolen, char *hostname, int hostnamelen, char *ostype, int ostypelen, char *devicetype, int devicetypelen) { int rc; assert(productlen >= 0 && versionlen >= 0 && infolen >= 0 && hostnamelen >= 0 && ostypelen >= 0 && devicetypelen >= 0); if (productlen > 0) *product = '\0'; if (versionlen > 0) *version = '\0'; if (infolen > 0) *info = '\0'; if (hostnamelen > 0) *hostname = '\0'; if (ostypelen > 0) *ostype = '\0'; if (devicetypelen > 0) *devicetype = '\0'; int retval = 0; // Now lets get this started! We begin with the product name if (product_template) { rc = dotmplsubst(subject, subjectlen, ovector, nummatches, product_template, product, productlen); if (rc != 0) { error("Warning: Servicescan failed to fill product_template (subjectlen: %d). Too long? Match string was line %d: v/%s/%s/%s", subjectlen, deflineno, (product_template)? product_template : "", (version_template)? version_template : "", (info_template)? info_template : ""); if (productlen > 0) *product = '\0'; retval = -1; } } if (version_template) { rc = dotmplsubst(subject, subjectlen, ovector, nummatches, version_template, version, versionlen); if (rc != 0) { error("Warning: Servicescan failed to fill version_template (subjectlen: %d). Too long? Match string was line %d: v/%s/%s/%s", subjectlen, deflineno, (product_template)? product_template : "", (version_template)? version_template : "", (info_template)? info_template : ""); if (versionlen > 0) *version = '\0'; retval = -1; } } if (info_template) { rc = dotmplsubst(subject, subjectlen, ovector, nummatches, info_template, info, infolen); if (rc != 0) { error("Warning: Servicescan failed to fill info_template (subjectlen: %d). Too long? Match string was line %d: v/%s/%s/%s", subjectlen, deflineno, (product_template)? product_template : "", (version_template)? version_template : "", (info_template)? info_template : ""); if (infolen > 0) *info = '\0'; retval = -1; } } if (hostname_template) { rc = dotmplsubst(subject, subjectlen, ovector, nummatches, hostname_template, hostname, hostnamelen); if (rc != 0) { error("Warning: Servicescan failed to fill hostname_template (subjectlen: %d). Too long? Match string was line %d: h/%s/", subjectlen, deflineno, (hostname_template)? hostname_template : ""); if (hostnamelen > 0) *hostname = '\0'; retval = -1; } } if (ostype_template) { rc = dotmplsubst(subject, subjectlen, ovector, nummatches, ostype_template, ostype, ostypelen); if (rc != 0) { error("Warning: Servicescan failed to fill ostype_template (subjectlen: %d). Too long? Match string was line %d: p/%s/", subjectlen, deflineno, (ostype_template)? ostype_template : ""); if (ostypelen > 0) *ostype = '\0'; retval = -1; } } if (devicetype_template) { rc = dotmplsubst(subject, subjectlen, ovector, nummatches, devicetype_template, devicetype, devicetypelen); if (rc != 0) { error("Warning: Servicescan failed to fill devicetype_template (subjectlen: %d). Too long? Match string was line %d: d/%s/", subjectlen, deflineno, (devicetype_template)? devicetype_template : ""); if (devicetypelen > 0) *devicetype = '\0'; retval = -1; } } return retval;}ServiceProbe::ServiceProbe() { int i; probename = NULL; probestring = NULL; totalwaitms = DEFAULT_SERVICEWAITMS; probestringlen = 0; probeprotocol = -1; // The default rarity level for a probe without a rarity // directive - should almost never have to be relied upon. rarity = 5; fallbackStr = NULL; for (i=0; i<MAXFALLBACKS+1; i++) fallbacks[i] = NULL;}ServiceProbe::~ServiceProbe() { vector<ServiceProbeMatch *>::iterator vi; if (probename) free(probename); if (probestring) free(probestring); for(vi = matches.begin(); vi != matches.end(); vi++) { delete *vi; } if (fallbackStr) free(fallbackStr);} // Parses the "probe " line in the nmap-service-probes file. Pass the rest of the line // after "probe ". The format better be: // [TCP|UDP] [probename] q|probetext| // Note that the delimiter (|) of the probetext can be anything (within reason) // the lineno is requested because this function will bail with an error // (giving the line number) if it fails to parse the string.void ServiceProbe::setProbeDetails(char *pd, int lineno) { char *p; unsigned int len; char delimiter; if (!pd || !*pd) fatal("Parse error on line %d of nmap-service-probes: no arguments found!", lineno); // First the protocol if (strncmp(pd, "TCP ", 4) == 0) probeprotocol = IPPROTO_TCP; else if (strncmp(pd, "UDP ", 4) == 0) probeprotocol = IPPROTO_UDP; else fatal("Parse error on line %d of nmap-service-probes: invalid protocol", lineno); pd += 4; // Next the service name if (!isalnum(*pd)) fatal("Parse error on line %d of nmap-service-probes - bad probe name", lineno); p = strchr(pd, ' '); if (!p) fatal("Parse error on line %d of nmap-service-probes - nothing after probe name", lineno); len = p - pd; probename = (char *) safe_malloc(len + 1); memcpy(probename, pd, len); probename[len] = '\0'; // Now for the probe itself pd = p+1; if (*pd != 'q') fatal("Parse error on line %d of nmap-service-probes - probe string must begin with 'q'", lineno); delimiter = *(++pd); p = strchr(++pd, delimiter); if (!p) fatal("Parse error on line %d of nmap-service-probes -- no ending delimiter for probe string", lineno); *p = '\0'; if (!cstring_unescape(pd, &len)) { fatal("Parse error on line %d of nmap-service-probes: bad probe string escaping", lineno); } setProbeString((const u8 *)pd, len);}void ServiceProbe::setProbeString(const u8 *ps, int stringlen) { if (probestringlen) free(probestring); probestringlen = stringlen; if (stringlen > 0) { probestring = (u8 *) safe_malloc(stringlen + 1); memcpy(probestring, ps, stringlen); probestring[stringlen] = '\0'; // but note that other \0 may be in string } else probestring = NULL;}void ServiceProbe::setPortVector(vector<u16> *portv, const char *portstr, int lineno) { const char *current_range; char *endptr; long int rangestart = 0, rangeend = 0; current_range = portstr; do { while(*current_range && isspace(*current_range)) current_range++; if (isdigit((int) *current_range)) { rangestart = strtol(current_range, &endptr, 10); if (rangestart < 0 || rangestart > 65535) { fatal("Parse error on line %d of nmap-service-probes: Ports must be between 0 and 65535 inclusive", lineno); } current_range = endptr; while(isspace((int) *current_range)) current_range++; } else { fatal("Parse error on line %d of nmap-service-probes: An example of proper portlist form is \"21-25,53,80\"", lineno); } /* Now I have a rangestart, time to go after rangeend */ if (!*current_range || *current_range == ',') { /* Single port specification */ rangeend = rangestart; } else if (*current_range == '-') { current_range++; if (isdigit((int) *current_range)) { rangeend = strtol(current_range, &endptr, 10); if (rangeend < 0 || rangeend > 65535 || rangeend < rangestart) { fatal("Parse error on line %d of nmap-service-probes: Ports must be between 0 and 65535 inclusive", lineno); } current_range = endptr; } else { fatal("Parse error on line %d of nmap-service-probes: An example of proper portlist form is \"21-25,53,80\"", lineno); } } else { fatal("Parse error on line %d of nmap-service-probes: An example of proper portlist form is \"21-25,53,80\"", lineno); } /* Now I have a rangestart and a rangeend, so I can add these ports */ while(rangestart <= rangeend) { portv->push_back(rangestart); rangestart++; } /* Find the next range */ while(isspace((int) *current_range)) current_range++; if (*current_range && *current_range != ',') { fatal("Parse error on line %d of nmap-service-probes: An example of proper portlist form is \"21-25,53,80\"", lineno); } if (*current_range == ',') current_range++; } while(current_range && *current_range);} // Takes a string as given in the 'ports '/'sslports ' line of // nmap-service-probes. Pass in the list from the appropriate // line. For 'sslports', tunnel should be specified as // SERVICE_TUNNEL_SSL. Otherwise use SERVICE_TUNNEL_NONE. The line // number is requested because this function will bail with an error // (giving the line number) if it fails to parse the string. Ports // are a comma separated list of ports and ranges // (e.g. 53,80,6000-6010).void ServiceProbe::setProbablePorts(enum service_tunnel_type tunnel, const char *portstr, int lineno) { if (tunnel == SERVICE_TUNNEL_NONE) setPortVector(&probableports, portstr, lineno); else { assert(tunnel == SERVICE_TUNNEL_SSL); setPortVector(&probablesslports, portstr, lineno); }} /* Returns true if the passed in port is on the list of probable ports for this probe and tunnel type. Use a tunnel of SERVICE_TUNNEL_SSL or SERVICE_TUNNEL_NONE as appropriate */bool ServiceProbe::portIsProbable(enum service_tunnel_type tunnel, u16 portno) { vector<u16> *portv; portv = (tunnel == SERVICE_TUNNEL_SSL)? &probablesslports : &probableports; if (find(portv->begin(), portv->end(), portno) == portv->end()) return false; return true;} // Returns true if the passed in service name is among those that can // be detected by the matches in this probe;bool ServiceProbe::serviceIsPossible(const char *sname) { vector<const char *>::iterator vi; for(vi = detectedServices.begin(); vi != detectedServices.end(); vi++) { if (strcmp(*vi, sname) == 0) return true; } return false;}// Takes a string following a Rarity directive in the probes file.// The string should contain a single integer between 1 and 9. The// default rarity is 5. This function will bail if the string is invalid.void ServiceProbe::setRarity(const char *portstr, int lineno) { int tp; tp = atoi(portstr); if (tp < 1 || tp > 9) fatal("%s: Rarity directive on line %d of nmap-service-probes must be between 1 and 9", __func__, lineno);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -