mirror of
https://github.com/nmap/nmap.git
synced 2026-09-27 02:29:42 +00:00
Add UDP support to memcached-info
This commit is contained in:
parent
502c082240
commit
4985033a3d
2 changed files with 98 additions and 46 deletions
|
|
@ -1,5 +1,9 @@
|
|||
#Nmap Changelog ($Id$); -*-text-*-
|
||||
|
||||
o [NSE] memcached-info can now gather information from the UDP memcached
|
||||
service in addition to the TCP service. The UDP service is frequently used as
|
||||
a DDoS reflector and amplifier. [Daniel Miller]
|
||||
|
||||
o [NSE][GH#1129] Changed url.absolute() behavior with respect to dot and
|
||||
dot-dot path segments to comply with RFC 3986, section 5.2. [nnposter]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
local nmap = require "nmap"
|
||||
local match = require "match"
|
||||
local math = require "math"
|
||||
local shortport = require "shortport"
|
||||
local stdnse = require "stdnse"
|
||||
local tab = require "tab"
|
||||
local string = require "string"
|
||||
local table = require "table"
|
||||
|
||||
description = [[
|
||||
Retrieves information (including system architecture, process ID, and
|
||||
|
|
@ -14,29 +16,40 @@ server time) from distributed memory object caching system memcached.
|
|||
-- nmap -p 11211 --script memcached-info
|
||||
--
|
||||
-- @output
|
||||
-- 11211/tcp open unknown
|
||||
-- 11211/udp open unknown
|
||||
-- | memcached-info:
|
||||
-- | Process ID 18568
|
||||
-- | Uptime 6950 seconds
|
||||
-- | Server time Sat Dec 31 14:16:10 2011
|
||||
-- | Architecture 64 bit
|
||||
-- | Used CPU (user) 0.172010
|
||||
-- | Used CPU (system) 0.200012
|
||||
-- | Current connections 10
|
||||
-- | Total connections 78
|
||||
-- | Maximum connections 1024
|
||||
-- | TCP Port 11211
|
||||
-- | UDP Port 11211
|
||||
-- |_ Authentication no
|
||||
-- | Process ID: 18568
|
||||
-- | Uptime: 6950 seconds
|
||||
-- | Server time: Sat Dec 31 14:16:10 2011
|
||||
-- | Architecture: 64 bit
|
||||
-- | Used CPU (user): 0.172010
|
||||
-- | Used CPU (system): 0.200012
|
||||
-- | Current connections: 10
|
||||
-- | Total connections: 78
|
||||
-- | Maximum connections: 1024
|
||||
-- | TCP Port: 11211
|
||||
-- | UDP Port: 11211
|
||||
-- |_ Authentication: no
|
||||
--
|
||||
-- @xmloutput
|
||||
-- <elem key="Process ID">17307</elem>
|
||||
-- <elem key="Uptime">10662 seconds</elem>
|
||||
-- <elem key="Server time">2018-03-01T16:46:59</elem>
|
||||
-- <elem key="Architecture">64 bit</elem>
|
||||
-- <elem key="Used CPU (user)">0.212809</elem>
|
||||
-- <elem key="Used CPU (system)">0.157151</elem>
|
||||
-- <elem key="Current connections">5</elem>
|
||||
-- <elem key="Total connections">11</elem>
|
||||
-- <elem key="Maximum connections">1024</elem>
|
||||
-- <elem key="TCP Port">11211</elem>
|
||||
-- <elem key="UDP Port">11211</elem>
|
||||
-- <elem key="Authentication">no</elem>
|
||||
|
||||
author = "Patrik Karlsson"
|
||||
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
|
||||
categories = {"discovery", "safe"}
|
||||
|
||||
|
||||
-- currently, we only support the TCP, text based protocol
|
||||
portrule = shortport.port_or_service(11211, "memcached", "tcp")
|
||||
portrule = shortport.port_or_service(11211, "memcached", {"tcp", "udp"})
|
||||
|
||||
local filter = {
|
||||
|
||||
|
|
@ -70,61 +83,96 @@ local function mergetab(tab1, tab2)
|
|||
return tab1
|
||||
end
|
||||
|
||||
local function recvResponse(socket)
|
||||
local kvs = {}
|
||||
repeat
|
||||
local status, response = socket:receive_buf(match.pattern_limit("\r\n", 2048), false)
|
||||
if ( not(status) ) then
|
||||
return false, "Failed to receive response from server"
|
||||
local Comm = {
|
||||
new = function(self, host, port, options)
|
||||
local o = { host = host, port = port, options = options or {}}
|
||||
self.protocol = port.protocol
|
||||
self.req_id = math.random(0,0xfff)
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end,
|
||||
connect = function(self)
|
||||
self.socket = nmap.new_socket(self.protocol)
|
||||
self.socket:set_timeout(self.options.timeout or stdnse.get_timeout(self.host))
|
||||
return self.socket:connect(self.host, self.port)
|
||||
end,
|
||||
exchange = function(self, data)
|
||||
local req_id = self.req_id
|
||||
self.req_id = req_id + 1
|
||||
if self.protocol == "udp" then
|
||||
data = string.pack(">I2 I2 I2 I2",
|
||||
req_id, -- request ID
|
||||
0, -- sequence number
|
||||
1, -- number of datagrams
|
||||
0 -- reserved, must be 0
|
||||
) .. data
|
||||
end
|
||||
local k,v = response:match("^STAT ([^%s]*) (.*)$")
|
||||
if ( k and v ) then
|
||||
kvs[k] = v
|
||||
local status = self.socket:send(data)
|
||||
if not status then
|
||||
return false, "Failed to send request to server"
|
||||
end
|
||||
if self.protocol == "udp" then
|
||||
local msgs = {}
|
||||
local dgrams = 0
|
||||
repeat
|
||||
local status, response = self.socket:receive_bytes(8)
|
||||
if not status then return false, "Failed to receive entire response" end
|
||||
local resp_id, seq, ndgrams, pos = string.unpack(">I2 I2 I2 xx", response)
|
||||
if resp_id == req_id then
|
||||
dgrams = ndgrams
|
||||
msgs[seq+1] = string.sub(response, pos)
|
||||
end
|
||||
until #msgs >= dgrams
|
||||
return true, table.concat(msgs)
|
||||
end
|
||||
until ( "END" == response or "ERROR" == response )
|
||||
|
||||
return true, kvs
|
||||
-- pattern matches ERR or ERROR at the beginning of a string or after a newline
|
||||
return self.socket:receive_buf(match.pattern_limit("%f[^\n\0]E[NR][DR]O?R?\r\n", 2048), true)
|
||||
end,
|
||||
}
|
||||
|
||||
local function parseResponse(response, expected)
|
||||
local kvs = {}
|
||||
for k, v in response:gmatch(("%%f[^\n\0]%s ([^%%s]*) (.-)\r\n"):format(expected)) do
|
||||
stdnse.debug1("k=%s, v=%s", k, v)
|
||||
kvs[k] = v
|
||||
end
|
||||
return kvs
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
|
||||
local socket = nmap.new_socket()
|
||||
socket:set_timeout(10000)
|
||||
local status = socket:connect(host, port)
|
||||
local client = Comm:new(host, port)
|
||||
local status = client:connect()
|
||||
if ( not(status) ) then
|
||||
return fail("Failed to connect to server")
|
||||
end
|
||||
|
||||
status = socket:send("stats\r\n")
|
||||
local status, response = client:exchange("stats\r\n")
|
||||
if ( not(status) ) then
|
||||
return fail("Failed to send request to server")
|
||||
return fail(("Failed to send request to server: %s"):format(response))
|
||||
end
|
||||
|
||||
local status, kvs = recvResponse(socket)
|
||||
if( not(status) ) then
|
||||
return fail(kvs)
|
||||
end
|
||||
local kvs = parseResponse(response, "STAT")
|
||||
|
||||
status = socket:send("stats settings\r\n")
|
||||
local status, response = client:exchange("stats settings\r\n")
|
||||
if ( not(status) ) then
|
||||
return fail("Failed to send request to server")
|
||||
return fail(("Failed to send request to server: %s"):format(response))
|
||||
end
|
||||
|
||||
local status, kvs2 = recvResponse(socket)
|
||||
if( not(status) ) then
|
||||
return fail(kvs2)
|
||||
end
|
||||
local kvs2 = parseResponse(response, "STAT")
|
||||
|
||||
kvs = mergetab(kvs, kvs2)
|
||||
|
||||
local result = tab.new(2)
|
||||
local result = stdnse.output_table()
|
||||
for _, item in ipairs(order) do
|
||||
if ( kvs[item] ) then
|
||||
local name = filter[item].name
|
||||
local val = ( filter[item].func and filter[item].func(kvs[item]) or kvs[item] )
|
||||
tab.addrow(result, name, val)
|
||||
result[name] = val
|
||||
end
|
||||
end
|
||||
return stdnse.format_output(true, tab.dump(result))
|
||||
return result
|
||||
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue