Merge r22026 through r22063 from /nmap-exp/david/nmap-script-help (new

--script-help option).
This commit is contained in:
david 2011-01-27 21:44:54 +00:00
parent 08cf0411cc
commit 8553cb3157
8 changed files with 213 additions and 2 deletions

View file

@ -251,6 +251,13 @@ o [NSE] Nmap has two new NSE script scanning phases. The new pre-scan
found to be running each service. See
http://nmap.org/book/nse-usage.html#nse-script-types. [Djalal]
o A new --script-help option prints out the categories, NSEDoc URL,
and description for scripts matching a specification. Use it like
this for example: nmap --script-help "default or http-*". You can
use this to get a preview of what scripts will run for a given
specification. Martin Holst Swende had the idea for this feature and
wrote the first implementation. [David]
o Dramatically improved nmap.xsl (used for converting Nmap XML output
to HTML). In particular:
- Put verbose details behind expander buttons so you can see them if

View file

@ -308,6 +308,7 @@ void NmapOps::Initialize() {
scriptversion = 0;
scripttrace = 0;
scriptupdatedb = 0;
scripthelp = false;
chosenScripts.clear();
#endif
memset(&sourcesock, 0, sizeof(sourcesock));

View file

@ -326,6 +326,7 @@ class NmapOps {
int scriptversion;
int scripttrace;
int scriptupdatedb;
bool scripthelp;
void chooseScripts(char* argument);
std::vector<std::string> chosenScripts;
#endif

14
docs/nse-scripts.dtd Normal file
View file

@ -0,0 +1,14 @@
<!-- DTD for Nmap XML -&#45;script-help output.
nmap -&#45;script-help "<rules>" -oX - -->
<!ELEMENT nse-scripts (script*)>
<!ELEMENT script (categories?, description?)>
<!ATTLIST script filename CDATA #REQUIRED>
<!ELEMENT categories (category*)>
<!ELEMENT category (#PCDATA)>
<!ELEMENT description (#PCDATA)>

View file

@ -192,7 +192,10 @@ Black Hat Briefings in 2010.</para>
directories full of scripts you wish to execute. You can customize
some scripts by providing arguments to them via the
<option>--script-args</option><indexterm><primary><option>--script-args</option></primary></indexterm>
option. The two remaining options,
option.
The <option>--script-help</option><indexterm><primary><option>--script-help</option></primary></indexterm>
shows a description of what each selected script does.
The two remaining options,
<option>--script-trace</option><indexterm><primary><option>--script-trace</option></primary></indexterm>
and <option>--script-updatedb</option>,<indexterm><primary><option>--script-updatedb</option></primary></indexterm>
are generally only used for script debugging and development. Script scanning is also included as part of the <option>-A</option> (aggressive scan) option.
@ -664,6 +667,51 @@ Nmap script database, but should be used cautiously since Nmap may contain explo
<xref linkend="nse-args"/> for a detailed explanation.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<indexterm><primary><option>--script-help</option></primary></indexterm>
<option>--script-help <replaceable>filename</replaceable>|<replaceable>category</replaceable>|<replaceable>directory</replaceable>|<replaceable>expression</replaceable>|all<optional>,...</optional></option></term>
</term>
<listitem>
<para>
Shows help about scripts. For each script matching the given
specification, Nmap prints the script name, its categories, and its
description. The specifications are the same as those accepted by
<option>--script</option>; so for example if you want help about
the <literal>ftp-anon</literal> script, you would run
<command>nmap --script-help ftp-anon</command>. A sample of script
help is shown in <xref linkend="nse-script-help"/>.
</para>
<example id="nse-script-help">
<indexterm><primary><option>--script-help</option></primary><secondary>example of</secondary></indexterm>
<title>Script help</title>
<screen>
$ nmap --script-help "afp-* and discovery"
Starting Nmap 5.36TEST4 ( http://nmap.org ) at 2011-01-27 13:04 PST
afp-serverinfo
Categories: discovery safe
http://nmap.org/nsedoc/scripts/afp-serverinfo.html
Shows AFP server information. This information includes the server's
hostname, IPv4 and IPv6 addresses, and hardware type (for example
<code>Macmini</code> or <code>MacBookPro</code>).
afp-showmount
Categories: discovery safe
http://nmap.org/nsedoc/scripts/afp-showmount.html
Shows AFP shares and ACLs.
</example>
<para>
If the
<option>-oX</option><indexterm><primary><option>-oX</option></primary></indexterm>
option is used, an XML representation of the script help will be
written to the given file.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<indexterm><primary><option>--script-trace</option></primary></indexterm>

10
nmap.cc
View file

@ -602,6 +602,8 @@ int nmap_main(int argc, char *argv[]) {
{"script_updatedb", no_argument, 0, 0},
{"script-args",required_argument,0,0},
{"script_args",required_argument,0,0},
{"script-help",required_argument,0,0},
{"script_help",required_argument,0,0},
#endif
{"ip_options", required_argument, 0, 0},
{"ip-options", required_argument, 0, 0},
@ -647,6 +649,9 @@ int nmap_main(int argc, char *argv[]) {
o.scripttrace = 1;
} else if (optcmp(long_options[option_index].name, "script-updatedb") == 0){
o.scriptupdatedb = 1;
} else if (optcmp(long_options[option_index].name, "script-help") == 0){
o.scripthelp = true;
o.chooseScripts(optarg);
} else
#endif
if (optcmp(long_options[option_index].name, "max-os-tries") == 0) {
@ -1316,6 +1321,11 @@ int nmap_main(int argc, char *argv[]) {
print_iflist();
exit(0);
}
if (o.scripthelp) {
/* Special-case open_nse for --script-help only. */
open_nse();
exit(0);
}
#if HAVE_IPV6
if(o.af() == AF_INET6 && o.traceroute)

View file

@ -6,6 +6,7 @@
#include "timing.h"
#include "Target.h"
#include "nmap_tty.h"
#include "xml.h"
#include "nse_main.h"
#include "nse_utility.h"
@ -193,6 +194,65 @@ static int scan_progress_meter (lua_State *L)
return 1;
}
/* This is like nmap.log_write, but doesn't append "NSE:" to the beginning of
messages. It is only used internally by nse_main.lua and is not available to
scripts. */
static int l_log_write(lua_State *L)
{
static const char *const ops[] = {"stdout", "stderr", NULL};
static const int logs[] = {LOG_STDOUT, LOG_STDERR};
int log = logs[luaL_checkoption(L, 1, NULL, ops)];
log_write(log, "%s", luaL_checkstring(L, 2));
return 0;
}
static int l_xml_start_tag(lua_State *L)
{
const char *name;
name = luaL_checkstring(L, 1);
xml_open_start_tag(name);
if (lua_isnoneornil(L, 2)) {
lua_newtable(L);
lua_replace(L, 2);
}
lua_pushnil(L);
while (lua_next(L, 2)) {
xml_attribute(luaL_checkstring(L, -2), "%s", luaL_checkstring(L, -1));
lua_pop(L, 1);
}
xml_close_start_tag();
return 0;
}
static int l_xml_end_tag(lua_State *L)
{
xml_end_tag();
return 0;
}
static int l_xml_write_escaped(lua_State *L)
{
const char *text;
text = luaL_checkstring(L, 1);
xml_write_escaped(text);
return 0;
}
static int l_xml_newline(lua_State *L)
{
xml_newline();
return 0;
}
static void open_cnse (lua_State *L)
{
static const luaL_Reg nse[] = {
@ -208,6 +268,11 @@ static void open_cnse (lua_State *L)
{"script_set_output", script_set_output},
{"host_set_output", host_set_output},
{"port_set_output", port_set_output},
{"log_write", l_log_write},
{"xml_start_tag", l_xml_start_tag},
{"xml_end_tag", l_xml_end_tag},
{"xml_write_escaped", l_xml_write_escaped},
{"xml_newline", l_xml_newline},
{NULL, NULL}
};
@ -220,8 +285,10 @@ static void open_cnse (lua_State *L)
setbfield(L, -1, "default", o.script == 1);
setbfield(L, -1, "scriptversion", o.scriptversion == 1);
setbfield(L, -1, "scriptupdatedb", o.scriptupdatedb == 1);
setbfield(L, -1, "scripthelp", o.scripthelp);
setsfield(L, -1, "script_dbpath", SCRIPT_ENGINE_DATABASE);
setsfield(L, -1, "scriptargs", o.scriptargs);
setsfield(L, -1, "NMAP_URL", NMAP_URL);
}
void ScriptResult::set_output (const char *out)

View file

@ -122,6 +122,7 @@ end
local script_database_type, script_database_path =
cnse.fetchfile_absolute(cnse.script_dbpath);
local script_database_update = cnse.scriptupdatedb;
local script_help = cnse.scripthelp;
local stdnse = require "stdnse";
@ -170,6 +171,7 @@ end
local log_write, verbosity, debugging =
nmap.log_write, nmap.verbosity, nmap.debugging;
local log_write_raw = cnse.log_write;
local function print_verbose (level, fmt, ...)
if verbosity() >= assert(tonumber(level)) or debugging() > 0 then
@ -421,6 +423,7 @@ do
portrule = portrule,
postrule = postrule,
args = {n = 0};
description = rawget(env, "description"),
categories = rawget(env, "categories"),
author = rawget(env, "author"),
license = rawget(env, "license"),
@ -819,6 +822,62 @@ local function run (threads_iter, scantype)
progress "endTask";
end
-- Format NSEDoc markup (e.g., including bullet lists and <code> sections) into
-- a display string at the given indentation level. Currently this only indents
-- the string and doesn't interpret any other markup.
local function format_nsedoc(nsedoc, indent)
indent = indent or ""
return string.gsub(nsedoc, "([^\n]+)", indent .. "%1")
end
-- Return the NSEDoc URL for the script with the given id.
local function nsedoc_url(id)
return string.format("%s/nsedoc/scripts/%s.html", cnse.NMAP_URL, id)
end
local function script_help_normal(chosen_scripts)
for i, script in ipairs(chosen_scripts) do
log_write_raw("stdout", "\n");
log_write_raw("stdout", string.format("%s\n", script.id));
log_write_raw("stdout", string.format("Categories: %s\n", table.concat(script.categories, " ")));
log_write_raw("stdout", string.format("%s\n", nsedoc_url(script.id)));
log_write_raw("stdout", format_nsedoc(script.description, " "));
end
end
local function script_help_xml(chosen_scripts)
cnse.xml_start_tag("nse-scripts");
cnse.xml_newline();
for i, script in ipairs(chosen_scripts) do
cnse.xml_start_tag("script", { filename = script.filename });
cnse.xml_newline();
cnse.xml_start_tag("categories");
for _, category in ipairs(script.categories) do
cnse.xml_start_tag("category");
cnse.xml_write_escaped(category);
cnse.xml_end_tag();
end
cnse.xml_end_tag();
cnse.xml_newline();
cnse.xml_start_tag("description");
cnse.xml_write_escaped(script.description);
cnse.xml_end_tag();
cnse.xml_newline();
-- script
cnse.xml_end_tag();
cnse.xml_newline();
end
-- nse-scripts
cnse.xml_end_tag();
cnse.xml_newline();
end
do -- Load script arguments (--script-args)
local args = cnse.scriptargs or "";
@ -919,10 +978,14 @@ end
local chosen_scripts = get_chosen_scripts(rules);
print_verbose(1, "Loaded %d scripts for scanning.", #chosen_scripts);
for i, script in ipairs(chosen_scripts) do
-- PLEASE DO NOT CHANGE THIS FORMAT. IT IS USED BY ZENMAP TO SELECT SCRIPTS
print_debug(2, "Loaded '%s'.", script.filename);
end
if script_help then
script_help_normal(chosen_scripts);
script_help_xml(chosen_scripts);
end
-- main(hosts)
-- This is the main function we return to NSE (on the C side), nse_main.cc
-- gets this function by loading and executing nse_main.lua. This