coolbins/system/usr/share/nmap/scripts/membase-http-info.nse

152 lines
4.8 KiB
Lua

local _G = require "_G"
local http = require "http"
local json = require "json"
local shortport = require "shortport"
local stdnse = require "stdnse"
local table = require "table"
local tab = require "tab"
description = [[
Retrieves information (hostname, OS, uptime, etc.) from the CouchBase
Web Administration port. The information retrieved by this script
does not require any credentials.
]]
---
-- @usage
-- nmap -p 8091 <ip> --script membase-http-info
--
-- @output
-- PORT STATE SERVICE
-- 8091/tcp open unknown
-- | membase-http-info:
-- | Hostname 192.168.0.5:8091
-- | OS x86_64-unknown-linux-gnu
-- | Version 1.7.2r-20-g6604356
-- | Kernel version 2.14.4
-- | Mnesia version 4.4.19
-- | Stdlib version 1.17.4
-- | OS mon version 2.2.6
-- | NS server version 1.7.2r-20-g6604356
-- | SASL version 2.1.9.4
-- | Status healthy
-- | Uptime 21465
-- | Total memory 522022912
-- | Free memory 41779200
-- |_ Server list 192.168.0.5:11210
--
author = "Patrik Karlsson"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"}
portrule = shortport.port_or_service(8091, "http", "tcp")
local function fail(err) return stdnse.format_output(false, err) end
local filter = {
["parsed[1]['nodes'][1]['os']"] = { name = "OS" },
["parsed[1]['nodes'][1]['version']"] = { name = "Version" },
["parsed[1]['nodes'][1]['hostname']"] = { name = "Hostname" },
["parsed[1]['nodes'][1]['status']"] = { name = "Status" },
["parsed[1]['nodes'][1]['uptime']"] = { name = "Uptime" },
["parsed[1]['nodes'][1]['memoryTotal']"] = { name = "Total memory" },
["parsed[1]['nodes'][1]['memoryFree']"] = { name = "Free memory" },
["parsed[1]['vBucketServerMap']['serverList']"] = { name = "Server list" },
["parsed['componentsVersion']['kernel']"] = { name = "Kernel version" },
["parsed['componentsVersion']['mnesia']"] = { name = "Mnesia version" },
["parsed['componentsVersion']['stdlib']"] = { name = "Stdlib version" },
["parsed['componentsVersion']['os_mon']"] = { name = "OS mon version" },
["parsed['componentsVersion']['ns_server']"] = { name = "NS server version" },
["parsed['componentsVersion']['sasl']"] = { name = "SASL version" },
}
local order = {
"parsed[1]['nodes'][1]['hostname']",
"parsed[1]['nodes'][1]['os']",
"parsed[1]['nodes'][1]['version']",
"parsed['componentsVersion']['kernel']",
"parsed['componentsVersion']['mnesia']",
"parsed['componentsVersion']['stdlib']",
"parsed['componentsVersion']['os_mon']",
"parsed['componentsVersion']['ns_server']",
"parsed['componentsVersion']['sasl']",
"parsed[1]['nodes'][1]['status']",
"parsed[1]['nodes'][1]['uptime']",
"parsed[1]['nodes'][1]['memoryTotal']",
"parsed[1]['nodes'][1]['memoryFree']",
"parsed[1]['vBucketServerMap']['serverList']",
}
local function cmdReq(host, port, url, result)
local response = http.get(host, port, url)
if ( 200 ~= response.status ) or ( response.header['server'] == nil ) then
return false
end
if ( response.header['server'] and
not( response.header['server']:match("^Couchbase Server") or response.header['server']:match("^Membase Server") ) ) then
return false
end
local status, parsed = json.parse(response.body)
if ( not(status) ) then
return false, "Failed to parse response from server"
end
result = result or {}
for item in pairs(filter) do
local var, val = ""
for x in item:gmatch("(.-%])") do
var = var .. x
local env = setmetatable({parsed=parsed}, {__index = _G})
local func = load("return " .. var, nil, "t", env)
if ( not(func()) ) then
val = nil
break
end
val = func()
end
if ( val ) then
local name = filter[item].name
val = ( "table" == type(val) and table.concat(val, ",") or val )
result[item] = { name = name, value = val }
end
end
return true, result
end
action = function(host, port)
-- Identify servers that answer 200 to invalid HTTP requests and exit as these would invalidate the tests
local status_404, result_404, _ = http.identify_404(host,port)
if ( status_404 and result_404 == 200 ) then
stdnse.debug1("Exiting due to ambiguous response from web server on %s:%s. All URIs return status 200.", host.ip, port.number)
return nil
end
local urls = { "/pools/default/buckets", "/pools" }
local status, result
for _, u in ipairs(urls) do
status, result = cmdReq(host, port, u, result)
end
if ( not(result) or not(next(result)) ) then
return
end
local output = tab.new(2)
for _, item in ipairs(order) do
if ( result[item] ) then
tab.addrow(output, result[item].name, result[item].value)
end
end
return stdnse.format_output(true, tab.dump(output))
end