mirror of
https://github.com/nmap/nmap.git
synced 2025-12-07 13:11:28 +00:00
Add http-apache-server-status. Closes #322
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
# Nmap Changelog ($Id$); -*-text-*-
|
||||
|
||||
o [NSE][GH#322] Added http-apache-server-status for parsing the server status
|
||||
page of Apache's mod_status. [Eric Gershman]
|
||||
|
||||
o [NSE][GH#314] Fix naming of SSL2_RC2_128_CBC_WITH_MD5 and
|
||||
SSL2_RC2_128_CBC_EXPORT40_WITH_MD5 ciphers in sslv2 in order to match the
|
||||
draft specification from Mozilla. [Bertrand Bonnefoy-Claudet]
|
||||
|
||||
98
scripts/http-apache-server-status.nse
Normal file
98
scripts/http-apache-server-status.nse
Normal file
@@ -0,0 +1,98 @@
|
||||
local shortport = require "shortport"
|
||||
local http = require "http"
|
||||
local stdnse = require "stdnse"
|
||||
local string = require "string"
|
||||
local table = require "table"
|
||||
|
||||
description = [[
|
||||
Attempts to retrieve the server-status page for Apache webservers that
|
||||
have mod_status enabled. If the server-status page exists and appears to
|
||||
be from mod_status the script will parse useful information such as the
|
||||
system uptime, Apache version and recent HTTP requests.
|
||||
|
||||
References:
|
||||
* http://httpd.apache.org/docs/2.4/mod/mod_status.html
|
||||
* https://blog.sucuri.net/2012/10/popular-sites-with-apache-server-status-enabled.html
|
||||
* https://www.exploit-db.com/ghdb/1355/
|
||||
* https://github.com/michenriksen/nmap-scripts
|
||||
]]
|
||||
|
||||
---
|
||||
--@usage nmap -p80 --script http-apache-server-status <target>
|
||||
--@usage nmap -sV --script http-apache-server-status <target>
|
||||
--
|
||||
--@output
|
||||
-- PORT STATE SERVICE
|
||||
-- 80/tcp open http
|
||||
-- | http-apache-server-status:
|
||||
-- | Heading: Apache Server Status for example.com (via 127.0.1.1)
|
||||
-- | Server Version: Apache/2.4.12 (Ubuntu)
|
||||
-- | Server Built: Jul 24 2015 15:59:00
|
||||
-- | Server Uptime: 53 minutes 31 seconds
|
||||
-- | Server Load: 0.00 0.01 0.05
|
||||
-- | Requests:
|
||||
-- |_ www.example.com:80 GET /server-status HTTP/1.1
|
||||
--
|
||||
-- @xmloutput
|
||||
-- <elem key="Heading">Apache Server Status for example.com (via 127.0.1.1)</elem>
|
||||
-- <elem key="Server Version">Apache/2.4.12 (Ubuntu)</elem>
|
||||
-- <elem key="Server Built">Jul 24 2015 15:59:00</elem>
|
||||
-- <elem key="Server Uptime">59 minutes 26 seconds</elem>
|
||||
-- <elem key="Server Load">0.01 0.02 0.05</elem>
|
||||
-- <table key="Requests">
|
||||
-- <elem>www.example.com:80	GET /server-status HTTP/1.1</elem>
|
||||
-- </table>
|
||||
|
||||
author = "Eric Gershman"
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
categories = {"discovery", "safe"}
|
||||
|
||||
portrule = shortport.port_or_service({80, 443}, {"http","https"}, "tcp", "open")
|
||||
action = function(host, port)
|
||||
-- Perform a GET request for /server-status
|
||||
local path = "/server-status"
|
||||
local response = http.get(host,port,path)
|
||||
local result = {}
|
||||
|
||||
-- Fail if there is no data in the response, the response body or if the HTTP status code is not successful
|
||||
if not response or not response.status or response.status ~= 200 or not response.body then
|
||||
stdnse.debug(1, "Failed to retrieve: %s", path)
|
||||
return
|
||||
end
|
||||
|
||||
-- Fail if this doesn't appear to be an Apache mod_status page
|
||||
if not string.match(response.body, "Apache%sServer%sStatus") then
|
||||
stdnse.debug(1, "%s does not appear to be a mod_status page", path)
|
||||
return
|
||||
end
|
||||
|
||||
result = stdnse.output_table()
|
||||
|
||||
-- Remove line breaks from response.body to handle html tags that span multiple lines
|
||||
response.body = string.gsub(response.body, "\n", "")
|
||||
|
||||
-- Add useful data to the result table
|
||||
result["Heading"] = string.match(response.body, "<h1>([^<]*)</h1>")
|
||||
result["Server Version"] = string.match(response.body, "Server%sVersion:%s*([^<]*)</")
|
||||
result["Server Built"] = string.match(response.body, "Server%sBuilt:%s*([^<]*)</")
|
||||
result["Server Uptime"] = string.match(response.body, "Server%suptime:%s*([^<]*)</")
|
||||
result["Server Load"] = string.match(response.body, "Server%sload:%s*([^<]*)</")
|
||||
|
||||
result.Requests = {}
|
||||
local uniq_requests = {}
|
||||
|
||||
-- Parse the Apache client requests into the result table
|
||||
for line in string.gmatch(response.body, "<td nowrap>.-</td></tr>") do
|
||||
-- skip line if the request is empty
|
||||
if not string.match(line, "<td%snowrap></td><td%snowrap></td></tr>") then
|
||||
local request = string.match(line, ">([^<]*)</td><td") .. "\t" .. string.match(line, ">([^<]*)</td></tr>")
|
||||
uniq_requests[request] = 1
|
||||
end
|
||||
end
|
||||
for request,count in pairs(uniq_requests) do
|
||||
table.insert(result.Requests,request)
|
||||
end
|
||||
table.sort(result.Requests)
|
||||
|
||||
return result
|
||||
end
|
||||
Reference in New Issue
Block a user