mirror of
https://github.com/nmap/nmap.git
synced 2025-12-08 13:41:29 +00:00
[NSE] Added Boolean Operators for --script. You may now use a boolean operator
("and", "or", or "not") combined with categories, filenames, and filenames with
a '*', wildcard, to match many files. This change requires the script database
to be recompiled. Please see the thread at
http://seclists.org/nmap-dev/2009/q2/0100.html for more information.
This commit is contained in:
@@ -1,5 +1,12 @@
|
|||||||
# Nmap Changelog ($Id$); -*-text-*-
|
# Nmap Changelog ($Id$); -*-text-*-
|
||||||
|
|
||||||
|
o [NSE] Added Boolean Operators for --script. You may now use a boolean
|
||||||
|
operator ("and", "or", or "not") combined with categories, filenames,
|
||||||
|
and filenames with a '*', wildcard, to match many files. This change
|
||||||
|
requires the script database to be recompiled. Please see the thread at
|
||||||
|
http://seclists.org/nmap-dev/2009/q2/0100.html for more
|
||||||
|
information. [Patrick]
|
||||||
|
|
||||||
o [Ncat] In SSL mode, Ncat now always uses secure connections, meaning
|
o [Ncat] In SSL mode, Ncat now always uses secure connections, meaning
|
||||||
that it uses only good ciphers and doesn't use SSLv2. Certificates
|
that it uses only good ciphers and doesn't use SSLv2. Certificates
|
||||||
can optionally be verified with the --ssl-verify and --ssl-trustfile
|
can optionally be verified with the --ssl-verify and --ssl-trustfile
|
||||||
|
|||||||
@@ -335,10 +335,11 @@ int script_updatedb (void)
|
|||||||
" ' categories field is not a table')\n"
|
" ' categories field is not a table')\n"
|
||||||
" local basename = assert(match(script, '[/\\\\]?([^/\\\\]-%.nse)$'))\n"
|
" local basename = assert(match(script, '[/\\\\]?([^/\\\\]-%.nse)$'))\n"
|
||||||
" table.sort(categories)\n"
|
" table.sort(categories)\n"
|
||||||
|
" db:write('Entry { filename = \"', basename, '\", categories = {')\n"
|
||||||
" for j, category in ipairs(categories) do\n"
|
" for j, category in ipairs(categories) do\n"
|
||||||
" db:write('Entry { category = \"', lower(category),"
|
" db:write(' \"', lower(category), '\",')\n"
|
||||||
" '\", filename = \"', basename, '\" }\\n')\n"
|
|
||||||
" end\n"
|
" end\n"
|
||||||
|
" db:write(' } }\\n')\n"
|
||||||
"end\n"
|
"end\n"
|
||||||
"db:close()\n";
|
"db:close()\n";
|
||||||
int status = SCRIPT_ENGINE_SUCCESS;
|
int status = SCRIPT_ENGINE_SUCCESS;
|
||||||
|
|||||||
125
nse_main.lua
125
nse_main.lua
@@ -249,25 +249,14 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- check_rules(rules)
|
-- check_rules(rules)
|
||||||
-- Ensures reserved rules are not explicitly specified.
|
|
||||||
-- Adds the "default" category if no rules were specified.
|
-- Adds the "default" category if no rules were specified.
|
||||||
-- Adds reserved rules that were internally specified (--sV for "version").
|
-- Adds other implicitly specified rules (e.g. "version")
|
||||||
--
|
--
|
||||||
-- Arguments:
|
-- Arguments:
|
||||||
-- rules The array of rules to check.
|
-- rules The array of rules to check.
|
||||||
local function check_rules (rules)
|
local function check_rules (rules)
|
||||||
local reserved = {
|
if cnse.default and #rules == 0 then rules[1] = "default" end
|
||||||
version = not not cnse.scriptversion,
|
if cnse.scriptversion then rules[#rules+1] = "version" end
|
||||||
};
|
|
||||||
for i, rule in ipairs(rules) do
|
|
||||||
if reserved[lower(rule)] ~= nil then
|
|
||||||
error("explicitly specifying rule '"..rule.."' is prohibited");
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if cnse.default and #rules == 0 then rules[1] = "default"; end
|
|
||||||
for rule, option in pairs(reserved) do
|
|
||||||
if option then rules[#rules+1] = rule; end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- chosen_scripts = get_chosen_scripts(rules)
|
-- chosen_scripts = get_chosen_scripts(rules)
|
||||||
@@ -290,42 +279,86 @@ local function get_chosen_scripts (rules)
|
|||||||
"database appears to be corrupt or out of date;\n"..
|
"database appears to be corrupt or out of date;\n"..
|
||||||
"\tplease update using: nmap --script-updatedb");
|
"\tplease update using: nmap --script-updatedb");
|
||||||
|
|
||||||
local chosen_scripts, entry_rules, files_loaded = {}, {}, {};
|
local chosen_scripts, entry_rules, used_rules, files_loaded = {}, {}, {}, {};
|
||||||
|
|
||||||
-- Initialize entry_rules with the list of rules provided by the user.
|
-- Tokens that are allowed in script rules (--script)
|
||||||
-- Each element of entry_rules may refer to another canonical element.
|
local protected_lua_tokens = {
|
||||||
-- Here the lower-case rule points to the potentially mixed-case rule
|
["and"] = true,
|
||||||
-- provided by the user.
|
["or"] = true,
|
||||||
for i, rule in ipairs(rules) do
|
["not"] = true,
|
||||||
entry_rules[lower(rule)] = rule;
|
};
|
||||||
entry_rules[rule] = false;
|
-- Globalize all names in str that are not protected_lua_tokens
|
||||||
end
|
local function globalize (str)
|
||||||
|
local lstr = lower(str);
|
||||||
-- Start by loading scripts by category. This function is run on each
|
if protected_lua_tokens[lstr] then
|
||||||
-- Entry in script.db.
|
return lstr;
|
||||||
local function entry (script_entry)
|
|
||||||
local category, filename = script_entry.category, script_entry.filename;
|
|
||||||
assert(type(category) == "string" and type(filename) == "string");
|
|
||||||
|
|
||||||
-- Don't load a file more than once.
|
|
||||||
if files_loaded[filename] then return end
|
|
||||||
|
|
||||||
-- Do we have a rule for this category (or an "all" rule)?
|
|
||||||
if entry_rules[category] ~= nil or
|
|
||||||
entry_rules.all ~= nil and category ~= "version" then
|
|
||||||
local index = entry_rules[category] ~= nil and category or "all";
|
|
||||||
local mark = entry_rules[index];
|
|
||||||
-- mark may point to the actual mixed case category passed via command
|
|
||||||
-- line
|
|
||||||
if type(mark) == "boolean" then
|
|
||||||
entry_rules[index] = true;
|
|
||||||
else
|
else
|
||||||
entry_rules[mark] = true;
|
return 'm("'..str..'")';
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
-- Escape a magic character by prepending the '%' escape character
|
||||||
|
local function escape_magic (str)
|
||||||
|
return "%"..str;
|
||||||
|
end
|
||||||
|
|
||||||
|
for i, rule in ipairs(rules) do
|
||||||
|
rule = match(rule, "^%s*(.-)%s*$"); -- strip surrounding whitespace
|
||||||
|
used_rules[rule] = false; -- has not been used yet
|
||||||
|
-- Globalize all `names`, all visible characters not ',', '(', ')', and ';'
|
||||||
|
local globalized_rule =
|
||||||
|
gsub(rule, "[\033-\039\042-\043\045-\058\060-\126]+", globalize);
|
||||||
|
-- Precompile the globalized rule
|
||||||
|
local compiled_rule, err = loadstring("return "..globalized_rule, "rule");
|
||||||
|
if not compiled_rule then
|
||||||
|
err = err:match("rule\"]:%d+:(.+)$"); -- remove (luaL_)where in code
|
||||||
|
error("Bad script rule:\n\t"..rule.." -> "..err);
|
||||||
|
end
|
||||||
|
entry_rules[globalized_rule] = {
|
||||||
|
original_rule = rule,
|
||||||
|
compiled_rule = compiled_rule,
|
||||||
|
};
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Checks if a given script, script_entry, should be loaded. A script_entry
|
||||||
|
-- should be in the form: { filename = "name.nse", categories = { ... } }
|
||||||
|
local function entry (script_entry)
|
||||||
|
local categories, filename = script_entry.categories, script_entry.filename;
|
||||||
|
assert(type(categories) == "table" and type(filename) == "string",
|
||||||
|
"script database appears corrupt, try `nmap --script-updatedb`");
|
||||||
|
local escaped_basename = match(filename, "([^/\\]-)%.nse$") or
|
||||||
|
match(filename, "([^/\\]-)$");
|
||||||
|
|
||||||
|
local r_categories = {all = true}; -- A reverse table of categories
|
||||||
|
for i, category in ipairs(categories) do
|
||||||
|
assert(type(category) == "string", "bad entry in script database");
|
||||||
|
r_categories[lower(category)] = true; -- Lowercase the entry
|
||||||
|
end
|
||||||
|
-- A matching function for each script rule.
|
||||||
|
-- If the pattern directly matches a category (e.g. "all"), then
|
||||||
|
-- we return true. Otherwise we test if it is a filename or if
|
||||||
|
-- the script_entry.filename matches the pattern.
|
||||||
|
local function m (pattern)
|
||||||
|
-- Check categories
|
||||||
|
if r_categories[lower(pattern)] then return true end
|
||||||
|
-- Check filename with wildcards
|
||||||
|
pattern = gsub(pattern, "%.nse$", ""); -- remove optional extension
|
||||||
|
pattern = gsub(pattern, "[%^%$%(%)%%%.%[%]%+%-%?]", escape_magic);
|
||||||
|
pattern = gsub(pattern, "%*", ".*"); -- change to Lua wildcard
|
||||||
|
pattern = "^"..pattern.."$"; -- anchor to beginning and end
|
||||||
|
return not not find(escaped_basename, pattern);
|
||||||
|
end
|
||||||
|
local env = {m = m};
|
||||||
|
|
||||||
|
for globalized_rule, rule_table in pairs(entry_rules) do
|
||||||
|
if setfenv(rule_table.compiled_rule, env)() then -- run the compiled rule
|
||||||
local t, path = cnse.fetchfile_absolute(filename);
|
local t, path = cnse.fetchfile_absolute(filename);
|
||||||
assert(t == "file", filename.." is not a file!");
|
assert(t == "file", filename.." is not a file!");
|
||||||
|
if not files_loaded[path] then
|
||||||
chosen_scripts[#chosen_scripts+1] = Script.new(path);
|
chosen_scripts[#chosen_scripts+1] = Script.new(path);
|
||||||
files_loaded[filename] = true;
|
used_rules[rule_table.original_rule] = true;
|
||||||
|
files_loaded[path] = true;
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -333,14 +366,14 @@ local function get_chosen_scripts (rules)
|
|||||||
db_closure(); -- Load the scripts
|
db_closure(); -- Load the scripts
|
||||||
|
|
||||||
-- Now load any scripts listed by name rather than by category.
|
-- Now load any scripts listed by name rather than by category.
|
||||||
for rule, loaded in pairs(entry_rules) do
|
for rule, loaded in pairs(used_rules) do
|
||||||
if not loaded then -- attempt to load the file/directory
|
if not loaded then -- attempt to load the file/directory
|
||||||
local t, path = cnse.fetchfile_absolute(rule);
|
local t, path = cnse.fetchfile_absolute(rule);
|
||||||
if t == nil then -- perhaps omitted the extension?
|
if t == nil then -- perhaps omitted the extension?
|
||||||
t, path = cnse.fetchfile_absolute(rule..".nse");
|
t, path = cnse.fetchfile_absolute(rule..".nse");
|
||||||
end
|
end
|
||||||
if t == nil then
|
if t == nil then
|
||||||
error("No such category, filename or directory: '"..rule.."'");
|
error("'"..rule.."' did not match a category, filename, or directory");
|
||||||
elseif t == "file" and not files_loaded[path] then
|
elseif t == "file" and not files_loaded[path] then
|
||||||
chosen_scripts[#chosen_scripts+1] = Script.new(path);
|
chosen_scripts[#chosen_scripts+1] = Script.new(path);
|
||||||
files_loaded[path] = true;
|
files_loaded[path] = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user