1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-10 09:49:05 +00:00

Rewrite http-methods.nse to use the http.generic_request function

instead of doing its own socket handling. Also make the output more
concise.
This commit is contained in:
david
2010-02-19 04:55:38 +00:00
parent bb2e8c439b
commit 650e639f1f

View File

@@ -15,13 +15,13 @@ individually to see if they are subject to e.g. IP address restrictions.
-- possible. -- possible.
-- --
-- @output -- @output
-- 80/tcp open http syn-ack Apache httpd 2.2.8 ((Ubuntu)) -- 80/tcp open http syn-ack
-- | HTTP allowed methods: according to OPTIONS request: GET,HEAD,POST,OPTIONS,TRACE -- | http-methods: GET,HEAD,POST,OPTIONS,TRACE
-- | HTTP Status for GET is 200 OK -- | GET / -> HTTP/1.1 200 OK
-- | HTTP Status for HEAD is 200 OK -- | HEAD / -> HTTP/1.1 200 OK
-- | HTTP Status for POST is 200 OK -- | POST / -> HTTP/1.1 200 OK
-- | HTTP Status for OPTIONS is 200 OK -- | OPTIONS / -> HTTP/1.1 200 OK
-- |_ HTTP Status for TRACE is 200 OK -- |_TRACE / -> HTTP/1.1 200 OK
-- --
-- @usage -- @usage
-- nmap --script=http-methods.nse --script-args http-methods.retest=1 <target> -- nmap --script=http-methods.nse --script-args http-methods.retest=1 <target>
@@ -33,7 +33,8 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"safe"} categories = {"safe"}
require "stdnse" require("http")
require("stdnse")
portrule = function(host, port) portrule = function(host, port)
if not (port.service == 'http' or port.service == 'https') if not (port.service == 'http' or port.service == 'https')
@@ -48,91 +49,49 @@ portrule = function(host, port)
return(true) return(true)
end end
--- cleanup function for HTTP response header
--
-- in multi line strings any lines after the first one are removed
-- if the first line contains HTTP protocol version and response code
-- only the response code itself is kept (removing "HTTP/1.? ")
-- @param some_string gives the (probably multi line) string to clean up,
-- normally a HTTP response header
-- @returns some_string as a clean string, single line
local cleanup = function(some_string)
if (some_string ~= nil)
then
some_string = string.gsub(some_string , "[\n\r].*", "")
some_string = string.gsub(some_string, "HTTP/[0-9]\.[0-9] ", "")
end
return(some_string)
end
action = function(host, port) action = function(host, port)
local socket, request, result, methods, protocol, output, httpstatus, methodsarray, i, own_httpstatus, url_path, retest_http_methods, try, catch, location local url_path, retest_http_methods
local response, methods, options_status_line, output
-- default vaules for script-args -- default vaules for script-args
url_path = nmap.registry.args["http-methods.url-path"] or "/" url_path = nmap.registry.args["http-methods.url-path"] or "/"
retest_http_methods = nmap.registry.args["http-methods.retest"] ~= nil retest_http_methods = nmap.registry.args["http-methods.retest"] ~= nil
catch = function() response = http.generic_request(host, port, "OPTIONS", url_path)
socket:close() if not response.status then
stdnse.print_debug("http-methods: OPTIONS %s failed.", url_path)
return
end end
try = nmap.new_try(catch) -- Cache in case retest is requested.
options_status_line = response["status-line"]
stdnse.print_debug("http-methods.nse: HTTP Status for OPTIONS is " .. response.status)
socket = nmap.new_socket() if not response.header["allow"] then
return string.format("No Allow header in OPTIONS response (status code %d)", response.status)
if (port.service == 'https' or port.version.service_tunnel == 'ssl')
then
protocol = "ssl"
else
protocol = "tcp"
end end
try(socket:connect(host.ip, port.number, protocol)) output = { response.header["allow"] }
request = "OPTIONS " .. url_path .. " HTTP/1.0\r\n\r\n"
try(socket:send(request))
result = try(socket:receive_lines(1))
socket:close()
own_httpstatus = cleanup(result)
stdnse.print_debug("http-methods.nse: HTTP Status for OPTIONS is " .. own_httpstatus)
methods = cleanup(string.match(result, "Allow: *(.+)[\n\r]"))
if (methods ~= nil)
then
-- got methods
output = "OPTIONS " .. url_path .. " request returned: " .. methods
else
-- got no methods
output = "OPTIONS " .. url_path .. " request returned no methods but response code " .. own_httpstatus
end
-- retest http methods if requested -- retest http methods if requested
if (retest_http_methods and methods ~= nil) if retest_http_methods then
then local methods = stdnse.strsplit(",%s*", response.header["allow"])
methodsarray = stdnse.strsplit(",", methods) local _
for i=1, #methodsarray, 1 for _, method in ipairs(methods) do
do local str
stdnse.print_debug("http-methods.nse: found method " .. i .. " " .. methodsarray[i]) if method == "OPTIONS" then
if (methodsarray[i] == 'OPTIONS') -- Use the saved value.
then str = options_status_line
stdnse.print_debug("http-methods.nse: no need to try method OPTIONS, using status of previous request");
output = output .. "\n HTTP Status for OPTIONS " .. url_path .. " is " .. own_httpstatus
else else
stdnse.print_debug("http-methods.nse: trying method " .. methodsarray[i] .. " on " .. protocol); response = http.generic_request(host, port, method, url_path)
if not response.status then
socket = nmap.new_socket() str = "Error getting response"
try(socket:connect(host.ip, port.number, protocol)) else
request = methodsarray[i] .. " " .. url_path .. " HTTP/1.0\r\n\r\n" str = response["status-line"]
try(socket:send(request)) end
httpstatus = cleanup(try(socket:receive_lines(1)))
socket:close()
stdnse.print_debug("http-methods.nse: HTTP Status for " .. methodsarray[i] .. " " .. url_path .. " is " .. httpstatus)
output = output .. "\n HTTP Status for " .. methodsarray[i] .. " " .. url_path .. " is " .. httpstatus
end end
output[#output + 1] = string.format("%s %s -> %s", method, url_path, str)
end end
end end
return(output) return stdnse.strjoin("\n", output)
end end