Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop Nmap scan and preserve XML output #243 #316

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions NmapOps.cc
Expand Up @@ -388,6 +388,7 @@ void NmapOps::Initialize() {
portlist = NULL;
exclude_portlist = NULL;
proxy_chain = NULL;
resuming = false;
}

bool NmapOps::SCTPScan() {
Expand Down
1 change: 1 addition & 0 deletions NmapOps.h
Expand Up @@ -181,6 +181,7 @@ class NmapOps {
/* Whether we have pcap functions (can be false on Windows). */
bool have_pcap;
int debugging;
bool resuming;

#define PACKET_SEND_NOPREF 1
#define PACKET_SEND_ETH_WEAK 2
Expand Down
1 change: 1 addition & 0 deletions main.cc
Expand Up @@ -222,6 +222,7 @@ int main(int argc, char *argv[]) {
if (gather_logfile_resumption_state(argv[2], &myargc, &myargv) == -1) {
fatal("Cannot resume from (supposed) log file %s", argv[2]);
}
o.resuming = true;
return nmap_main(myargc, myargv);
}

Expand Down
146 changes: 87 additions & 59 deletions nmap.cc
Expand Up @@ -1816,18 +1816,48 @@ int nmap_main(int argc, char *argv[]) {
fflush(stderr);

timep = time(NULL);

/* Brief info in case they forget what was scanned */
Strncpy(mytime, ctime(&timep), sizeof(mytime));
chomp(mytime);
char *xslfname = o.XSLStyleSheet();
xml_start_document("nmaprun");
if (xslfname) {
xml_open_pi("xml-stylesheet");
xml_attribute("href", "%s", xslfname);
xml_attribute("type", "text/xsl");
xml_close_pi();

if (!o.resuming) {
/* Brief info in case they forget what was scanned */
char *xslfname = o.XSLStyleSheet();
xml_start_document("nmaprun");
if (xslfname) {
xml_open_pi("xml-stylesheet");
xml_attribute("href", "%s", xslfname);
xml_attribute("type", "text/xsl");
xml_close_pi();
xml_newline();
}

xml_start_comment();
xml_write_escaped(" %s %s scan initiated %s as: %s ", NMAP_NAME, NMAP_VERSION, mytime, join_quoted(argv, argc).c_str());
xml_end_comment();
xml_newline();

xml_open_start_tag("nmaprun");
xml_attribute("scanner", "nmap");
xml_attribute("args", "%s", join_quoted(argv, argc).c_str());
xml_attribute("start", "%lu", (unsigned long) timep);
xml_attribute("startstr", "%s", mytime);
xml_attribute("version", "%s", NMAP_VERSION);
xml_attribute("xmloutputversion", NMAP_XMLOUTPUTVERSION);
xml_close_start_tag();
xml_newline();

output_xml_scaninfo_records(&ports);

xml_open_start_tag("verbose");
xml_attribute("level", "%d", o.verbose);
xml_close_empty_tag();
xml_newline();
xml_open_start_tag("debugging");
xml_attribute("level", "%d", o.debugging);
xml_close_empty_tag();
xml_newline();
} else {
xml_start_tag("nmaprun", false);
}

std::string command;
Expand All @@ -1838,37 +1868,11 @@ int nmap_main(int argc, char *argv[]) {
command += argv[i];
}

xml_start_comment();
xml_write_escaped(" %s %s scan initiated %s as: %s ", NMAP_NAME, NMAP_VERSION, mytime, join_quoted(argv, argc).c_str());
xml_end_comment();
xml_newline();

log_write(LOG_NORMAL | LOG_MACHINE, "# ");
log_write(LOG_NORMAL | LOG_MACHINE, "%s %s scan initiated %s as: ", NMAP_NAME, NMAP_VERSION, mytime);
log_write(LOG_NORMAL | LOG_MACHINE, "%s", command.c_str());
log_write(LOG_NORMAL | LOG_MACHINE, "\n");

xml_open_start_tag("nmaprun");
xml_attribute("scanner", "nmap");
xml_attribute("args", "%s", join_quoted(argv, argc).c_str());
xml_attribute("start", "%lu", (unsigned long) timep);
xml_attribute("startstr", "%s", mytime);
xml_attribute("version", "%s", NMAP_VERSION);
xml_attribute("xmloutputversion", NMAP_XMLOUTPUTVERSION);
xml_close_start_tag();
xml_newline();

output_xml_scaninfo_records(&ports);

xml_open_start_tag("verbose");
xml_attribute("level", "%d", o.verbose);
xml_close_empty_tag();
xml_newline();
xml_open_start_tag("debugging");
xml_attribute("level", "%d", o.debugging);
xml_close_empty_tag();
xml_newline();

/* Before we randomize the ports scanned, lets output them to machine
parseable output */
if (o.verbose)
Expand Down Expand Up @@ -2331,13 +2335,22 @@ int gather_logfile_resumption_state(char *fname, int *myargc, char ***myargv) {
if (!q || ((unsigned int) (q - p) >= sizeof(nmap_arg_buffer) - 32))
fatal("Unable to parse supposed log file %s. Perhaps the Nmap execution had not finished at least one host? In that case there is no use \"resuming\"", fname);


strncpy(nmap_arg_buffer, "nmap --append-output ", sizeof(nmap_arg_buffer));
if ((q - p) + 21 + 1 >= (int) sizeof(nmap_arg_buffer))
fatal("0verfl0w");
memcpy(nmap_arg_buffer + 21, p, q - p);
nmap_arg_buffer[21 + q - p] = '\0';

q = strstr(nmap_arg_buffer, "-->");
if (q) {
*q = '\0';
char *unescaped = xml_unescape(nmap_arg_buffer);
if (sizeof(nmap_arg_buffer) < strlen(unescaped) + 1)
fatal("0verfl0w");
memcpy(nmap_arg_buffer, unescaped, strlen(unescaped) + 1);
free(unescaped);
}

if (strstr(nmap_arg_buffer, "--randomize-hosts") != NULL) {
error("WARNING: You are attempting to resume a scan which used --randomize-hosts. Some hosts in the last randomized batch may be missed and others may be repeated once");
}
Expand All @@ -2363,37 +2376,52 @@ int gather_logfile_resumption_state(char *fname, int *myargc, char ***myargv) {
fatal("Unable to parse supposed log file %s. Sorry", fname);
*q = ' ';
} else {
/* OK, I guess (hope) it is a normal log then (-oN) */
/* Let's see if it's an XML log (-oX) */
q = p;
found = NULL;
while ((q = strstr(q, "\nNmap scan report for ")))
found = q = q + 22;

/* There may be some later IPs of the form :
"Nmap scan report for florence (x.x.7.10)" (dns reverse lookup)
or "Nmap scan report for x.x.7.10".
*/
while ((q = strstr(q, "\n<address addr=\"")))
found = q = q + 16;
if (found) {
q = strchr(found, '\n');
q = strchr(found, '"');
if (!q)
fatal("Unable to parse supposed log file %s. Sorry", fname);
*q = '\0';
p = strchr(found, '(');
if (!p) { /* No DNS reverse lookup, found should already contain IP */
lastipstr = strdup(found);
} else { /* DNS reverse lookup, IP is between parentheses */
*q = '\n';
q--;
if (inet_pton(AF_INET, found, &lastip) == 0)
fatal("Unable to parse supposed log file %s. Sorry", fname);
*q = '"';
} else {
/* OK, I guess (hope) it is a normal log then (-oN) */
q = p;
found = NULL;
while ((q = strstr(q, "\nNmap scan report for ")))
found = q = q + 22;

/* There may be some later IPs of the form :
"Nmap scan report for florence (x.x.7.10)" (dns reverse lookup)
or "Nmap scan report for x.x.7.10".
*/
if (found) {
q = strchr(found, '\n');
if (!q)
fatal("Unable to parse supposed log file %s. Sorry", fname);
*q = '\0';
lastipstr = strdup(p + 1);
p = strchr(found, '(');
if (!p) { /* No DNS reverse lookup, found should already contain IP */
lastipstr = strdup(found);
} else { /* DNS reverse lookup, IP is between parentheses */
*q = '\n';
q--;
*q = '\0';
lastipstr = strdup(p + 1);
}
*q = p ? ')' : '\n'; /* recover changed chars */
if (inet_pton(AF_INET, lastipstr, &lastip) == 0)
fatal("Unable to parse ip (%s) in supposed log file %s. Sorry", lastipstr, fname);
free(lastipstr);
} else {
error("Warning: You asked for --resume but it doesn't look like any hosts in the log file were successfully scanned. Starting from the beginning.");
lastip.s_addr = 0;
}
*q = p ? ')' : '\n'; /* recover changed chars */
if (inet_pton(AF_INET, lastipstr, &lastip) == 0)
fatal("Unable to parse ip (%s) in supposed log file %s. Sorry", lastipstr, fname);
free(lastipstr);
} else {
error("Warning: You asked for --resume but it doesn't look like any hosts in the log file were successfully scanned. Starting from the beginning.");
lastip.s_addr = 0;
}
}
o.resume_ip = lastip;
Expand Down
78 changes: 71 additions & 7 deletions xml.cc
Expand Up @@ -201,6 +201,68 @@ struct xml_writer {

static struct xml_writer xml;

char *xml_unescape(const char *str) {
char *result = NULL;
size_t n = 0, len;
const char *p;
int i;

i = 0;
for (p = str; *p != '\0'; p++) {
const char *repl;
char buf[32];

if (*p != '&') {
/* Based on the asumption that ampersand is only used for escaping. */
buf[0] = *p;
buf[1] = '\0';
repl = buf;
} else if (strncmp(p, "&lt;", 4) == 0) {
repl = "<";
p += 3;
} else if (strncmp(p, "&gt;", 4) == 0) {
repl = ">";
p += 3;
} else if (strncmp(p, "&amp;", 5) == 0) {
repl = "&";
p += 4;
} else if (strncmp(p, "&quot;", 6) == 0) {
repl = "\"";
p += 5;
} else if (strncmp(p, "&apos;", 6) == 0) {
repl = "\'";
p += 5;
} else if (strncmp(p, "&#45;", 5) == 0) {
repl = "-";
p += 4;
} else {
/* Escaped control characters and anything outside of ASCII. */
Strncpy(buf, p + 3, sizeof(buf));
char *q;
q = strchr(buf, ';');
if(!q)
buf[0] = '\0';
else
*q = '\0';
repl = buf;
}

len = strlen(repl);
/* Double the size of the result buffer if necessary. */
if (i == 0 || i + len > n) {
n = (i + len) * 2;
result = (char *) safe_realloc(result, n + 1);
}
memcpy(result + i, repl, len);
i += len;
}
/* Trim to length. (Also does initial allocation when str is empty.) */
result = (char *) safe_realloc(result, i + 1);
result[i] = '\0';

return result;
}

/* Escape a string for inclusion in XML. This gets <>&, "' for attribute
values, -- for inside comments, and characters with value > 0x7F. It
also gets control characters with value < 0x20 to avoid parser
Expand Down Expand Up @@ -362,19 +424,21 @@ int xml_close_pi() {
/* Open a start tag, like "<name". The tag must be later closed with
xml_close_start_tag or xml_close_empty_tag. Usually the tag is closed
after writing some attributes. */
int xml_open_start_tag(const char *name) {
int xml_open_start_tag(const char *name, const bool write) {
assert(!xml.tag_open);
log_write(LOG_XML, "<%s", name);
if (write)
log_write(LOG_XML, "<%s", name);
xml.element_stack.push_back(name);
xml.tag_open = true;
xml.root_written = true;

return 0;
}

int xml_close_start_tag() {
int xml_close_start_tag(const bool write) {
assert(xml.tag_open);
log_write(LOG_XML, ">");
if(write)
log_write(LOG_XML, ">");
xml.tag_open = false;

return 0;
Expand All @@ -392,10 +456,10 @@ int xml_close_empty_tag() {
return 0;
}

int xml_start_tag(const char *name) {
if (xml_open_start_tag(name) < 0)
int xml_start_tag(const char *name, const bool write) {
if (xml_open_start_tag(name, write) < 0)
return -1;
if (xml_close_start_tag() < 0)
if (xml_close_start_tag(write) < 0)
return -1;

return 0;
Expand Down
9 changes: 6 additions & 3 deletions xml.h
Expand Up @@ -137,10 +137,10 @@ int xml_end_comment();
int xml_open_pi(const char *name);
int xml_close_pi();

int xml_open_start_tag(const char *name);
int xml_close_start_tag();
int xml_open_start_tag(const char *name, const bool write = true);
int xml_close_start_tag(const bool write = true);
int xml_close_empty_tag();
int xml_start_tag(const char *name);
int xml_start_tag(const char *name, const bool write = true);
int xml_end_tag();

int xml_attribute(const char *name, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
Expand All @@ -151,5 +151,8 @@ int xml_depth();
bool xml_tag_open();
bool xml_root_written();


char *xml_unescape(const char *str);

#endif