mirror of
https://github.com/nmap/nmap.git
synced 2025-12-14 03:39:02 +00:00
o [NSE] Added a Versant object database library and the scripts
broadcast-versant-locate and versant-info. The first discovers Versant databases on the LAN and the second queries them for information. [Patrik]
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
# Nmap Changelog ($Id$); -*-text-*-
|
# Nmap Changelog ($Id$); -*-text-*-
|
||||||
|
|
||||||
|
o [NSE] Added a Versant object database library and the scripts
|
||||||
|
broadcast-versant-locate and versant-info. The first discovers Versant
|
||||||
|
databases on the LAN and the second queries them for information. [Patrik]
|
||||||
|
|
||||||
o [NSE] Added the library rpcap and the scripts rpcap-brute and rpcap-info
|
o [NSE] Added the library rpcap and the scripts rpcap-brute and rpcap-info
|
||||||
which perform brute force password guessing and extract information from the
|
which perform brute force password guessing and extract information from the
|
||||||
WinPcap Remote Packet Capture daemon. [Patrik]
|
WinPcap Remote Packet Capture daemon. [Patrik]
|
||||||
|
|||||||
279
nselib/versant.lua
Normal file
279
nselib/versant.lua
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
---
|
||||||
|
-- A tiny Versant library allowing some basic information enumeration.
|
||||||
|
-- The code is entirely based on packet dumps captured when using the Versant
|
||||||
|
-- Management Center administration application.
|
||||||
|
--
|
||||||
|
-- @author "Patrik Karlsson <patrik@cqure.net>"
|
||||||
|
--
|
||||||
|
|
||||||
|
module(... or "versant", package.seeall)
|
||||||
|
|
||||||
|
require 'match'
|
||||||
|
|
||||||
|
Versant = {
|
||||||
|
|
||||||
|
-- fallback to these constants when version and user are not given
|
||||||
|
USER = "nmap",
|
||||||
|
VERSION = "8.0.2",
|
||||||
|
|
||||||
|
-- Creates an instance of the Versant class
|
||||||
|
-- @param host table
|
||||||
|
-- @param port table
|
||||||
|
-- @return o new instance of Versant
|
||||||
|
new = function(self, host, port)
|
||||||
|
local o = { host = host, port = port, socket = nmap.new_socket() }
|
||||||
|
setmetatable(o, self)
|
||||||
|
self.__index = self
|
||||||
|
return o
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Connects a socket to the Versant server
|
||||||
|
-- @return status true on success, false on failure
|
||||||
|
-- @return err string containing the error message if status is false
|
||||||
|
connect = function(self)
|
||||||
|
return self.socket:connect(self.host, self.port)
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Closes the socket
|
||||||
|
-- @return status true on success, false on failure
|
||||||
|
-- @return err string containing the error message if status is false
|
||||||
|
close = function(self)
|
||||||
|
return self.socket:close()
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Sends command to the server
|
||||||
|
-- @param cmd string containing the command to run
|
||||||
|
-- @param arg string containing any arguments
|
||||||
|
-- @param user [optional] string containing the user name
|
||||||
|
-- @param ver [optional] string containing the version number
|
||||||
|
-- @return status true on success, false on failure
|
||||||
|
-- @return data opaque string containing the response
|
||||||
|
sendCommand = function(self, cmd, arg, user, ver)
|
||||||
|
|
||||||
|
user = user or Versant.USER
|
||||||
|
ver = ver or Versant.VERSION
|
||||||
|
arg = arg or ""
|
||||||
|
|
||||||
|
local data = bin.pack("H", "000100000000000000020002000000010000000000000000000000000000000000010000")
|
||||||
|
data = data .. cmd .. "\0" .. user .. "\0" .. ver .. "\0"
|
||||||
|
-- align to even 4 bytes
|
||||||
|
if ( #data % 4 ~= 0 ) then
|
||||||
|
for i=1, ( 4 - (#data % 4)) do
|
||||||
|
data = data .. "\0"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
data = data .. bin.pack("H", "0000000b000001000000000000000000")
|
||||||
|
data = data .. ("%s:%d\0"):format(self.host.ip, self.port.number)
|
||||||
|
data = data .. "\0\0\0\0\0\0\0\0\0\0" .. arg
|
||||||
|
|
||||||
|
while ( #data < 2048 ) do
|
||||||
|
data = data .. "\0"
|
||||||
|
end
|
||||||
|
|
||||||
|
local status, err = self.socket:send(data)
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, "Failed to send request to server"
|
||||||
|
end
|
||||||
|
|
||||||
|
local status, data = self.socket:receive_buf(match.numbytes(2048), true)
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, "Failed to read response from server"
|
||||||
|
end
|
||||||
|
|
||||||
|
return status, data
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Get database node information
|
||||||
|
-- @return status true on success, false on failure
|
||||||
|
-- @return result table containing an entry for each database. Each entry
|
||||||
|
-- contains a table with the following fields:
|
||||||
|
-- <code>name</code> - the database name
|
||||||
|
-- <code>owner</code> - the database owner
|
||||||
|
-- <code>created</code> - the date when the database was created
|
||||||
|
-- <code>version</code> - the database version
|
||||||
|
getNodeInfo = function(self)
|
||||||
|
local status, data = self:sendCommand("o_getnodeinfo", "-nodeinfo")
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, data
|
||||||
|
end
|
||||||
|
|
||||||
|
status, data = self.socket:receive_buf(match.numbytes(4), true)
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, "Failed to read response from server"
|
||||||
|
end
|
||||||
|
|
||||||
|
local _, db_count = bin.unpack(">I", data)
|
||||||
|
if ( db_count == 0 ) then
|
||||||
|
return false, "Database count was zero"
|
||||||
|
end
|
||||||
|
|
||||||
|
status, data = self.socket:receive_buf(match.numbytes(4), true)
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, "Failed to read response from server"
|
||||||
|
end
|
||||||
|
|
||||||
|
local _, buf_size = bin.unpack(">I", data)
|
||||||
|
local dbs = {}
|
||||||
|
|
||||||
|
for i=1, db_count do
|
||||||
|
status, data = self.socket:receive_buf(match.numbytes(buf_size), true)
|
||||||
|
local _, db = nil, {}
|
||||||
|
|
||||||
|
_, db.name = bin.unpack("z", data, 23)
|
||||||
|
_, db.owner = bin.unpack("z", data, 599)
|
||||||
|
_, db.created= bin.unpack("z", data, 631)
|
||||||
|
_, db.version= bin.unpack("z", data, 663)
|
||||||
|
|
||||||
|
-- remove trailing line-feed
|
||||||
|
db.created = db.created:match("^(.-)\n*$")
|
||||||
|
|
||||||
|
table.insert(dbs, db)
|
||||||
|
end
|
||||||
|
return true, dbs
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Gets the database OBE port, this port is dynamically allocated once this
|
||||||
|
-- command completes.
|
||||||
|
--
|
||||||
|
-- @return status true on success, false on failure
|
||||||
|
-- @return port table containing the OBE port
|
||||||
|
getObePort = function(self)
|
||||||
|
|
||||||
|
local status, data = self:sendCommand("o_oscp", "-utility")
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, data
|
||||||
|
end
|
||||||
|
|
||||||
|
status, data = self.socket:receive_buf(match.numbytes(256), true)
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, "Failed to read response from server"
|
||||||
|
end
|
||||||
|
|
||||||
|
local pos, success = bin.unpack(">I", data)
|
||||||
|
if ( success ~= 0 ) then
|
||||||
|
return false, "Response contained invalid data"
|
||||||
|
end
|
||||||
|
|
||||||
|
local port = { protocol = "tcp" }
|
||||||
|
pos, port.number = bin.unpack(">S", data, pos)
|
||||||
|
|
||||||
|
return true, port
|
||||||
|
end,
|
||||||
|
|
||||||
|
|
||||||
|
-- Get's the XML license file from the database
|
||||||
|
-- @return status true on success, false on failure
|
||||||
|
-- @return data string containing the XML license file
|
||||||
|
getLicense = function(self)
|
||||||
|
|
||||||
|
local status, data = self:sendCommand("o_licfile", "-license")
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, data
|
||||||
|
end
|
||||||
|
|
||||||
|
status, data = self.socket:receive_buf(match.numbytes(4), true)
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, "Failed to read response from server"
|
||||||
|
end
|
||||||
|
|
||||||
|
local _, len = bin.unpack(">I", data)
|
||||||
|
if ( len == 0 ) then
|
||||||
|
return false, "Failed to retrieve license file"
|
||||||
|
end
|
||||||
|
|
||||||
|
status, data = self.socket:receive_buf(match.numbytes(len), true)
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, "Failed to read response from server"
|
||||||
|
end
|
||||||
|
|
||||||
|
return true, data
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Gets the TCP port for a given database
|
||||||
|
-- @param db string containing the database name
|
||||||
|
-- @return status true on success, false on failure
|
||||||
|
-- @return port table containing the database port
|
||||||
|
getDbPort = function(self, db)
|
||||||
|
local status, data = self:sendCommand(db, "")
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, data
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, "Failed to connect to database"
|
||||||
|
end
|
||||||
|
|
||||||
|
local _, port = nil, { protocol = "tcp" }
|
||||||
|
_, port.number = bin.unpack(">I", data, 27)
|
||||||
|
if ( port == 0 ) then
|
||||||
|
return false, "Failed to determine database port"
|
||||||
|
end
|
||||||
|
return true, port
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
Versant.OBE = {
|
||||||
|
|
||||||
|
-- Creates a new versant OBE instance
|
||||||
|
-- @param host table
|
||||||
|
-- @param port table
|
||||||
|
-- @return o new instance of Versant OBE
|
||||||
|
new = function(self, host, port)
|
||||||
|
local o = { host = host, port = port, socket = nmap.new_socket() }
|
||||||
|
setmetatable(o, self)
|
||||||
|
self.__index = self
|
||||||
|
return o
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Connects a socket to the Versant server
|
||||||
|
-- @return status true on success, false on failure
|
||||||
|
-- @return err string containing the error message if status is false
|
||||||
|
connect = function(self)
|
||||||
|
return self.socket:connect(self.host, self.port)
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Closes the socket
|
||||||
|
-- @return status true on success, false on failure
|
||||||
|
-- @return err string containing the error message if status is false
|
||||||
|
close = function(self)
|
||||||
|
return self.socket:close()
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Get database information including file paths and hostname
|
||||||
|
-- @return status true on success false on failure
|
||||||
|
-- @return result table containing the fields:
|
||||||
|
-- <code>root_path</code> - the database root directory
|
||||||
|
-- <code>db_path</code> - the database directory
|
||||||
|
-- <code>lib_path</code> - the library directory
|
||||||
|
-- <code>hostname</code> - the database host name
|
||||||
|
getVODInfo = function(self)
|
||||||
|
local data = bin.pack("H", "1002005d00000000000100000000000d000000000000000000000000")
|
||||||
|
data = data .. "-noprint -i "
|
||||||
|
|
||||||
|
while( #data < 256 ) do
|
||||||
|
data = data .. "\0"
|
||||||
|
end
|
||||||
|
|
||||||
|
self.socket:send(data)
|
||||||
|
local status, data = self.socket:receive_buf(match.numbytes(256), true)
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, "Failed to read response from server"
|
||||||
|
end
|
||||||
|
|
||||||
|
local pos, len = bin.unpack(">I", data, 13)
|
||||||
|
status, data = self.socket:receive_buf(match.numbytes(len), true)
|
||||||
|
if ( not(status) ) then
|
||||||
|
return false, "Failed to read response from server"
|
||||||
|
end
|
||||||
|
|
||||||
|
local result, pos, offset = {}, 1, 13
|
||||||
|
pos, result.version = bin.unpack("z", data)
|
||||||
|
|
||||||
|
for _, item in ipairs({"root_path", "db_path", "lib_path", "hostname"}) do
|
||||||
|
pos, result[item] = bin.unpack("z", data, offset)
|
||||||
|
offset = offset + 256
|
||||||
|
end
|
||||||
|
return true, result
|
||||||
|
end,
|
||||||
|
}
|
||||||
35
scripts/broadcast-versant-locate.nse
Normal file
35
scripts/broadcast-versant-locate.nse
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
description = [[
|
||||||
|
Discovers Versant object databases using the srvloc protocol
|
||||||
|
]]
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @usage
|
||||||
|
-- nmap --script broadcast-versant-locate
|
||||||
|
--
|
||||||
|
-- @output
|
||||||
|
-- Pre-scan script results:
|
||||||
|
-- | broadcast-versant-locate:
|
||||||
|
-- |_ vod://192.168.200.222:5019
|
||||||
|
--
|
||||||
|
|
||||||
|
|
||||||
|
author = "Patrik Karlsson"
|
||||||
|
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||||
|
categories = {"broadcast", "safe"}
|
||||||
|
|
||||||
|
require 'srvloc'
|
||||||
|
|
||||||
|
prerule = function() return true end
|
||||||
|
|
||||||
|
action = function()
|
||||||
|
local helper = srvloc.Helper:new()
|
||||||
|
local status, result = helper:ServiceRequest("service:odbms.versant:vod", "default")
|
||||||
|
helper:close()
|
||||||
|
|
||||||
|
if ( not(status) ) then return end
|
||||||
|
local output = {}
|
||||||
|
for _, v in ipairs(result) do
|
||||||
|
table.insert(output, v:match("^service:odbms.versant:vod://(.*)$"))
|
||||||
|
end
|
||||||
|
return stdnse.format_output(true, output)
|
||||||
|
end
|
||||||
@@ -35,6 +35,7 @@ Entry { filename = "broadcast-rip-discover.nse", categories = { "broadcast", "sa
|
|||||||
Entry { filename = "broadcast-ripng-discover.nse", categories = { "broadcast", "safe", } }
|
Entry { filename = "broadcast-ripng-discover.nse", categories = { "broadcast", "safe", } }
|
||||||
Entry { filename = "broadcast-sybase-asa-discover.nse", categories = { "broadcast", "safe", } }
|
Entry { filename = "broadcast-sybase-asa-discover.nse", categories = { "broadcast", "safe", } }
|
||||||
Entry { filename = "broadcast-upnp-info.nse", categories = { "broadcast", "safe", } }
|
Entry { filename = "broadcast-upnp-info.nse", categories = { "broadcast", "safe", } }
|
||||||
|
Entry { filename = "broadcast-versant-locate.nse", categories = { "broadcast", "safe", } }
|
||||||
Entry { filename = "broadcast-wake-on-lan.nse", categories = { "broadcast", "safe", } }
|
Entry { filename = "broadcast-wake-on-lan.nse", categories = { "broadcast", "safe", } }
|
||||||
Entry { filename = "broadcast-wpad-discover.nse", categories = { "broadcast", "safe", } }
|
Entry { filename = "broadcast-wpad-discover.nse", categories = { "broadcast", "safe", } }
|
||||||
Entry { filename = "broadcast-wsdd-discover.nse", categories = { "broadcast", "safe", } }
|
Entry { filename = "broadcast-wsdd-discover.nse", categories = { "broadcast", "safe", } }
|
||||||
@@ -322,6 +323,7 @@ Entry { filename = "tftp-enum.nse", categories = { "discovery", "intrusive", } }
|
|||||||
Entry { filename = "unusual-port.nse", categories = { "safe", } }
|
Entry { filename = "unusual-port.nse", categories = { "safe", } }
|
||||||
Entry { filename = "upnp-info.nse", categories = { "default", "discovery", "safe", } }
|
Entry { filename = "upnp-info.nse", categories = { "default", "discovery", "safe", } }
|
||||||
Entry { filename = "url-snarf.nse", categories = { "safe", } }
|
Entry { filename = "url-snarf.nse", categories = { "safe", } }
|
||||||
|
Entry { filename = "versant-info.nse", categories = { "discovery", "safe", } }
|
||||||
Entry { filename = "vmauthd-brute.nse", categories = { "brute", "intrusive", } }
|
Entry { filename = "vmauthd-brute.nse", categories = { "brute", "intrusive", } }
|
||||||
Entry { filename = "vnc-brute.nse", categories = { "brute", "intrusive", } }
|
Entry { filename = "vnc-brute.nse", categories = { "brute", "intrusive", } }
|
||||||
Entry { filename = "vnc-info.nse", categories = { "default", "discovery", "safe", } }
|
Entry { filename = "vnc-info.nse", categories = { "default", "discovery", "safe", } }
|
||||||
|
|||||||
110
scripts/versant-info.nse
Normal file
110
scripts/versant-info.nse
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
description = [[
|
||||||
|
Extracts information, including file paths, version and database names from
|
||||||
|
a Versant object database.
|
||||||
|
]]
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @usage
|
||||||
|
-- nmap -p 5019 <ip> --script versant-info
|
||||||
|
--
|
||||||
|
-- @output
|
||||||
|
-- PORT STATE SERVICE REASON
|
||||||
|
-- 5019/tcp open versant syn-ack
|
||||||
|
-- | versant-info:
|
||||||
|
-- | Hostname: WIN-S6HA7RJFAAR
|
||||||
|
-- | Root path: C:\Versant\8
|
||||||
|
-- | Database path: C:\Versant\db
|
||||||
|
-- | Library path: C:\Versant\8
|
||||||
|
-- | Version: 8.0.2
|
||||||
|
-- | Databases
|
||||||
|
-- | FirstDB@WIN-S6HA7RJFAAR:5019
|
||||||
|
-- | Created: Sat Mar 03 12:00:02 2012
|
||||||
|
-- | Owner: Administrator
|
||||||
|
-- | Version: 8.0.2
|
||||||
|
-- | SecondDB@WIN-S6HA7RJFAAR:5019
|
||||||
|
-- | Created: Sat Mar 03 03:44:10 2012
|
||||||
|
-- | Owner: Administrator
|
||||||
|
-- | Version: 8.0.2
|
||||||
|
-- | ThirdDB@WIN-S6HA7RJFAAR:5019
|
||||||
|
-- | Created: Sun Mar 04 02:20:21 2012
|
||||||
|
-- | Owner: Administrator
|
||||||
|
-- |_ Version: 8.0.2
|
||||||
|
--
|
||||||
|
|
||||||
|
require 'shortport'
|
||||||
|
require 'versant'
|
||||||
|
|
||||||
|
author = "Patrik Karlsson"
|
||||||
|
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||||
|
categories = {"discovery", "safe"}
|
||||||
|
|
||||||
|
portrule = shortport.port_or_service(5019, "versant", "tcp")
|
||||||
|
|
||||||
|
local function fail(err) return ("\n ERROR: %s"):format(err or "") end
|
||||||
|
|
||||||
|
action = function(host, port)
|
||||||
|
|
||||||
|
local v = versant.Versant:new(host, port)
|
||||||
|
local status = v:connect()
|
||||||
|
if ( not(status) ) then
|
||||||
|
return fail("Failed to connect to server")
|
||||||
|
end
|
||||||
|
|
||||||
|
local status, newport = v:getObePort()
|
||||||
|
if ( not(status) ) then
|
||||||
|
return fail("Failed to retrieve OBE port")
|
||||||
|
end
|
||||||
|
v:close()
|
||||||
|
|
||||||
|
v = versant.Versant.OBE:new(host, newport)
|
||||||
|
status = v:connect()
|
||||||
|
if ( not(status) ) then
|
||||||
|
return fail("Failed to connect to server")
|
||||||
|
end
|
||||||
|
|
||||||
|
status, result = v:getVODInfo()
|
||||||
|
if ( not(status) ) then
|
||||||
|
return fail("Failed to get VOD information")
|
||||||
|
end
|
||||||
|
v:close()
|
||||||
|
|
||||||
|
local output = {}
|
||||||
|
|
||||||
|
table.insert(output, ("Hostname: %s"):format(result.hostname))
|
||||||
|
table.insert(output, ("Root path: %s"):format(result.root_path))
|
||||||
|
table.insert(output, ("Database path: %s"):format(result.db_path))
|
||||||
|
table.insert(output, ("Library path: %s"):format(result.lib_path))
|
||||||
|
table.insert(output, ("Version: %s"):format(result.version))
|
||||||
|
|
||||||
|
port.version.product = "Versant Database"
|
||||||
|
port.version.name = "versant"
|
||||||
|
nmap.set_port_version(host, port, "hardmatched")
|
||||||
|
|
||||||
|
-- the script may fail after this part, but we want to report at least
|
||||||
|
-- the above information if that's the case.
|
||||||
|
|
||||||
|
v = versant.Versant:new(host, port)
|
||||||
|
status = v:connect()
|
||||||
|
if ( not(status) ) then
|
||||||
|
return stdnse.format_output(true, output)
|
||||||
|
end
|
||||||
|
|
||||||
|
status, result = v:getNodeInfo()
|
||||||
|
if ( not(status) ) then
|
||||||
|
return stdnse.format_output(true, output)
|
||||||
|
end
|
||||||
|
v:close()
|
||||||
|
|
||||||
|
local databases = { name = "Databases" }
|
||||||
|
|
||||||
|
for _, db in ipairs(result) do
|
||||||
|
local db_tbl = { name = db.name }
|
||||||
|
table.insert(db_tbl, ("Created: %s"):format(db.created))
|
||||||
|
table.insert(db_tbl, ("Owner: %s"):format(db.owner))
|
||||||
|
table.insert(db_tbl, ("Version: %s"):format(db.version))
|
||||||
|
table.insert(databases, db_tbl)
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(output, databases)
|
||||||
|
return stdnse.format_output(true, output)
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user