mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
@@ -1,5 +1,9 @@
|
|||||||
# Nmap Changelog ($Id$); -*-text-*-
|
# Nmap Changelog ($Id$); -*-text-*-
|
||||||
|
|
||||||
|
o [GH#316] Added scan resume from Nmap's XML output. Now you can --resume a
|
||||||
|
canceled scan from all 3 major output formats: -oN, -oG, and -oX.
|
||||||
|
[Tudor Emil Coman]
|
||||||
|
|
||||||
o [Ndiff][GH#591] Fix a bug where hosts with the same IP but different
|
o [Ndiff][GH#591] Fix a bug where hosts with the same IP but different
|
||||||
hostnames were shown as changing hostnames between scans. Made sort stable
|
hostnames were shown as changing hostnames between scans. Made sort stable
|
||||||
with regard to hostnames. [Daniel Miller]
|
with regard to hostnames. [Daniel Miller]
|
||||||
|
|||||||
@@ -389,6 +389,7 @@ void NmapOps::Initialize() {
|
|||||||
portlist = NULL;
|
portlist = NULL;
|
||||||
exclude_portlist = NULL;
|
exclude_portlist = NULL;
|
||||||
proxy_chain = NULL;
|
proxy_chain = NULL;
|
||||||
|
resuming = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NmapOps::SCTPScan() {
|
bool NmapOps::SCTPScan() {
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ class NmapOps {
|
|||||||
/* Whether we have pcap functions (can be false on Windows). */
|
/* Whether we have pcap functions (can be false on Windows). */
|
||||||
bool have_pcap;
|
bool have_pcap;
|
||||||
int debugging;
|
int debugging;
|
||||||
|
bool resuming;
|
||||||
|
|
||||||
#define PACKET_SEND_NOPREF 1
|
#define PACKET_SEND_NOPREF 1
|
||||||
#define PACKET_SEND_ETH_WEAK 2
|
#define PACKET_SEND_ETH_WEAK 2
|
||||||
|
|||||||
1
main.cc
1
main.cc
@@ -222,6 +222,7 @@ int main(int argc, char *argv[]) {
|
|||||||
if (gather_logfile_resumption_state(argv[2], &myargc, &myargv) == -1) {
|
if (gather_logfile_resumption_state(argv[2], &myargc, &myargv) == -1) {
|
||||||
fatal("Cannot resume from (supposed) log file %s", argv[2]);
|
fatal("Cannot resume from (supposed) log file %s", argv[2]);
|
||||||
}
|
}
|
||||||
|
o.resuming = true;
|
||||||
return nmap_main(myargc, myargv);
|
return nmap_main(myargc, myargv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
148
nmap.cc
148
nmap.cc
@@ -1855,18 +1855,48 @@ int nmap_main(int argc, char *argv[]) {
|
|||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
|
|
||||||
timep = time(NULL);
|
timep = time(NULL);
|
||||||
|
|
||||||
/* Brief info in case they forget what was scanned */
|
|
||||||
Strncpy(mytime, ctime(&timep), sizeof(mytime));
|
Strncpy(mytime, ctime(&timep), sizeof(mytime));
|
||||||
chomp(mytime);
|
chomp(mytime);
|
||||||
char *xslfname = o.XSLStyleSheet();
|
|
||||||
xml_start_document("nmaprun");
|
if (!o.resuming) {
|
||||||
if (xslfname) {
|
/* Brief info in case they forget what was scanned */
|
||||||
xml_open_pi("xml-stylesheet");
|
char *xslfname = o.XSLStyleSheet();
|
||||||
xml_attribute("href", "%s", xslfname);
|
xml_start_document("nmaprun");
|
||||||
xml_attribute("type", "text/xsl");
|
if (xslfname) {
|
||||||
xml_close_pi();
|
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_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;
|
std::string command;
|
||||||
@@ -1877,37 +1907,11 @@ int nmap_main(int argc, char *argv[]) {
|
|||||||
command += argv[i];
|
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, "# ");
|
||||||
log_write(LOG_NORMAL | LOG_MACHINE, "%s %s scan initiated %s as: ", NMAP_NAME, NMAP_VERSION, mytime);
|
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, "%s", command.c_str());
|
||||||
log_write(LOG_NORMAL | LOG_MACHINE, "\n");
|
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
|
/* Before we randomize the ports scanned, lets output them to machine
|
||||||
parseable output */
|
parseable output */
|
||||||
if (o.verbose)
|
if (o.verbose)
|
||||||
@@ -2328,13 +2332,22 @@ int gather_logfile_resumption_state(char *fname, int *myargc, char ***myargv) {
|
|||||||
if (!q || ((unsigned int) (q - p) >= sizeof(nmap_arg_buffer) - 32))
|
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);
|
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));
|
strncpy(nmap_arg_buffer, "nmap --append-output ", sizeof(nmap_arg_buffer));
|
||||||
if ((q - p) + 21 + 1 >= (int) sizeof(nmap_arg_buffer))
|
if ((q - p) + 21 + 1 >= (int) sizeof(nmap_arg_buffer))
|
||||||
fatal("0verfl0w");
|
fatal("0verfl0w");
|
||||||
memcpy(nmap_arg_buffer + 21, p, q - p);
|
memcpy(nmap_arg_buffer + 21, p, q - p);
|
||||||
nmap_arg_buffer[21 + q - p] = '\0';
|
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) {
|
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");
|
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");
|
||||||
}
|
}
|
||||||
@@ -2360,37 +2373,52 @@ int gather_logfile_resumption_state(char *fname, int *myargc, char ***myargv) {
|
|||||||
fatal("Unable to parse supposed log file %s. Sorry", fname);
|
fatal("Unable to parse supposed log file %s. Sorry", fname);
|
||||||
*q = ' ';
|
*q = ' ';
|
||||||
} else {
|
} else {
|
||||||
/* OK, I guess (hope) it is a normal log then (-oN) */
|
/* Let's see if it's an XML log (-oX) */
|
||||||
q = p;
|
q = p;
|
||||||
found = NULL;
|
found = NULL;
|
||||||
while ((q = strstr(q, "\nNmap scan report for ")))
|
while ((q = strstr(q, "\n<address addr=\"")))
|
||||||
found = q = q + 22;
|
found = q = q + 16;
|
||||||
|
|
||||||
/* 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) {
|
if (found) {
|
||||||
q = strchr(found, '\n');
|
q = strchr(found, '"');
|
||||||
if (!q)
|
if (!q)
|
||||||
fatal("Unable to parse supposed log file %s. Sorry", fname);
|
fatal("Unable to parse supposed log file %s. Sorry", fname);
|
||||||
*q = '\0';
|
*q = '\0';
|
||||||
p = strchr(found, '(');
|
if (inet_pton(AF_INET, found, &lastip) == 0)
|
||||||
if (!p) { /* No DNS reverse lookup, found should already contain IP */
|
fatal("Unable to parse supposed log file %s. Sorry", fname);
|
||||||
lastipstr = strdup(found);
|
*q = '"';
|
||||||
} 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 {
|
} 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.");
|
/* OK, I guess (hope) it is a normal log then (-oN) */
|
||||||
lastip.s_addr = 0;
|
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';
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
o.resume_ip = lastip;
|
o.resume_ip = lastip;
|
||||||
|
|||||||
78
xml.cc
78
xml.cc
@@ -201,6 +201,68 @@ struct xml_writer {
|
|||||||
|
|
||||||
static struct xml_writer xml;
|
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, "<", 4) == 0) {
|
||||||
|
repl = "<";
|
||||||
|
p += 3;
|
||||||
|
} else if (strncmp(p, ">", 4) == 0) {
|
||||||
|
repl = ">";
|
||||||
|
p += 3;
|
||||||
|
} else if (strncmp(p, "&", 5) == 0) {
|
||||||
|
repl = "&";
|
||||||
|
p += 4;
|
||||||
|
} else if (strncmp(p, """, 6) == 0) {
|
||||||
|
repl = "\"";
|
||||||
|
p += 5;
|
||||||
|
} else if (strncmp(p, "'", 6) == 0) {
|
||||||
|
repl = "\'";
|
||||||
|
p += 5;
|
||||||
|
} else if (strncmp(p, "-", 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
|
/* Escape a string for inclusion in XML. This gets <>&, "' for attribute
|
||||||
values, -- for inside comments, and characters with value > 0x7F. It
|
values, -- for inside comments, and characters with value > 0x7F. It
|
||||||
also gets control characters with value < 0x20 to avoid parser
|
also gets control characters with value < 0x20 to avoid parser
|
||||||
@@ -362,9 +424,10 @@ int xml_close_pi() {
|
|||||||
/* Open a start tag, like "<name". The tag must be later closed with
|
/* 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
|
xml_close_start_tag or xml_close_empty_tag. Usually the tag is closed
|
||||||
after writing some attributes. */
|
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);
|
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.element_stack.push_back(name);
|
||||||
xml.tag_open = true;
|
xml.tag_open = true;
|
||||||
xml.root_written = true;
|
xml.root_written = true;
|
||||||
@@ -372,9 +435,10 @@ int xml_open_start_tag(const char *name) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int xml_close_start_tag() {
|
int xml_close_start_tag(const bool write) {
|
||||||
assert(xml.tag_open);
|
assert(xml.tag_open);
|
||||||
log_write(LOG_XML, ">");
|
if(write)
|
||||||
|
log_write(LOG_XML, ">");
|
||||||
xml.tag_open = false;
|
xml.tag_open = false;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -392,10 +456,10 @@ int xml_close_empty_tag() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int xml_start_tag(const char *name) {
|
int xml_start_tag(const char *name, const bool write) {
|
||||||
if (xml_open_start_tag(name) < 0)
|
if (xml_open_start_tag(name, write) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (xml_close_start_tag() < 0)
|
if (xml_close_start_tag(write) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
9
xml.h
9
xml.h
@@ -137,10 +137,10 @@ int xml_end_comment();
|
|||||||
int xml_open_pi(const char *name);
|
int xml_open_pi(const char *name);
|
||||||
int xml_close_pi();
|
int xml_close_pi();
|
||||||
|
|
||||||
int xml_open_start_tag(const char *name);
|
int xml_open_start_tag(const char *name, const bool write = true);
|
||||||
int xml_close_start_tag();
|
int xml_close_start_tag(const bool write = true);
|
||||||
int xml_close_empty_tag();
|
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_end_tag();
|
||||||
|
|
||||||
int xml_attribute(const char *name, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
int xml_attribute(const char *name, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
@@ -151,5 +151,8 @@ int xml_depth();
|
|||||||
bool xml_tag_open();
|
bool xml_tag_open();
|
||||||
bool xml_root_written();
|
bool xml_root_written();
|
||||||
|
|
||||||
|
|
||||||
|
char *xml_unescape(const char *str);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user