mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
Structured script output.
Scripts may now return a key–value table, or such a table in addition to a string. The table will be automatically formatted for normal output and will appear as a hierarchy of elements in XML output. Some history and discussion of this development can be found at https://secwiki.org/w/Nmap/Structured_Script_Output. This is a merge of r29484:29569 from /nmap-exp/david/xml-output.
This commit is contained in:
@@ -162,6 +162,10 @@ void Target::Recycle() {
|
||||
|
||||
Target::~Target() {
|
||||
FreeInternal();
|
||||
while (!scriptResults.empty()) {
|
||||
scriptResults.front().clear();
|
||||
scriptResults.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
void Target::FreeInternal() {
|
||||
|
||||
@@ -230,12 +230,22 @@
|
||||
|
||||
<!ELEMENT cpe (#PCDATA)>
|
||||
|
||||
<!ELEMENT script EMPTY >
|
||||
<!ELEMENT script (table|elem)* >
|
||||
<!ATTLIST script
|
||||
id CDATA #REQUIRED
|
||||
output CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT table (table|elem)* >
|
||||
<!ATTLIST table
|
||||
key CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT elem (#PCDATA)>
|
||||
<!ATTLIST elem
|
||||
key CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT os ( portused* , osmatch*, osfingerprint* ) >
|
||||
|
||||
<!ELEMENT portused EMPTY >
|
||||
|
||||
@@ -38,6 +38,11 @@ Additionally, you can use:
|
||||
-- | sample-script:
|
||||
-- | This is some output
|
||||
-- |_ Some more output
|
||||
-- @xmloutput
|
||||
-- <elem>This is some output</elem>
|
||||
-- <table>
|
||||
-- <elem>Some more output</elem>
|
||||
-- </table>
|
||||
--
|
||||
-- @args sample-script.arg1 Here, we document each argument, how it's used, and
|
||||
-- necessary, the default value.
|
||||
@@ -171,23 +176,45 @@ action = function( host, port )
|
||||
target.add('192.168.1.1')
|
||||
end
|
||||
|
||||
-- If your response is more complicated, you can build a table, potentially
|
||||
-- with subtables, and pass it to stdnse.format_output(). Each table can have
|
||||
-- a list of output values, numerically, which will be displayed in order.
|
||||
-- Additionally, they can have the 'name' key, which will be displayed at the
|
||||
-- top, and the 'warning' key, which will only be displayed if debugging is
|
||||
-- enabled. For more information and examples, see the documentation for
|
||||
-- stdnse.format_output().
|
||||
-- Construct a table representing what the script has to report.
|
||||
local output_tab = stdnse.output_table()
|
||||
output_tab.name1 = 'value1'
|
||||
output_tab.name2 = 'value2'
|
||||
output_tab.subtable = { 'sub1', 'sub2', 'sub3' }
|
||||
|
||||
-- Returning this table will produce output like this:
|
||||
-- | sample-script:
|
||||
-- | name1: value1
|
||||
-- | name2: value2
|
||||
-- | subtable:
|
||||
-- | sub1
|
||||
-- | sub2
|
||||
-- |_ sub3
|
||||
--
|
||||
-- If you need more control over output formatting, you can return a string in
|
||||
-- addition to the table. stdnse.format_output() is a formatting function used
|
||||
-- to make string output. Each table can have a list of output values,
|
||||
-- numerically, which will be displayed in order. Additionally, they can have
|
||||
-- the 'name' key, which will be displayed at the top, and the 'warning' key,
|
||||
-- which will only be displayed if debugging is enabled. For more information
|
||||
-- and examples, see the documentation for stdnse.format_output().
|
||||
--
|
||||
-- The following will display:
|
||||
-- | sample-script:
|
||||
-- | value1
|
||||
-- | value2
|
||||
-- | Name 1: value1
|
||||
-- | Name 2: value2
|
||||
-- | This is a subtable
|
||||
-- | subtable1
|
||||
-- |_ subtable2
|
||||
local response = {'value1', 'value2', {name="This is a subtable", 'subtable1', 'subtable2'}}
|
||||
return stdnse.format_output(true, response)
|
||||
-- | sub1
|
||||
-- | sub2
|
||||
-- |_ sub3
|
||||
|
||||
output_str = stdnse.format_output(true, {
|
||||
'Name 1: ' .. 'value1',
|
||||
'Name 2: ' .. 'value2',
|
||||
{ name='This is a subtable', 'sub1', 'sub2', 'sub3' }
|
||||
})
|
||||
|
||||
return output_tab, output_str
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -1302,9 +1302,18 @@ NSE: Script Scanning completed.
|
||||
The action is the heart of an NSE script. It contains all of the
|
||||
instructions to be executed when the script's prerule, portrule, hostrule or postrule
|
||||
triggers. It is a Lua function which accepts the same arguments as the
|
||||
rule and can return either <literal>nil</literal> or a string. If a string is returned by a service script, the string and script's filename are printed in the Nmap port table output. A string returned by a host script is printed below the port table. No output is produced if the
|
||||
script returns <literal>nil</literal>. For an example of an NSE
|
||||
action refer to <xref linkend="nse-tutorial-action"/>.
|
||||
rule. The return value of the action value may be a table of
|
||||
name–value pairs, a string, or <code>nil</code>. For an example of
|
||||
an NSE action refer to <xref linkend="nse-tutorial-action"/>.
|
||||
</para>
|
||||
<para>
|
||||
If the output of the action is a table, it is automatically formatted in
|
||||
a structured fashion for inclusion in the normal (<option>-oN</option>)
|
||||
and XML (<option>-oX</option>) output formats. If a string, the text is
|
||||
displayed directly in normal output, and written as an XML attribute in
|
||||
XML output, No output is produced if the script returns
|
||||
<literal>nil</literal>. See <xref linkend="nse-structured-output"/> for
|
||||
details of how different return values are handled.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
@@ -2166,6 +2175,140 @@ socket:close()
|
||||
</sect3>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="nse-structured-output">
|
||||
<title>Structured and Unstructured Output</title>
|
||||
<indexterm>structured script output</indexterm>
|
||||
|
||||
<para>
|
||||
NSE scripts should usually return a table representing their
|
||||
output, one that is nicely organized and has thoughtfully chosen
|
||||
keys. Such a table will be automatically formatted for screen
|
||||
output and will be stored as nested elements in XML output.
|
||||
Having XML output broken down logically into keys and values
|
||||
makes it easier for other tools to make use of script output.
|
||||
It is possible for a script to return only a string, but doing
|
||||
so is deprecated. In the past, scripts could only return a
|
||||
string, and their output was simply copied to the XML as a blob
|
||||
of text–this is now known as <quote>unstructured
|
||||
output</quote>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Suppose a script called <filename>user-list</filename> returns a
|
||||
table as shown in this code sample. The following paragraphs
|
||||
show how it appears in normal and XML output.
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
local output = stdnse.output_table()
|
||||
output.hostname = "slimer"
|
||||
output.users = {}
|
||||
output.users[#output.users + 1] = "root"
|
||||
output.users[#output.users + 1] = "foo"
|
||||
output.users[#output.users + 1] = "bar"
|
||||
return output
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
A Lua table is converted to a string for normal output. The way
|
||||
this works is: each nested table gets a new level of
|
||||
indentation. Table entries with string keys are preceded by the
|
||||
key and a colon; entries with integer keys simply appear in
|
||||
order.
|
||||
Unlike normal Lua tables, which are unordered, a table that
|
||||
comes from <code>stdnse.output_table</code> will keep its keys in
|
||||
the order they were inserted.
|
||||
<xref linkend="nse-normal-structured-output"/> shows how the
|
||||
example table appears in normal output.
|
||||
</para>
|
||||
|
||||
<example id="nse-normal-structured-output">
|
||||
<title>Automatic formatting of NSE structured output</title>
|
||||
<screen>
|
||||
PORT STATE SERVICE
|
||||
1123/tcp open unknown
|
||||
| user-list:
|
||||
| hostname: slimer
|
||||
| users:
|
||||
| root
|
||||
| foo
|
||||
|_ bar
|
||||
</screen>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
The XML representation of a Lua table is constructed as follows.
|
||||
Nested table become <code>table</code> elements. Entries of
|
||||
tables that are not themselves tables become <code>elem</code>
|
||||
elements. Entries (whether <code>table</code> or
|
||||
<code>elem</code>) with string keys get a <code>key</code>
|
||||
attribute (e.g.
|
||||
<code><elem key="username">foo</elem></code>);
|
||||
entries with integer keys have no <code>key</code> element and
|
||||
their key is implicit in the order in which they appear.
|
||||
</para>
|
||||
<para>
|
||||
In addition to the above, whatever normal output the script
|
||||
produces (even if automatically generated) is copied to the
|
||||
<code>output</code> attribute of the <code>script</code>
|
||||
element. Newlines and other special characters will be encoded
|
||||
as XML character entities, for example <code>&#xa;</code>.
|
||||
<xref linkend="nse-xml-structured-output"/> shows how the example
|
||||
table appears in XML.
|
||||
</para>
|
||||
|
||||
<example id="nse-xml-structured-output">
|
||||
<title>NSE structured output in XML</title>
|
||||
<screen><![CDATA[<script id="t" output="
hostname: slimer
users: 
 root
 foo
 bar">
|
||||
<elem key="hostname">slimer</elem>
|
||||
<table key="users">
|
||||
<elem>root</elem>
|
||||
<elem>foo</elem>
|
||||
<elem>bar</elem>
|
||||
</table>
|
||||
</script>
|
||||
]]></screen>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
Some scripts need more control their normal output. This is the
|
||||
case, for example, with scripts that need to display complex
|
||||
tables. For complete control over the output, these scripts may
|
||||
do either of these things:
|
||||
<simplelist>
|
||||
<member>return a string as second return value, or</member>
|
||||
<member>set the <code>__tostring</code> metamethod on the
|
||||
returned table.</member>
|
||||
</simplelist>
|
||||
The resulting string will be used in normal output, and the
|
||||
table will be used in XML as usual. The formatted string may
|
||||
contain newline characters to appear as multiple lines.
|
||||
</para>
|
||||
<para>
|
||||
If the above code example were modified in this way to return a
|
||||
formatted string,
|
||||
<programlisting>
|
||||
local output = stdnse.output_table()
|
||||
output.hostname = "slimer"
|
||||
output.users = {}
|
||||
output.users[#output.users + 1] = "root"
|
||||
output.users[#output.users + 1] = "foo"
|
||||
output.users[#output.users + 1] = "bar"
|
||||
local output_str = string.format("hostname: %s\n", output.hostname)
|
||||
output_str = output_str .. "\n" .. stdnse.strjoin(", ", output.users)
|
||||
return output, output_str
|
||||
</programlisting>
|
||||
then the normal output would appear as follows:
|
||||
<screen>
|
||||
PORT STATE SERVICE
|
||||
1123/tcp open unknown
|
||||
| user-list:
|
||||
| hostname: slimer
|
||||
|_ users: root, foo, bar
|
||||
</screen>
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="nse-exceptions">
|
||||
<title>Exception Handling</title>
|
||||
<indexterm><primary>exceptions in NSE</primary></indexterm>
|
||||
|
||||
10
nmap.cc
10
nmap.cc
@@ -1758,7 +1758,10 @@ int nmap_main(int argc, char *argv[]) {
|
||||
script_scan_results = get_script_scan_results_obj();
|
||||
script_scan(Targets, SCRIPT_PRE_SCAN);
|
||||
printscriptresults(script_scan_results, SCRIPT_PRE_SCAN);
|
||||
script_scan_results->clear();
|
||||
while (!script_scan_results->empty()) {
|
||||
script_scan_results->front().clear();
|
||||
script_scan_results->pop_front();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2055,7 +2058,10 @@ int nmap_main(int argc, char *argv[]) {
|
||||
if (o.script) {
|
||||
script_scan(Targets, SCRIPT_POST_SCAN);
|
||||
printscriptresults(script_scan_results, SCRIPT_POST_SCAN);
|
||||
script_scan_results->clear();
|
||||
while (!script_scan_results->empty()) {
|
||||
script_scan_results->front().clear();
|
||||
script_scan_results->pop_front();
|
||||
}
|
||||
delete new_targets;
|
||||
new_targets = NULL;
|
||||
}
|
||||
|
||||
144
nse_main.cc
144
nse_main.cc
@@ -36,6 +36,9 @@
|
||||
#define NSE_SELECTED_BY_NAME "NSE_SELECTED_BY_NAME"
|
||||
#define NSE_CURRENT_HOSTS "NSE_CURRENT_HOSTS"
|
||||
|
||||
#define NSE_FORMAT_TABLE "NSE_FORMAT_TABLE"
|
||||
#define NSE_FORMAT_XML "NSE_FORMAT_XML"
|
||||
|
||||
#ifndef MAXPATHLEN
|
||||
# define MAXPATHLEN 2048
|
||||
#endif
|
||||
@@ -113,7 +116,9 @@ static int script_set_output (lua_State *L)
|
||||
{
|
||||
ScriptResult sr;
|
||||
sr.set_id(luaL_checkstring(L, 1));
|
||||
sr.set_output(luaL_checkstring(L, 2));
|
||||
sr.set_output_tab(L, 2);
|
||||
if (!lua_isnil(L, 3))
|
||||
sr.set_output_str(luaL_checkstring(L, 3));
|
||||
script_scan_results.push_back(sr);
|
||||
return 0;
|
||||
}
|
||||
@@ -123,7 +128,9 @@ static int host_set_output (lua_State *L)
|
||||
ScriptResult sr;
|
||||
Target *target = nseU_gettarget(L, 1);
|
||||
sr.set_id(luaL_checkstring(L, 2));
|
||||
sr.set_output(luaL_checkstring(L, 3));
|
||||
sr.set_output_tab(L, 3);
|
||||
if (!lua_isnil(L, 4))
|
||||
sr.set_output_str(luaL_checkstring(L, 4));
|
||||
target->scriptResults.push_back(sr);
|
||||
return 0;
|
||||
}
|
||||
@@ -136,7 +143,9 @@ static int port_set_output (lua_State *L)
|
||||
Target *target = nseU_gettarget(L, 1);
|
||||
p = nseU_getport(L, target, &port, 2);
|
||||
sr.set_id(luaL_checkstring(L, 3));
|
||||
sr.set_output(luaL_checkstring(L, 4));
|
||||
sr.set_output_tab(L, 4);
|
||||
if (!lua_isnil(L, 5))
|
||||
sr.set_output_str(luaL_checkstring(L, 5));
|
||||
target->ports.addScriptResult(p->portno, p->proto, sr);
|
||||
target->ports.numscriptresults++;
|
||||
return 0;
|
||||
@@ -236,6 +245,19 @@ static int l_xml_newline(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_protect_xml(lua_State *L)
|
||||
{
|
||||
const char *text;
|
||||
size_t len;
|
||||
std::string output;
|
||||
|
||||
text = luaL_checklstring(L, 1, &len);
|
||||
output = protect_xml(std::string(text, len));
|
||||
lua_pushlstring(L, output.c_str(), output.size());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int nse_fetch (lua_State *L, int (*fetch)(char *, size_t, const char *))
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
@@ -340,6 +362,7 @@ static void open_cnse (lua_State *L)
|
||||
{"xml_end_tag", l_xml_end_tag},
|
||||
{"xml_write_escaped", l_xml_write_escaped},
|
||||
{"xml_newline", l_xml_newline},
|
||||
{"protect_xml", l_protect_xml},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -356,14 +379,76 @@ static void open_cnse (lua_State *L)
|
||||
|
||||
}
|
||||
|
||||
void ScriptResult::set_output (const char *out)
|
||||
/* Global persistent Lua state used by the engine. */
|
||||
static lua_State *L_NSE = NULL;
|
||||
|
||||
void ScriptResult::clear (void)
|
||||
{
|
||||
output = std::string(out);
|
||||
if (o.debugging > 3)
|
||||
log_write(LOG_STDOUT, "ScriptResult::clear %d id %s\n", output_ref, get_id());
|
||||
luaL_unref(L_NSE, LUA_REGISTRYINDEX, output_ref);
|
||||
output_ref = LUA_NOREF;
|
||||
}
|
||||
|
||||
const char *ScriptResult::get_output (void) const
|
||||
void ScriptResult::set_output_tab (lua_State *L, int pos)
|
||||
{
|
||||
return output.c_str();
|
||||
clear();
|
||||
lua_pushvalue(L, pos);
|
||||
output_ref = luaL_ref(L_NSE, LUA_REGISTRYINDEX);
|
||||
if (o.debugging > 3)
|
||||
log_write(LOG_STDOUT, "ScriptResult::set_output_tab %d id %s\n", output_ref, get_id());
|
||||
}
|
||||
|
||||
void ScriptResult::set_output_str (const char *out)
|
||||
{
|
||||
output_str = std::string(out);
|
||||
}
|
||||
|
||||
static std::string format_obj(lua_State *L, int pos)
|
||||
{
|
||||
std::string output;
|
||||
|
||||
pos = lua_absindex(L, pos);
|
||||
|
||||
/* Look up the FORMAT_TABLE function from nse_main.lua and call it. */
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, NSE_FORMAT_TABLE);
|
||||
if (lua_isnil(L, -1)) {
|
||||
log_write(LOG_STDOUT, "%s: Cannot find function _R[\"%s\"] that should be in nse_main.lua\n",
|
||||
SCRIPT_ENGINE, NSE_FORMAT_TABLE);
|
||||
lua_pop(L, 1);
|
||||
return output;
|
||||
}
|
||||
|
||||
lua_pushvalue(L, pos);
|
||||
if (lua_pcall(L, 1, 1, 0) != 0) {
|
||||
if (o.debugging)
|
||||
log_write(LOG_STDOUT, "%s: Error in FORMAT_TABLE: %s\n", SCRIPT_ENGINE, lua_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
return output;
|
||||
}
|
||||
|
||||
output = std::string(lua_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::string ScriptResult::get_output_str (void) const
|
||||
{
|
||||
std::string output;
|
||||
|
||||
/* Explicit string output? */
|
||||
if (!output_str.empty())
|
||||
return output_str;
|
||||
|
||||
/* Auto-formatted table output? */
|
||||
lua_rawgeti(L_NSE, LUA_REGISTRYINDEX, output_ref);
|
||||
if (!lua_isnil(L_NSE, -1))
|
||||
output = format_obj(L_NSE, -1);
|
||||
|
||||
lua_pop(L_NSE, 1);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void ScriptResult::set_id (const char *ident)
|
||||
@@ -381,12 +466,50 @@ ScriptResults *get_script_scan_results_obj (void)
|
||||
return &script_scan_results;
|
||||
}
|
||||
|
||||
static void format_xml(lua_State *L, int pos)
|
||||
{
|
||||
pos = lua_absindex(L, pos);
|
||||
|
||||
/* Look up the FORMAT_XML function from nse_main.lua and call it. */
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, NSE_FORMAT_XML);
|
||||
if (lua_isnil(L, -1)) {
|
||||
log_write(LOG_STDOUT, "%s: Cannot find function _R[\"%s\"] that should be in nse_main.lua\n",
|
||||
SCRIPT_ENGINE, NSE_FORMAT_XML);
|
||||
lua_pop(L, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
lua_pushvalue(L, pos);
|
||||
if (lua_pcall(L, 1, 1, 0) != 0) {
|
||||
if (o.debugging)
|
||||
log_write(LOG_STDOUT, "%s: Error in FORMAT_XML: %s\n", SCRIPT_ENGINE, lua_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptResult::write_xml() const
|
||||
{
|
||||
std::string output_str;
|
||||
|
||||
xml_open_start_tag("script");
|
||||
xml_attribute("id", "%s", get_id());
|
||||
xml_attribute("output", "%s", get_output());
|
||||
xml_close_empty_tag();
|
||||
|
||||
output_str = get_output_str();
|
||||
if (!output_str.empty())
|
||||
xml_attribute("output", "%s", protect_xml(output_str).c_str());
|
||||
|
||||
/* Any table output? */
|
||||
lua_rawgeti(L_NSE, LUA_REGISTRYINDEX, output_ref);
|
||||
if (!lua_isnil(L_NSE, -1)) {
|
||||
xml_close_start_tag();
|
||||
format_xml(L_NSE, -1);
|
||||
xml_end_tag();
|
||||
} else {
|
||||
xml_close_empty_tag();
|
||||
}
|
||||
|
||||
lua_pop(L_NSE, 1);
|
||||
}
|
||||
|
||||
/* int panic (lua_State *L)
|
||||
@@ -625,9 +748,6 @@ void nse_gettarget (lua_State *L, int index)
|
||||
lua_replace(L, -2);
|
||||
}
|
||||
|
||||
/* Global persistent Lua state used by the engine. */
|
||||
static lua_State *L_NSE = NULL;
|
||||
|
||||
void open_nse (void)
|
||||
{
|
||||
if (L_NSE == NULL)
|
||||
|
||||
15
nse_main.h
15
nse_main.h
@@ -19,11 +19,20 @@ extern "C" {
|
||||
class ScriptResult
|
||||
{
|
||||
private:
|
||||
std::string output;
|
||||
std::string id;
|
||||
/* Structured output table, an integer ref in L_NSE[LUA_REGISTRYINDEX]. */
|
||||
int output_ref;
|
||||
/* Unstructured output string, for scripts that do not return a structured
|
||||
table, or return a string in addition to a table. */
|
||||
std::string output_str;
|
||||
public:
|
||||
void set_output (const char *);
|
||||
const char *get_output (void) const;
|
||||
ScriptResult() {
|
||||
output_ref = LUA_NOREF;
|
||||
}
|
||||
void clear (void);
|
||||
void set_output_tab (lua_State *, int);
|
||||
void set_output_str (const char *);
|
||||
std::string get_output_str (void) const;
|
||||
void set_id (const char *);
|
||||
const char *get_id (void) const;
|
||||
void write_xml() const;
|
||||
|
||||
111
nse_main.lua
111
nse_main.lua
@@ -43,6 +43,8 @@ local BASE = "NSE_BASE";
|
||||
local WAITING_TO_RUNNING = "NSE_WAITING_TO_RUNNING";
|
||||
local DESTRUCTOR = "NSE_DESTRUCTOR";
|
||||
local SELECTED_BY_NAME = "NSE_SELECTED_BY_NAME";
|
||||
local FORMAT_TABLE = "NSE_FORMAT_TABLE";
|
||||
local FORMAT_XML = "NSE_FORMAT_XML";
|
||||
|
||||
-- This is a limit on the number of script instance threads running at once. It
|
||||
-- exists only to limit memory use when there are many open ports. It doesn't
|
||||
@@ -283,14 +285,25 @@ do
|
||||
print_debug(1, fmt, ...);
|
||||
end
|
||||
|
||||
-- Sets scripts output. Variable result is a string.
|
||||
function Thread:set_output(result)
|
||||
-- Sets script output. r1 and r2 are the (as many as two) return values.
|
||||
function Thread:set_output(r1, r2)
|
||||
-- Structure table and unstructured string outputs.
|
||||
local tab, str
|
||||
|
||||
if r2 then
|
||||
tab, str = r1, r2;
|
||||
elseif type(r1) == "string" then
|
||||
tab, str = nil, r1;
|
||||
else
|
||||
tab, str = r1, nil;
|
||||
end
|
||||
|
||||
if self.type == "prerule" or self.type == "postrule" then
|
||||
cnse.script_set_output(self.id, result);
|
||||
cnse.script_set_output(self.id, tab, str);
|
||||
elseif self.type == "hostrule" then
|
||||
cnse.host_set_output(self.host, self.id, result);
|
||||
cnse.host_set_output(self.host, self.id, tab, str);
|
||||
elseif self.type == "portrule" then
|
||||
cnse.port_set_output(self.host, self.port, self.id, result);
|
||||
cnse.port_set_output(self.host, self.port, self.id, tab, str);
|
||||
end
|
||||
end
|
||||
|
||||
@@ -902,18 +915,19 @@ local function run (threads_iter, hosts)
|
||||
current, running[co] = thread, nil;
|
||||
thread:start_time_out_clock();
|
||||
|
||||
local s, result = resume(co, unpack(thread.args, 1, thread.args.n));
|
||||
-- Threads may have zero, one, or two return values.
|
||||
local s, r1, r2 = resume(co, unpack(thread.args, 1, thread.args.n));
|
||||
if not s then -- script error...
|
||||
all[co], num_threads = nil, num_threads-1;
|
||||
if debugging() > 0 then
|
||||
thread:d("%THREAD_AGAINST threw an error!\n%s\n",
|
||||
traceback(co, tostring(result)));
|
||||
traceback(co, tostring(r1)));
|
||||
else
|
||||
thread:set_output("ERROR: Script execution failed (use -d to debug)");
|
||||
end
|
||||
thread:close(timeouts, result);
|
||||
thread:close(timeouts, r1);
|
||||
elseif status(co) == "suspended" then
|
||||
if result == NSE_YIELD_VALUE then
|
||||
if r1 == NSE_YIELD_VALUE then
|
||||
waiting[co] = thread;
|
||||
else
|
||||
all[co], num_threads = nil, num_threads-1;
|
||||
@@ -922,15 +936,7 @@ local function run (threads_iter, hosts)
|
||||
end
|
||||
elseif status(co) == "dead" then
|
||||
all[co], num_threads = nil, num_threads-1;
|
||||
if type(result) == "string" then
|
||||
-- Escape any character outside the range 32-126 except for tab,
|
||||
-- carriage return, and line feed. This makes the string safe for
|
||||
-- screen display as well as XML (see section 2.2 of the XML spec).
|
||||
result = gsub(result, "[^\t\r\n\032-\126]", function(a)
|
||||
return format("\\x%02X", byte(a));
|
||||
end);
|
||||
thread:set_output(result);
|
||||
end
|
||||
thread:set_output(r1, r2);
|
||||
thread:d("Finished %THREAD_AGAINST.");
|
||||
thread:close(timeouts);
|
||||
end
|
||||
@@ -949,6 +955,75 @@ local function run (threads_iter, hosts)
|
||||
progress "endTask";
|
||||
end
|
||||
|
||||
-- This function does the automatic formatting of Lua objects into strings, for
|
||||
-- normal output and for the XML @output attribute. Each nested table is
|
||||
-- indented by two spaces. Tables having a __tostring metamethod are converted
|
||||
-- using tostring. Otherwise, integer keys are listed first and only their
|
||||
-- value is shown; then string keys are shown prefixed by the key and a colon.
|
||||
-- Any other kinds of keys. Anything that is not a table is converted to a
|
||||
-- string with tostring.
|
||||
local function format_table(obj, indent)
|
||||
indent = indent or " ";
|
||||
if type(obj) == "table" then
|
||||
local mt = getmetatable(obj)
|
||||
if mt and mt["__tostring"] then
|
||||
-- Table obeys tostring, so use that.
|
||||
return tostring(obj)
|
||||
end
|
||||
|
||||
local lines = {};
|
||||
-- Do integer keys.
|
||||
for _, v in ipairs(obj) do
|
||||
lines[#lines + 1] = indent .. format_table(v, indent .. " ");
|
||||
end
|
||||
-- Do string keys.
|
||||
for k, v in pairs(obj) do
|
||||
if type(k) == "string" then
|
||||
lines[#lines + 1] = indent .. k .. ": " .. format_table(v, indent .. " ");
|
||||
end
|
||||
end
|
||||
return "\n" .. concat(lines, "\n");
|
||||
else
|
||||
return tostring(obj);
|
||||
end
|
||||
end
|
||||
_R[FORMAT_TABLE] = format_table
|
||||
|
||||
local format_xml
|
||||
local function format_xml_elem(obj, key)
|
||||
if key then
|
||||
key = cnse.protect_xml(tostring(key));
|
||||
end
|
||||
if type(obj) == "table" then
|
||||
cnse.xml_start_tag("table", {key=key});
|
||||
cnse.xml_newline();
|
||||
else
|
||||
cnse.xml_start_tag("elem", {key=key});
|
||||
end
|
||||
format_xml(obj);
|
||||
cnse.xml_end_tag();
|
||||
cnse.xml_newline();
|
||||
end
|
||||
|
||||
-- This function writes an XML representation of a Lua object to the XML stream.
|
||||
function format_xml(obj, key)
|
||||
if type(obj) == "table" then
|
||||
-- Do integer keys.
|
||||
for _, v in ipairs(obj) do
|
||||
format_xml_elem(v);
|
||||
end
|
||||
-- Do string keys.
|
||||
for k, v in pairs(obj) do
|
||||
if type(k) == "string" then
|
||||
format_xml_elem(v, k);
|
||||
end
|
||||
end
|
||||
else
|
||||
cnse.xml_write_escaped(cnse.protect_xml(tostring(obj)));
|
||||
end
|
||||
end
|
||||
_R[FORMAT_XML] = format_xml
|
||||
|
||||
-- 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.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
-- @name stdnse
|
||||
|
||||
local _G = require "_G"
|
||||
local coroutine = require "coroutine"
|
||||
local math = require "math"
|
||||
local nmap = require "nmap"
|
||||
local os = require "os"
|
||||
@@ -17,6 +18,7 @@ local error = error;
|
||||
local getmetatable = getmetatable;
|
||||
local ipairs = ipairs
|
||||
local pairs = pairs
|
||||
local rawset = rawset
|
||||
local require = require;
|
||||
local select = select
|
||||
local setmetatable = setmetatable;
|
||||
@@ -1032,4 +1034,50 @@ function seeall (env)
|
||||
setmetatable(env, m);
|
||||
end
|
||||
|
||||
--- Return a table that keeps elements in order of insertion.
|
||||
--
|
||||
-- The pairs function, called on a table returned by this function, will yield
|
||||
-- elements in the order they were inserted. This function is meant to be used
|
||||
-- to construct output tables returned by scripts.
|
||||
--
|
||||
-- Reinserting a key that is already in the table does not change its position
|
||||
-- in the order. However, removing a key by assigning to <code>nil</code> and
|
||||
-- then doing another assignment will move the key to the end of the order.
|
||||
--
|
||||
-- @return An ordered table.
|
||||
function output_table ()
|
||||
local t = {}
|
||||
local reverse = {}
|
||||
local order = {}
|
||||
local function iterator ()
|
||||
for i, key in ipairs(order) do
|
||||
coroutine.yield(key, t[key])
|
||||
end
|
||||
end
|
||||
local mt = {
|
||||
__newindex = function (_, k, v)
|
||||
if reverse[k] then
|
||||
rawset(t, k, v)
|
||||
if v == nil then
|
||||
table.remove(order, reverse[k])
|
||||
reverse[k] = nil
|
||||
end
|
||||
else
|
||||
if v ~= nil then
|
||||
table.insert(order, k)
|
||||
reverse[k] = #order
|
||||
end
|
||||
rawset(t, k, v)
|
||||
end
|
||||
end,
|
||||
__index = function (_, k)
|
||||
return t[k]
|
||||
end,
|
||||
__pairs = function (_)
|
||||
return coroutine.wrap(iterator)
|
||||
end,
|
||||
}
|
||||
return setmetatable({}, mt)
|
||||
end
|
||||
|
||||
return _ENV;
|
||||
|
||||
54
output.cc
54
output.cc
@@ -425,16 +425,46 @@ int print_iflist(void) {
|
||||
}
|
||||
|
||||
#ifndef NOLUA
|
||||
/* Escape control characters to make a string safe to display on a terminal. */
|
||||
static std::string escape_for_screen(const std::string s) {
|
||||
std::string r;
|
||||
|
||||
for (unsigned int i = 0; i < s.size(); i++) {
|
||||
char buf[5];
|
||||
unsigned char c = s[i];
|
||||
if (c == '\t' || c == '\r' || c == '\n' || (0x20 <= c && c <= 0x7e)) {
|
||||
r += c;
|
||||
} else {
|
||||
Snprintf(buf, sizeof(buf), "\\x%02X", c);
|
||||
r += buf;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Do something to protect characters that can't appear in XML. This is not a
|
||||
reversible transform, more a last-ditch effort to write readable XML with
|
||||
characters that shouldn't be part of regular output anyway. The escaping that
|
||||
xml_write_escaped is not enough; some characters are not allowed to appear in
|
||||
XML, not even escaped. */
|
||||
std::string protect_xml(const std::string s) {
|
||||
/* escape_for_screen is good enough. */
|
||||
return escape_for_screen(s);
|
||||
}
|
||||
|
||||
static char *formatScriptOutput(ScriptResult sr) {
|
||||
std::vector<std::string> lines;
|
||||
|
||||
const char *c_output;
|
||||
std::string c_output;
|
||||
const char *p, *q;
|
||||
std::string result;
|
||||
unsigned int i;
|
||||
|
||||
c_output = sr.get_output();
|
||||
p = c_output;
|
||||
c_output = escape_for_screen(sr.get_output_str());
|
||||
if (c_output.empty())
|
||||
return NULL;
|
||||
p = c_output.c_str();
|
||||
|
||||
while (*p != '\0') {
|
||||
q = strchr(p, '\n');
|
||||
@@ -798,8 +828,10 @@ void printportoutput(Target *currenths, PortList *plist) {
|
||||
ssr_iter->write_xml();
|
||||
|
||||
char *script_output = formatScriptOutput((*ssr_iter));
|
||||
Tbl->addItem(rowno, 0, true, true, script_output);
|
||||
free(script_output);
|
||||
if (script_output != NULL) {
|
||||
Tbl->addItem(rowno, 0, true, true, script_output);
|
||||
free(script_output);
|
||||
}
|
||||
rowno++;
|
||||
}
|
||||
|
||||
@@ -2198,8 +2230,10 @@ void printscriptresults(ScriptResults *scriptResults, stype scantype) {
|
||||
iter->write_xml();
|
||||
|
||||
script_output = formatScriptOutput((*iter));
|
||||
log_write(LOG_PLAIN, "%s\n", script_output);
|
||||
free(script_output);
|
||||
if (script_output != NULL) {
|
||||
log_write(LOG_PLAIN, "%s\n", script_output);
|
||||
free(script_output);
|
||||
}
|
||||
}
|
||||
xml_end_tag();
|
||||
}
|
||||
@@ -2220,8 +2254,10 @@ void printhostscriptresults(Target *currenths) {
|
||||
iter->write_xml();
|
||||
|
||||
script_output = formatScriptOutput((*iter));
|
||||
log_write(LOG_PLAIN, "%s\n", script_output);
|
||||
free(script_output);
|
||||
if (script_output != NULL) {
|
||||
log_write(LOG_PLAIN, "%s\n", script_output);
|
||||
free(script_output);
|
||||
}
|
||||
}
|
||||
xml_end_tag();
|
||||
}
|
||||
|
||||
2
output.h
2
output.h
@@ -220,6 +220,8 @@ void printosscanoutput(Target *currenths);
|
||||
void printserviceinfooutput(Target *currenths);
|
||||
|
||||
#ifndef NOLUA
|
||||
std::string protect_xml(const std::string s);
|
||||
|
||||
/* Use this function to report NSE_PRE_SCAN and NSE_POST_SCAN results */
|
||||
void printscriptresults(ScriptResults *scriptResults, stype scantype);
|
||||
|
||||
|
||||
11
portlist.cc
11
portlist.cc
@@ -147,6 +147,14 @@ void Port::freeService(bool del_service) {
|
||||
}
|
||||
}
|
||||
|
||||
void Port::freeScriptResults(void)
|
||||
{
|
||||
while (!scriptResults.empty()) {
|
||||
scriptResults.front().clear();
|
||||
scriptResults.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
/* Fills in namebuf (as long as there is space in buflen) with the
|
||||
Name nmap normal output will use to describe the port. This takes
|
||||
into account to confidence level, any SSL tunneling, etc. Truncates
|
||||
@@ -508,6 +516,9 @@ PortList::~PortList() {
|
||||
for(i=0; i < port_list_count[proto]; i++) { // free every Port
|
||||
if(port_list[proto][i]) {
|
||||
port_list[proto][i]->freeService(true);
|
||||
#ifndef NOLUA
|
||||
port_list[proto][i]->freeScriptResults();
|
||||
#endif
|
||||
delete port_list[proto][i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,6 +181,7 @@ class Port {
|
||||
public:
|
||||
Port();
|
||||
void freeService(bool del_service);
|
||||
void freeScriptResults(void);
|
||||
void getNmapServiceName(char *namebuf, int buflen, const char *rpcinfo) const;
|
||||
|
||||
u16 portno;
|
||||
|
||||
@@ -13,9 +13,13 @@ sent, so the difference includes at least the duration of one RTT.
|
||||
---
|
||||
-- @output
|
||||
-- 80/tcp open http
|
||||
-- |_ http-date: Thu, 23 Jul 2009 23:15:57 GMT; -6s from local time.
|
||||
-- |_http-date: Thu, 02 Aug 2012 22:11:03 GMT; 0s from local time.
|
||||
-- 80/tcp open http
|
||||
-- |_ http-date: Wed, 17 Jan 2007 09:29:10 GMT; -2y187d13h46m53s from local time.
|
||||
-- |_http-date: Thu, 02 Aug 2012 22:07:12 GMT; -3m51s from local time.
|
||||
--
|
||||
-- @xmloutput
|
||||
-- <elem key="date">2012-08-02T23:07:12Z</elem>
|
||||
-- <elem key="delta">-231</elem>
|
||||
|
||||
author = "David Fifield"
|
||||
|
||||
@@ -39,9 +43,13 @@ action = function(host, port)
|
||||
return
|
||||
end
|
||||
|
||||
-- Should account for estimated RTT too.
|
||||
local diff = stdnse.format_difftime(response_date, request_date)
|
||||
local output_tab = stdnse.output_table()
|
||||
-- ISO 8601 date and time.
|
||||
output_tab.date = os.date("%Y-%m-%dT%H:%M:%SZ", os.time(response_date))
|
||||
output_tab.delta = os.difftime(os.time(response_date), os.time(request_date))
|
||||
|
||||
return string.format("%s; %s from local time.",
|
||||
response.header["date"], diff)
|
||||
local output_str = string.format("%s; %s from local time.",
|
||||
response.header["date"], stdnse.format_difftime(response_date, request_date))
|
||||
|
||||
return output_tab, output_str
|
||||
end
|
||||
|
||||
@@ -22,6 +22,12 @@ original target.
|
||||
-- PORT STATE SERVICE
|
||||
-- 80/tcp open http
|
||||
-- |_http-title: Go ahead and ScanMe!
|
||||
--
|
||||
-- @xmloutput
|
||||
-- <elem key="title">Go ahead and ScanMe!</elem>
|
||||
-- @xmloutput
|
||||
-- <elem key="title">Wikipedia, the free encyclopedia</elem>
|
||||
-- <elem key="redirect_url">http://en.wikipedia.org/wiki/Main_Page</elem>
|
||||
|
||||
author = "Diman Todorov"
|
||||
|
||||
@@ -41,7 +47,7 @@ action = function(host, port)
|
||||
if resp.location then
|
||||
redirect_url = resp.location[#resp.location]
|
||||
if resp.status and tostring( resp.status ):match( "30%d" ) then
|
||||
return ("Did not follow redirect to %s"):format( redirect_url )
|
||||
return {redirect_url = redirect_url}, ("Did not follow redirect to %s"):format( redirect_url )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -64,10 +70,14 @@ action = function(host, port)
|
||||
end
|
||||
end
|
||||
|
||||
local output_tab = stdnse.output_table()
|
||||
output_tab.title = title
|
||||
output_tab.redirect_url = redirect_url
|
||||
|
||||
local output_str = display_title
|
||||
if redirect_url then
|
||||
output_str = output_str .. "\n" .. ("Requested resource was %s"):format( redirect_url )
|
||||
end
|
||||
|
||||
return output_str
|
||||
return output_tab, output_str
|
||||
end
|
||||
|
||||
@@ -13,24 +13,26 @@ organizationName, stateOrProvinceName, and countryName of the subject.
|
||||
|
||||
<code>
|
||||
443/tcp open https
|
||||
| ssl-cert: Subject: commonName=www.paypal.com/organizationName=PayPal, Inc.\
|
||||
| ssl-cert: Subject: commonName=www.paypal.com/organizationName=PayPal, Inc.\
|
||||
/stateOrProvinceName=California/countryName=US
|
||||
| Not valid before: 2009-05-28 00:00:00
|
||||
|_ Not valid after: 2010-05-01 23:59:59
|
||||
| Not valid before: 2011-03-23 00:00:00
|
||||
|_Not valid after: 2013-04-01 23:59:59
|
||||
</code>
|
||||
|
||||
With <code>-v</code> it adds the issuer name and fingerprints.
|
||||
|
||||
<code>
|
||||
443/tcp open https
|
||||
| ssl-cert: Subject: commonName=www.paypal.com/organizationName=PayPal, Inc.\
|
||||
| ssl-cert: Subject: commonName=www.paypal.com/organizationName=PayPal, Inc.\
|
||||
/stateOrProvinceName=California/countryName=US
|
||||
| Issuer: commonName=VeriSign Class 3 Extended Validation SSL CA\
|
||||
| Issuer: commonName=VeriSign Class 3 Extended Validation SSL CA\
|
||||
/organizationName=VeriSign, Inc./countryName=US
|
||||
| Not valid before: 2009-05-28 00:00:00
|
||||
| Not valid after: 2010-05-01 23:59:59
|
||||
| MD5: c5b8 7ddd ccc7 537f 8861 b476 078d e8fd
|
||||
|_ SHA-1: dc5a cb8b 9eb9 b5de 7117 c536 8c15 0e75 ba88 702e
|
||||
| Public Key type: rsa
|
||||
| Public Key bits: 2048
|
||||
| Not valid before: 2011-03-23 00:00:00
|
||||
| Not valid after: 2013-04-01 23:59:59
|
||||
| MD5: bf47 ceca d861 efa7 7d14 88ad 4a73 cb5b
|
||||
|_SHA-1: d846 5221 467a 0d15 3df0 9f2e af6d 4390 0213 9a68
|
||||
</code>
|
||||
|
||||
With <code>-vv</code> it adds the PEM-encoded contents of the entire
|
||||
@@ -38,32 +40,73 @@ certificate.
|
||||
|
||||
<code>
|
||||
443/tcp open https
|
||||
| ssl-cert: Subject: commonName=www.paypal.com/organizationName=PayPal, Inc.\
|
||||
/stateOrProvinceName=California/countryName=US/serialNumber=3014267\
|
||||
/1.3.6.1.4.1.311.60.2.1.3=US/streetAddress=2211 N 1st St\
|
||||
/1.3.6.1.4.1.311.60.2.1.2=Delaware/postalCode=95131-2021\
|
||||
/localityName=San Jose/organizationalUnitName=Information Systems\
|
||||
/2.5.4.15=V1.0, Clause 5.(b)
|
||||
| Issuer: commonName=VeriSign Class 3 Extended Validation SSL CA\
|
||||
| ssl-cert: Subject: commonName=www.paypal.com/organizationName=PayPal, Inc.\
|
||||
/stateOrProvinceName=California/countryName=US/1.3.6.1.4.1.311.60.2.1.2=Delaware\
|
||||
/postalCode=95131-2021/localityName=San Jose/serialNumber=3014267\
|
||||
/streetAddress=2211 N 1st St/1.3.6.1.4.1.311.60.2.1.3=US\
|
||||
/organizationalUnitName=PayPal Production/businessCategory=Private Organization
|
||||
| Issuer: commonName=VeriSign Class 3 Extended Validation SSL CA\
|
||||
/organizationName=VeriSign, Inc./countryName=US\
|
||||
/organizationalUnitName=Terms of use at https://www.verisign.com/rpa (c)06
|
||||
| Not valid before: 2009-05-28 00:00:00
|
||||
| Not valid after: 2010-05-01 23:59:59
|
||||
| MD5: c5b8 7ddd ccc7 537f 8861 b476 078d e8fd
|
||||
| SHA-1: dc5a cb8b 9eb9 b5de 7117 c536 8c15 0e75 ba88 702e
|
||||
| -----BEGIN CERTIFICATE-----
|
||||
| MIIFxzCCBK+gAwIBAgIQX02QuADDB7CVjZdooVge+zANBgkqhkiG9w0BAQUFADCB
|
||||
| Public Key type: rsa
|
||||
| Public Key bits: 2048
|
||||
| Not valid before: 2011-03-23 00:00:00
|
||||
| Not valid after: 2013-04-01 23:59:59
|
||||
| MD5: bf47 ceca d861 efa7 7d14 88ad 4a73 cb5b
|
||||
| SHA-1: d846 5221 467a 0d15 3df0 9f2e af6d 4390 0213 9a68
|
||||
| -----BEGIN CERTIFICATE-----
|
||||
| MIIGSzCCBTOgAwIBAgIQLjOHT2/i1B7T//819qTJGDANBgkqhkiG9w0BAQUFADCB
|
||||
...
|
||||
| 9YDR12XLZeQjO1uiunCsJkDIf9/5Mqpu57pw8v1QNA==
|
||||
|_-----END CERTIFICATE-----
|
||||
</code>
|
||||
]]
|
||||
|
||||
---
|
||||
-- @output
|
||||
-- 443/tcp open https
|
||||
-- | ssl-cert: Subject: commonName=www.paypal.com/organizationName=PayPal, Inc.\
|
||||
-- | ssl-cert: Subject: commonName=www.paypal.com/organizationName=PayPal, Inc.\
|
||||
-- /stateOrProvinceName=California/countryName=US
|
||||
-- | Not valid before: 2009-05-28 00:00:00
|
||||
-- |_ Not valid after: 2010-05-01 23:59:59
|
||||
-- | Not valid before: 2011-03-23 00:00:00
|
||||
-- |_Not valid after: 2013-04-01 23:59:59
|
||||
--
|
||||
-- @xmloutput
|
||||
-- <table key="subject">
|
||||
-- <elem key="1.3.6.1.4.1.311.60.2.1.2">Delaware</elem>
|
||||
-- <elem key="1.3.6.1.4.1.311.60.2.1.3">US</elem>
|
||||
-- <elem key="postalCode">95131-2021</elem>
|
||||
-- <elem key="localityName">San Jose</elem>
|
||||
-- <elem key="serialNumber">3014267</elem>
|
||||
-- <elem key="countryName">US</elem>
|
||||
-- <elem key="stateOrProvinceName">California</elem>
|
||||
-- <elem key="streetAddress">2211 N 1st St</elem>
|
||||
-- <elem key="organizationalUnitName">PayPal Production</elem>
|
||||
-- <elem key="commonName">www.paypal.com</elem>
|
||||
-- <elem key="organizationName">PayPal, Inc.</elem>
|
||||
-- <elem key="businessCategory">Private Organization</elem>
|
||||
-- </table>
|
||||
-- <table key="issuer">
|
||||
-- <elem key="organizationalUnitName">Terms of use at https://www.verisign.com/rpa (c)06</elem>
|
||||
-- <elem key="organizationName">VeriSign, Inc.</elem>
|
||||
-- <elem key="commonName">VeriSign Class 3 Extended Validation SSL CA</elem>
|
||||
-- <elem key="countryName">US</elem>
|
||||
-- </table>
|
||||
-- <table key="pubkey">
|
||||
-- <elem key="type">rsa</elem>
|
||||
-- <elem key="bits">2048</elem>
|
||||
-- </table>
|
||||
-- <table key="validity">
|
||||
-- <elem key="notBefore">2011-03-23T00:00:00Z</elem>
|
||||
-- <elem key="notAfter">2013-04-01T23:59:59Z</elem>
|
||||
-- </table>
|
||||
-- <elem key="md5">bf47cecad861efa77d1488ad4a73cb5b</elem>
|
||||
-- <elem key="sha1">d8465221467a0d153df09f2eaf6d439002139a68</elem>
|
||||
-- <elem key="pem">-----BEGIN CERTIFICATE-----
|
||||
-- MIIGSzCCBTOgAwIBAgIQLjOHT2/i1B7T//819qTJGDANBgkqhkiG9w0BAQUFADCB
|
||||
-- ...
|
||||
-- 9YDR12XLZeQjO1uiunCsJkDIf9/5Mqpu57pw8v1QNA==
|
||||
-- -----END CERTIFICATE-----
|
||||
-- </elem>
|
||||
|
||||
author = "David Fifield"
|
||||
|
||||
@@ -129,7 +172,37 @@ function stringify_name(name)
|
||||
return stdnse.strjoin("/", fields)
|
||||
end
|
||||
|
||||
local function parseCertificate(cert)
|
||||
local function name_to_table(name)
|
||||
local output = {}
|
||||
for k, v in pairs(name) do
|
||||
if type(k) == "table" then
|
||||
k = stdnse.strjoin(".", k)
|
||||
end
|
||||
output[k] = v
|
||||
end
|
||||
return output
|
||||
end
|
||||
|
||||
local function format_time(t)
|
||||
return os.date("%Y-%m-%dT%H:%M:%SZ", os.time(t))
|
||||
end
|
||||
|
||||
local function output_tab(cert)
|
||||
local o = stdnse.output_table()
|
||||
o.subject = name_to_table(cert.subject)
|
||||
o.issuer = name_to_table(cert.issuer)
|
||||
o.pubkey = cert.pubkey
|
||||
o.validity = {}
|
||||
for k, v in pairs(cert.validity) do
|
||||
o.validity[k] = format_time(v)
|
||||
end
|
||||
o.md5 = stdnse.tohex(cert:digest("md5"))
|
||||
o.sha1 = stdnse.tohex(cert:digest("sha1"))
|
||||
o.pem = cert.pem
|
||||
return o
|
||||
end
|
||||
|
||||
local function output_str(cert)
|
||||
local lines = {}
|
||||
|
||||
lines[#lines + 1] = "Subject: " .. stringify_name(cert.subject)
|
||||
@@ -156,7 +229,7 @@ local function parseCertificate(cert)
|
||||
if nmap.verbosity() > 1 then
|
||||
lines[#lines + 1] = cert.pem
|
||||
end
|
||||
return lines
|
||||
return stdnse.strjoin("\n", lines)
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
@@ -164,10 +237,8 @@ action = function(host, port)
|
||||
if ( not(status) ) then
|
||||
return
|
||||
end
|
||||
|
||||
local lines = parseCertificate(cert)
|
||||
|
||||
return stdnse.strjoin("\n", lines)
|
||||
return output_tab(cert), output_str(cert)
|
||||
end
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user