From 5effe4c770113643a6a3903e7ddaf603899943f4 Mon Sep 17 00:00:00 2001 From: paulino Date: Mon, 27 Jun 2011 20:38:59 +0000 Subject: [PATCH] New version of http-trace. It addresses issues discussed: * http://seclists.org/nmap-dev/2010/q2/295 * http://seclists.org/nmap-dev/2007/q3/327 * http://seclists.org/nmap-dev/2007/q4/610 Features: * This version will always show you if TRACE is enabled (Current http-trace only shows headers that are different from the original response causing confusion in cases where TRACE is not reported as enabled because the host did not return any additional headers) * Supports redirects. --- scripts/http-trace.nse | 129 +++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 81 deletions(-) diff --git a/scripts/http-trace.nse b/scripts/http-trace.nse index 34b5b793a..56e44eab4 100644 --- a/scripts/http-trace.nse +++ b/scripts/http-trace.nse @@ -1,99 +1,66 @@ description = [[ -Sends an HTTP TRACE request and shows header fields that were modified in the -response. +Sends an HTTP TRACE request and shows if the method TRACE is enabled. If debug is enabled, it returns the header fields that were modified in the response. ]] --- +-- @usage +-- nmap --script http-trace -d +-- -- @output --- 80/tcp open http --- | http-trace: Response differs from request. First 5 additional lines: --- | Cookie: UID=d4287aa38d02f409841b4e0c0050c131... --- | Country: us --- | Ip_is_advertise_combined: yes --- | Ip_conntype-Confidence: -1 --- |_ Ip_line_speed: medium +-- 80/tcp open http syn-ack +-- | http-trace: TRACE is enabled +-- | Headers: +-- | Date: Tue, 14 Jun 2011 04:41:28 GMT +-- | Server: Apache +-- | Connection: close +-- | Transfer-Encoding: chunked +-- |_Content-Type: message/http +-- +-- @args http-trace.path Path to URI --- 08/31/2007 - -author = "Kris Katterjohn" +author = "Paulino Calderon" license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"discovery", "safe"} -require "comm" require "shortport" require "stdnse" - ---- Truncates and formats the first 5 elements of a table. ---@param tab The table to truncate. ---@return Truncated, formatted table. -local truncate = function(tab) - local str = "" - str = str .. tab[1] .. "\n" - str = str .. tab[2] .. "\n" - str = str .. tab[3] .. "\n" - str = str .. tab[4] .. "\n" - str = str .. tab[5] .. "\n" - return str -end - ---- Validates the HTTP response and checks for modifications. ---@param response The HTTP response from the server. ---@param original The original HTTP request sent to the server. ---@return A string describing the changes (if any) between the response and --- request. -local validate = function(response, original) - local start, stop - local body - - if not response:match("HTTP/1.[01] 200") or - not response:match("TRACE / HTTP/1.0") then - return - end - - start, stop = response:find("\r\n\r\n") - body = response:sub(stop + 1) - - if original ~= body then - local output = "Response differs from request. " - - if body:match("^TRACE / HTTP/1.0\r\n") then - local extra = body:sub(19) -- skip TRACE line - local tab = {} - - -- Skip extra newline at the end (making sure it's there) - extra = extra:gsub("\r\n\r\n$", "\r\n") - - tab = stdnse.strsplit("\r\n", extra) - - if #tab > 5 then - output = output .. "First 5 additional lines:\n" - return output .. truncate(tab) - end - - output = output .. "Additional lines:\n" - return output .. extra .. "\n" - end - - -- This shouldn't happen - - output = output .. "Full response:\n" - return output .. body .. "\n" - end - - return -end +require "http" portrule = shortport.http -action = function(host, port) - local cmd = "TRACE / HTTP/1.0\r\n\r\n" +--- Validates the HTTP response and returns header list +--@param response The HTTP response +--@param response_headers The HTTP response headers +local validate = function(response, response_headers) + local output_lines = {} - local sd, response = comm.tryssl(host, port, cmd, false) - if not sd then - stdnse.print_debug("Unable to open connection") - return - end - return validate(response, cmd) + if not(response:match("HTTP/1.[01] 200") or response:match("TRACE / HTTP/1.[01]")) then + return + else + output_lines[ #output_lines+1 ] = "TRACE is enabled" + end + if nmap.verbosity() >= 2 then + output_lines[ #output_lines+1 ]= "Headers:" + for _, value in pairs(response_headers) do + output_lines [ #output_lines+1 ] = value + end + end + if #output_lines > 0 then + return stdnse.strjoin("\n", output_lines) + end +end + +--- +--MAIN +--- +action = function(host, port) + local path = nmap.registry.args["http-trace.path"] or "/" + + local req = http.generic_request(host, port, "TRACE", path) + if (req.status == 301 or req.status == 302) and req.header["location"] then + req = http.generic_request(host, port, "TRACE", req.header["location"]) + end + return validate(req.body, req.rawheader) end