diff --git a/nselib/url.lua b/nselib/url.lua index 93b1b634f..15ebf65c6 100644 --- a/nselib/url.lua +++ b/nselib/url.lua @@ -319,7 +319,8 @@ end -- This function takes a of the form -- "name1=value1&name2=value2" -- and returns a table containing the name-value pairs, with the name as the key --- and the value as its associated value. +-- and the value as its associated value. Both the name and the value are +-- subject to URL decoding. -- @param query Query string. -- @return A table of name-value pairs following the pattern -- table["name"] = value. @@ -333,9 +334,11 @@ function parse_query(query) query = string.gsub(query, ">", ">") local function ginsert(qstr) - local first, last = string.find(qstr, "=") - if first then - parsed[string.sub(qstr, 0, first-1)] = string.sub(qstr, first+1) + local pos = qstr:find("=", 1, true) + if pos then + parsed[unescape(qstr:sub(1, pos - 1))] = unescape(qstr:sub(pos + 1)) + else + parsed[unescape(qstr)] = "" end end @@ -355,18 +358,19 @@ end --- -- Builds a query string from a table. -- --- This is the inverse of parse_query. +-- This is the inverse of parse_query. Both the parameter name +-- and value are subject to URL encoding. -- @param query A dictionary table where table['name'] = -- value. -- @return A query string (like "name=value2&name=value2"). ----------------------------------------------------------------------------- function build_query(query) - local qstr = "" + local qstr = {} for i,v in pairs(query) do - qstr = qstr .. i .. '=' .. v .. '&' + qstr[#qstr+1] = escape(i) .. '=' .. escape(v) end - return string.sub(qstr, 0, #qstr-1) + return table.concat(qstr, '&') end return _ENV; diff --git a/scripts/http-form-fuzzer.nse b/scripts/http-form-fuzzer.nse index 69da08a0d..40d78ca82 100644 --- a/scripts/http-form-fuzzer.nse +++ b/scripts/http-form-fuzzer.nse @@ -97,14 +97,6 @@ local function generate_safe_postdata(form) return postdata end -local function generate_get_string(data) - local get_str = {"?"} - for name,value in pairs(data) do - get_str[#get_str+1]=url.escape(name).."="..url.escape(value).."&" - end - return table.concat(get_str) -end - -- generate a charset of characters with ascii codes from 33 to 126 -- you can use http://www.asciitable.com/ to see which characters those actually are local charset = generate_charset(33,126) @@ -156,7 +148,7 @@ local function fuzz_form(form, minlen, maxlen, host, port, path) if form["method"]=="post" then sending_function = function(data) return http.post(host, port, form_submission_path, nil, nil, data) end else - sending_function = function(data) return http.get(host, port, form_submission_path..generate_get_string(data), {no_cache=true, bypass_cache=true}) end + sending_function = function(data) return http.get(host, port, form_submission_path.."?"..url.build_query(data), {no_cache=true, bypass_cache=true}) end end for _,field in ipairs(form["fields"]) do diff --git a/scripts/http-open-redirect.nse b/scripts/http-open-redirect.nse index 2fe4792ce..4acbb73b7 100644 --- a/scripts/http-open-redirect.nse +++ b/scripts/http-open-redirect.nse @@ -43,6 +43,8 @@ categories = {"discovery", "intrusive"} portrule = shortport.http +local redirect_canary = "http://scanme.nmap.org/" + local function dbg(str,...) stdnse.debug2(str, ...) end @@ -74,10 +76,9 @@ local function checkLocationEcho(query, destination) local q = url.parse_query(query); -- Check the values (and keys) and see if they are reflected in the location header for k,v in pairs(q) do - local s,f = string.find(destination, v) - if s == 1 then + if destination:sub(1, #v) == v then -- Build a new URL - q[k] = "http%3A%2f%2fscanme.nmap.org%2f"; + q[k] = redirect_canary; return url.build_query(q) end end @@ -123,7 +124,7 @@ action = function(host, port) dbg("Checking potential open redirect: %s:%s%s", host,port,url); local testResponse = http.get(host, port, url); --dbgt(testResponse) - if isRedirect(testResponse.status) and testResponse.header.location == "http://scanme.nmap.org/" then + if isRedirect(testResponse.status) and testResponse.header.location == redirect_canary then table.insert(results, ("%s://%s:%s%s"):format(parsed.scheme, host, port,url)) end end diff --git a/scripts/http-rfi-spider.nse b/scripts/http-rfi-spider.nse index 767695c12..5254c2e94 100644 --- a/scripts/http-rfi-spider.nse +++ b/scripts/http-rfi-spider.nse @@ -69,14 +69,6 @@ local function generate_safe_postdata(form) return postdata end -local function generate_get_string(data) - local get_str = {"?"} - for name,value in pairs(data) do - get_str[#get_str+1]=url.escape(name).."="..url.escape(value).."&" - end - return table.concat(get_str) -end - -- checks each field of a form to see if it's vulnerable to rfi local function check_form(form, host, port, path) local vulnerable_fields = {} @@ -96,7 +88,7 @@ local function check_form(form, host, port, path) if form["method"]=="post" then sending_function = function(data) return http.post(host, port, form_submission_path, nil, nil, data) end else - sending_function = function(data) return http.get(host, port, form_submission_path..generate_get_string(data), nil) end + sending_function = function(data) return http.get(host, port, form_submission_path.."?"..url.build_query(data), nil) end end for _,field in ipairs(form["fields"]) do @@ -208,7 +200,7 @@ function action(host, port) end --for end --if - -- now try inclusion by parameters + -- now try inclusion by query parameters local injectable = {} -- search for injectable links (as in sql-injection.nse) if r.response.status and r.response.body then diff --git a/scripts/http-sql-injection.nse b/scripts/http-sql-injection.nse index 41c4cfa18..dfd5275f1 100644 --- a/scripts/http-sql-injection.nse +++ b/scripts/http-sql-injection.nse @@ -102,7 +102,7 @@ local function build_injection_vector(urls) for k, v in pairs(qtab) do old_qtab = qtab[k]; - qtab[k] = qtab[k] .. "'%20OR%20sqlspider" + qtab[k] = qtab[k] .. "' OR sqlspider" utab.query = url.build_query(qtab) urlstr = url.build(utab) diff --git a/scripts/http-unsafe-output-escaping.nse b/scripts/http-unsafe-output-escaping.nse index c974d4f44..cdb373fcd 100644 --- a/scripts/http-unsafe-output-escaping.nse +++ b/scripts/http-unsafe-output-escaping.nse @@ -78,7 +78,7 @@ local function getReflected(parsed, r) end local function addPayload(v) - return v.."ghz%3Ehzx%22zxc%27xcv" + return v.."ghz>hzx\"zxc'xcv" end local function createMinedLinks(reflected_values, all_values)