From 6f51d7d6a92046ff06dfc5052859cb6a39df2d8d Mon Sep 17 00:00:00 2001 From: batrick Date: Fri, 29 May 2009 00:30:56 +0000 Subject: [PATCH] Fix to the parsing of the --script-args switch [1]. Previously, the --script-args switch would only accept values with alphanumeric characters or underscores. A full treatise of the history of changes to this switch and problems can be found here [2]. Here are the new rules for --script-args definitively: --script-args may contain a sequence of key=value pairs and array entries separated by commas. All whitespace except where noted below is ignored. A key, value, or array value may be a sequence of characters except '{', '}', ',', '=', and all space characters. You may overcome this restriction by using quotes (single or double) to allow all characters within the quotation marks. You may also use the quote delimiter inside the sequence so long as it is escaped by a backslash. A value for a key/value pair or an array value are allowed to be a nested table delimited by '{' and '}'. [1] http://seclists.org/nmap-dev/2009/q2/0204.html [2] http://seclists.org/nmap-dev/2009/q2/0211.html --- nse_main.lua | 70 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 8 deletions(-) diff --git a/nse_main.lua b/nse_main.lua index 03637febc..46ec7aab9 100644 --- a/nse_main.lua +++ b/nse_main.lua @@ -54,11 +54,12 @@ local yield = coroutine.yield; local traceback = debug.traceback; local byte = string.byte; -local format = string.format; local find = string.find; +local format = string.format; local gsub = string.gsub; local lower = string.lower; local match = string.match; +local sub = string.sub; local insert = table.insert; local remove = table.remove; @@ -490,14 +491,67 @@ local function run (threads) progress "endTask"; end -do -- Load script arguments - local args = gsub((cnse.scriptargs or ""), "=([%w_]+)", "=\"%1\""); - local argsf, err = loadstring("return {"..args.."}", "Script Arguments"); - if not argsf then - error("failed to parse --script-args:\n"..args.."\n"..err); - else - nmap.registry.args = argsf(); +do -- Load script arguments (--script-args) + local args = cnse.scriptargs or ""; + + -- Parse a string in 'str' at 'start'. + local function parse_string (str, start) + -- Unquoted + local uqi, uqj, uqm = find(str, + "^%s*([^'\"%s{},=][^%s{},=]*)%s*[},=]", start); + -- Quoted + local qi, qj, q, qm = find(str, "^%s*(['\"])(.-[^\\])%1%s*[},=]", start); + -- Empty Quote + local eqi, eqj = find(str, "^%s*(['\"])%1%s*[},=]", start); + if uqi then + return uqm, uqj-1; + elseif qi then + return gsub(qm, "\\"..q, q), qj-1; + elseif eqi then + return "", eqj-1; + else + error("Value around '"..sub(str, start, start+10).. + "' is invalid or is unterminated by a valid seperator"); + end end + -- Takes 'str' at index 'start' and parses a table. + -- Returns the table and the place in the string it finished reading. + local function parse_table (str, start) + local _, j = find(str, "^%s*{", start); + local t = {}; -- table we return + local tmp, nc; -- temporary and next character inspected + + while true do + j = j+1; -- move past last token + + _, j, nc = find(str, "^%s*(%S)", j); + + if nc == "}" then -- end of table + return t, j; + else -- try to read key/value pair, or array value + local av = false; -- this is an array value? + if nc == "{" then -- array value + av, tmp, j = true, parse_table(str, j); + else + tmp, j = parse_string(str, j); + end + nc = sub(str, j+1, j+1); -- next token + if not av and nc == "=" then -- key/value? + _, j, nc = find(str, "^%s*(%S)", j+2); + if nc == "{" then + t[tmp], j = parse_table(str, j); + else -- regular string + t[tmp], j = parse_string(str, j); + end + nc = sub(str, j+1, j+1); -- next token + else -- not key/value pair, save array value + t[#t+1] = tmp; + end + if nc == "," then j = j+1 end -- skip "," token + end + end + end + nmap.registry.args = parse_table("{"..args.."}", 1); end -- Load all user chosen scripts