diff --git a/scripts/http-comments-displayer.nse b/scripts/http-comments-displayer.nse new file mode 100644 index 000000000..d69a2fd6a --- /dev/null +++ b/scripts/http-comments-displayer.nse @@ -0,0 +1,156 @@ +description = [[ +Extracts and outputs HTML/JS comments from HTTP responses. +]] + +--- +-- @usage nmap -p80 --script http-comments-displayer.nse +-- +-- This scripts uses patterns to extract HTML comments from HTTP +-- responses and writes these to the command line. +-- +-- @args http-comments-displayer.singlepages Some single pages +-- to check for comments. For example, {"/", "/wiki"}. +-- Default: nil (crawler mode on) +-- @args http-comments-displayer.context declares the number of chars +-- to extend our final strings. This is useful when we need to +-- to see the code that the comments are reffering to. +-- Default: 0, Maximum Value: 50 +-- +-- +-- @output +-- PORT STATE SERVICE REASON +-- 80/tcp open http syn-ack +-- | http-comments-displayer: +-- | Path: / +-- | Line number: 214 +-- | Comment: +-- | +-- | +-- | Path: /register.php +-- | Line number: 15 +-- | Comment: +-- |_ /* We should avoid the hardcoding here */ +-- +--- + +categories = {"discovery", "safe"} +author = "George Chatzisofroniou" +license = "Same as Nmap--See http://nmap.org/book/man-legal.html" + +local http = require "http" +local shortport = require "shortport" +local stdnse = require "stdnse" +local table = require "table" +local string = require "string" +local httpspider = require "httpspider" + +PATTERNS = { + "", -- HTML comment + "/%*.-%*/", -- Javascript multiline comment + "[ ,\n]//.-\n" -- Javascript one-line comment. Could be better? + } + +portrule = shortport.port_or_service( {80, 443}, {"http", "https"}, "tcp", "open") + +-- Returns comment's line number by counting the occurences of the +-- new line character ("\n") from the start of the HTML file until +-- the related comment. +local getLineNumber = function(body, comment) + + local partofresponse = body:find(comment, 1, true) + partofresponse = body:sub(0, partofresponse) + _, count = string.gsub(partofresponse, "\n", "\n") + + return count + 1 + +end + +action = function(host, port) + + local context = stdnse.get_script_args("http-comments-displayer.context") + local singlepages = stdnse.get_script_args("http-comments-displayer.singlepages") + + local comments = {} + + local crawler = httpspider.Crawler:new( host, port, '/', { scriptname = SCRIPT_NAME, withinhost = 1 } ) + + if (not(crawler)) then + return + end + + crawler:set_timeout(10000) + + if context then + if (tonumber(context) > 100) then + context = 100 + end + + -- Lua's abbreviated patterns support doesn't have a fixed-number-of-repetitions syntax. + for i, pattern in ipairs(PATTERNS) do + PATTERNS[i] = string.rep(".", context) .. PATTERNS[i] .. string.rep(".", context) + end + end + + local index, k, target, response, path + while (true) do + + if singlepages then + k, target = next(singlepages, index) + if (k == nil) then + break + end + response = http.get(host, port, target) + path = target + + else + status, r = crawler:crawl() + -- if the crawler fails it can be due to a number of different reasons + -- most of them are "legitimate" and should not be reason to abort + if (not(status)) then + if (r.err) then + return stdnse.format_output(true, ("ERROR: %s"):format(r.reason)) + else + break + end + end + + response = r.response + path = tostring(r.url) + end + + if response.body then + + for i, pattern in ipairs(PATTERNS) do + for c in string.gmatch(response.body, pattern) do + + local linenumber = getLineNumber(response.body, c) + + comments[c] = "\nPath: " .. path .. "\nLine number: " .. linenumber .. "\nComment: \n" + end + end + + if (index) then + index = index + 1 + else + index = 1 + end + end + + end + + -- If the table is empty. + if next(comments) == nil then + return "Couldn't find any comments." + end + + -- Create a nice output. + local results = {} + for c, _ in pairs(comments) do + table.insert(results, {_, {{c}}}) + end + + results.name = crawler:getLimitations() + + return stdnse.format_output(true, results) + +end