Skip to content

Commit

Permalink
Update nmap-os-db syntax to support nested ranges
Browse files Browse the repository at this point in the history
  • Loading branch information
bonsaiviking committed Nov 27, 2023
1 parent 71d7602 commit b839872
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 18 deletions.
1 change: 1 addition & 0 deletions nmap-os-db
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#
# For a complete description of Nmap OS detection and the format of
# fingerprints in this file, see https://nmap.org/book/osdetect.html.
This nmap-os-db is only valid for Nmap 7.94.2 and later

# This first element provides the number of points every fingerprint
# test is worth. Tests like TTL or Don't fragment are worth less
Expand Down
2 changes: 1 addition & 1 deletion nmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@
file by the makefiles. */
#define NMAP_MAJOR 7
#define NMAP_MINOR 94
#define NMAP_BUILD 1
#define NMAP_BUILD 2
/* SVN, BETA, etc. */
#define NMAP_SPECIAL "SVN"

Expand Down
96 changes: 81 additions & 15 deletions osscan.cc
Original file line number Diff line number Diff line change
Expand Up @@ -292,43 +292,99 @@ void FingerPrint::erase() {
| (or)
- (range)
No parentheses are allowed. */
bool expr_match(const char *val, size_t vlenx, const char *expr, size_t explen, bool do_nested) {
bool expr_match(const char *val, size_t vlen, const char *expr, size_t explen, bool do_nested) {
const char *p, *q, *q1; /* OHHHH YEEEAAAAAHHHH!#!@#$!% */
size_t vlen = strlen(val);
if (vlen == 0)
vlen = strlen(val);
if (explen == 0)
explen = strlen(expr);

// If both are empty, match; else if either is empty, no match.
if (vlen == 0) {
return explen == 0;
}
else if (explen == 0) {
return vlen == 0;
}

p = expr;

do {
const char *nest = NULL; // where the [] nested expr starts
const char *subval = val; // portion of val after previous nest and before the next one
size_t sublen; // length of subval not subject to nested matching
q = strchr(p, '|');
size_t explen = q ? q - p : strlen(p);

// if we're already in a nested expr, we skip this and just match as usual.
if (do_nested) {
nest = strchr(p, '[');
subval = val;
// As long as we keep finding nested portions, e.g. M[>500]ST11W[1-5]
while (nest) {
q1 = strchr(nest, ']');
assert(q1);
if (q && q < q1) {
// "AB[C|D]E|XYZ"
q = strchr(q1, '|');
}
// "AB[C-D]E" or or "AB[C-D]E|F"
sublen = nest - p;
if (strncmp(p, subval, sublen) != 0) {
goto next_expr;
}
nest++;
subval += sublen;
size_t nlen = 0;
while (isxdigit(subval[nlen])) {
nlen++;
}
p = q1 + 1;
// fprintf(stderr, "nest: %-.*s cmp %-.*s\n", nlen, subval, q1 - nest, nest);
if (nlen > 0 && expr_match(subval, nlen, nest, q1 - nest, false)) {
subval += nlen;
nest = strchr(p, '[');
}
else {
goto next_expr;
}
}
// No more nested portions. string match the rest:
sublen = vlen - (subval - val);
if ((explen - (p - expr)) == sublen && !strncmp(subval, p, sublen)) {
return true;
}
}
sublen = q ? q - p : explen - (p - expr);
if (*p == '>') {
if ((vlen > explen - 1)
|| (vlen == explen - 1 && strncmp(val, p + 1, vlen) > 0)) {
if ((vlen > sublen - 1)
|| (vlen == sublen - 1 && strncmp(subval, p + 1, vlen) > 0)) {
return true;
}
}
else if (*p == '<') {
if ((vlen < explen - 1)
|| (vlen == explen - 1 && strncmp(val, p + 1, vlen) < 0)) {
if ((vlen < sublen - 1)
|| (vlen == sublen - 1 && strncmp(subval, p + 1, vlen) < 0)) {
return true;
}
} else {
q1 = strchr(p, '-');
if (q1 != NULL) {
size_t explen1 = q1 - p;
if ((vlen > explen1)
|| (vlen == explen1 && strncmp(val, p + 1, vlen) >= 0)) {
explen -= (explen1 + 1);
if ((vlen < explen)
|| (vlen == explen && strncmp(val, p + 1, vlen) <= 0)) {
size_t sublen1 = q1 - p;
if ((vlen > sublen1)
|| (vlen == sublen1 && strncmp(subval, p, vlen) >= 0)) {
p = q1 + 1;
sublen -= (sublen1 + 1);
if ((vlen < sublen)
|| (vlen == sublen && strncmp(subval, p, vlen) <= 0)) {
return true;
}
}
}
else if (vlen == explen && !strncmp(p, val, vlen)) {
else if (vlen == sublen && !strncmp(p, subval, vlen)) {
return true;
}
}
next_expr:
if (q)
p = q + 1;
} while (q);
Expand All @@ -348,6 +404,7 @@ static void AVal_match(const FingerTest &reference, const FingerTest &fprint, co
return;

const std::vector<Attr> &pointsV = points.Attrs;
bool tcp_opt_match = points.name == "OPS";

const std::vector<const char *> &refV = *reference.results;
assert(refV.size() == points.numAttrs);
Expand All @@ -366,7 +423,7 @@ static void AVal_match(const FingerTest &reference, const FingerTest &fprint, co
fatal("%s: Got bogus point amount (%d) for test %s.%s", __func__, pointsThisTest, points.name.str, aDef.name.str);
subtests += pointsThisTest;

if (expr_match(current_fp, 0, current_ref, 0)) {
if (expr_match(current_fp, 0, current_ref, 0, tcp_opt_match || aDef.name == "O")) {
subtests_succeeded += pointsThisTest;
} else {
if (verbose)
Expand Down Expand Up @@ -1072,6 +1129,15 @@ FingerPrintDB *parse_fingerprint_file(const char *fname, bool points_only) {
if (DB->MatchPoints)
fatal("Found MatchPoints directive on line %d of %s even though it has previously been seen in the file", lineno, fname);
parsingMatchPoints = true;
} else if (strncmp(line, "This nmap-os-db", 15) == 0) {
p = strstr(line, "Nmap ");
if (!p)
fatal("Parse error on line %d of nmap-os-db file: %s", lineno, line);
q = strchr(p + 5, ' ');
if (strncmp(p + 5, NMAP_NUM_VERSION, q - p) > 0) {
error("%sOS detection results may be inaccurate.", line);
}
continue;
} else {
error("Parse error on line %d of nmap-os-db file: %s", lineno, line);
continue;
Expand Down
2 changes: 0 additions & 2 deletions tests/expr_match_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ const struct expr_test tests[] = {
{"<A", "", false},
{">A", "", false},
{"1-9", "", false},
#if 0
{"M[1-9]", "M2", true},
{"M[<5]S", "M2S", true},
{"M[>A]S", "MFS", true},
Expand Down Expand Up @@ -116,7 +115,6 @@ const struct expr_test tests[] = {
{"[<5]S", "2B", false},
{"[>A7]S", "FS", false},
{"[>A7]S", "A6S", false},
#endif
{"", "", true}
};

Expand Down

0 comments on commit b839872

Please sign in to comment.