1
0
mirror of https://github.com/nmap/nmap.git synced 2026-01-04 13:49:03 +00:00

AUTH_UNIX support for rpc.lua.

http://seclists.org/nmap-dev/2012/q2/54

This patch is from Daniel Miller. He writes:

I've just finished enhancing the nfs-ls, nfs-statfs, and nfs-showmount
scripts so that they can run based on version detection information,
for cases where the portmapper is firewalled. For nfs-ls and
nfs-statfs, this required making a hostrule to check that both a
mountd service and a nfs service were detected. In the process, I
ended up adding the AUTH_UNIX flavor to rpc.lua, since the RFC states
that AUTH_NULL can only be used for the NULL procedure (and my Linux
nfs-kernel-server was enforcing that).

Other minor changes:

* If running privileged, attempt to bind to a reserved port. Many NFS
servers refuse to talk to source ports >1024, as a "security measure"
* handle an odd case in nfs-ls where READDIRPLUS does not return file
attributes. Chose to use all ?'s, but in the future maybe a direct
GETATTR call?
* remove reference to nfs.dirlist argument from nfs-ls doc, since it is unused
This commit is contained in:
david
2012-06-20 02:12:58 +00:00
parent be24e6d5c4
commit 360ba052e9
5 changed files with 331 additions and 41 deletions

View File

@@ -4,6 +4,7 @@ local stdnse = require "stdnse"
local string = require "string"
local tab = require "tab"
local table = require "table"
local nmap = require "nmap"
description = [[
Attempts to get useful information about files from NFS exports.
@@ -55,8 +56,7 @@ These access permissions are shown only with NFSv3:
-- |_ lrwxrwxrwx 1000 1002 8 2010-06-10 08:34 symlink
--
-- @args nfs-ls.maxfiles If set, limits the amount of files returned by
-- the script when using the <code>nfs-ls.dirlist</code> argument.
-- If set to 0
-- the script. If set to 0
-- or less, all files are shown. The default value is 10.
-- @args nfs-ls.human If set to <code>1</code> or <code>true</code>,
-- shows file sizes in a human readable format with suffixes like
@@ -88,19 +88,57 @@ categories = {"discovery", "safe"}
portrule = shortport.port_or_service(111, "rpcbind", {"tcp", "udp"} )
local mountport = nil
local nfsport = nil
hostrule = function(host)
for _,proto in ipairs({"tcp","udp"}) do
local port = nmap.get_ports(host, nil, proto, "open")
while port do
if port.version then
if port.service == "mountd" then
mountport = port
elseif port.service == "nfs" then
nfsport = port
end
end
if mountport and nfsport then break end
port = nmap.get_ports(host, port, proto, "open")
end
if mountport and nfsport then break end
end
if nfsport == nil then return false end
if nfsport.version.rpc_highver == 4 and nfsport.version.rpc_lowver <= 3 then
nfsport.version.rpc_goodver = 3
else
nfsport.version.rpc_goodver = nfsport.version.rpc_highver
end
return (mountport and nfsport)
end
local procedures = { }
local function table_attributes(nfs, mount, attr)
local file = {}
file.type = rpc.Util.FtypeToChar(attr.mode)
file.mode = rpc.Util.FpermToString(attr.mode)
file.uid = tostring(attr.uid)
file.gid = tostring(attr.gid)
if nfs.human then
file.size = rpc.Util.SizeToHuman(attr.size)
if attr.mode then
file.type = rpc.Util.FtypeToChar(attr.mode)
file.mode = rpc.Util.FpermToString(attr.mode)
file.uid = tostring(attr.uid)
file.gid = tostring(attr.gid)
if nfs.human then
file.size = rpc.Util.SizeToHuman(attr.size)
else
file.size = tostring(attr.size)
end
file.time = rpc.Util.TimeToString(attr[nfs.time].seconds)
else
file.size = tostring(attr.size)
file.type = '?'
file.mode = '?????????'
file.uid = '?'
file.gid = '?'
file.size = '?'
file.time = '?'
end
file.time = rpc.Util.TimeToString(attr[nfs.time].seconds)
file.filename = mount
return file
@@ -145,12 +183,12 @@ local function nfs_ls(nfs, mount, results, access)
local nfsobj = rpc.NFS:new()
local mnt_comm, nfs_comm, fhandle
mnt_comm, fhandle = rpc.Helper.MountPath(nfs.host, nfs.port, mount)
mnt_comm, fhandle = procedures.MountPath(nfs.host, mount)
if mnt_comm == nil then
return false, fhandle
end
local nfs_comm, status = rpc.Helper.NfsOpen(nfs.host, nfs.port)
local nfs_comm, status = procedures.NfsOpen(nfs.host)
if nfs_comm == nil then
rpc.Helper.UnmountPath(mnt_comm, mount)
return false, status
@@ -243,12 +281,11 @@ local function report(nfs, table)
return tab.dump(outtab)
end
action = function(host, port)
local mainaction = function(host)
local o, results, mounts, status = {}, {}, {}
local nfs_info =
{
host = host,
port = port,
--recurs = tonumber(nmap.registry.args['nfs-ls.recurs']) or 1,
}
@@ -275,9 +312,13 @@ action = function(host, port)
table.insert(o, args)
end
status, mounts = rpc.Helper.ShowMounts(nfs_info.host, nfs_info.port)
status, mounts = procedures.ShowMounts(nfs_info.host)
if not status or mounts == nil then
return stdnse.format_output(false, mounts)
if mounts then
return stdnse.format_output(false, mounts)
else
return stdnse.format_output(false, "Mount error")
end
end
for _, v in ipairs(mounts) do
@@ -298,3 +339,85 @@ action = function(host, port)
return stdnse.format_output(true, o)
end
hostaction = function(host)
procedures = {
ShowMounts = function(ahost)
local mnt_comm, status, result, mounts
local mnt = rpc.Mount:new()
mnt_comm = rpc.Comm:new('mountd', mountport.version.rpc_highver)
status, result = mnt_comm:Connect(ahost, mountport)
if ( not(status) ) then
stdnse.print_debug(4, "ShowMounts: %s", result)
return false, result
end
status, mounts = mnt:Export(mnt_comm)
mnt_comm:Disconnect()
if ( not(status) ) then
stdnse.print_debug(4, "ShowMounts: %s", mounts)
end
return status, mounts
end,
MountPath = function(ahost, path)
local fhandle, status, err
local mountd, mnt_comm
local mnt = rpc.Mount:new()
mnt_comm = rpc.Comm:new("mountd", mountport.version.rpc_highver)
status, err = mnt_comm:Connect(host, mountport)
if not status then
stdnse.print_debug(4, "MountPath: %s", err)
return nil, err
end
status, fhandle = mnt:Mount(mnt_comm, path)
if not status then
mnt_comm:Disconnect()
stdnse.print_debug(4, "MountPath: %s", fhandle)
return nil, fhandle
end
return mnt_comm, fhandle
end,
NfsOpen = function(ahost)
local nfs_comm, status, err
nfs_comm = rpc.Comm:new('nfs', nfsport.version.rpc_goodver)
status, err = nfs_comm:Connect(host, nfsport)
if not status then
stdnse.print_debug(4, "NfsOpen: %s", err)
return nil, err
end
return nfs_comm, nil
end,
}
return mainaction(host)
end
portaction = function(host, port)
procedures = {
ShowMounts = function(ahost)
return rpc.Helper.ShowMounts(ahost, port)
end,
MountPath = function(ahost, path)
return rpc.Helper.MountPath(ahost, port, path)
end,
NfsOpen = function(ahost)
return rpc.Helper.NfsOpen(ahost, port)
end,
}
return mainaction(host)
end
local ActionsTable = {
-- portrule: use rpcbind service
portrule = portaction,
-- hostrule: Talk to services directly
hostrule = hostaction
}
action = function(...) return ActionsTable[SCRIPT_TYPE](...) end

View File

@@ -32,14 +32,34 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"}
portrule = shortport.port_or_service(111, "rpcbind", {"tcp", "udp"} )
portrule = shortport.port_or_service(111, {"rpcbind", "mountd"}, {"tcp", "udp"} )
local function get_exports(host, port)
local mnt = rpc.Mount:new()
mnt_comm = rpc.Comm:new('mountd', port.version.rpc_highver)
status, result = mnt_comm:Connect(host, port)
if ( not(status) ) then
stdnse.print_debug(4, "get_exports: %s", result)
return false, result
end
status, mounts = mnt:Export(mnt_comm)
mnt_comm:Disconnect()
if ( not(status) ) then
stdnse.print_debug(4, "get_exports: %s", mounts)
end
return status, mounts
end
action = function(host, port)
local status, mounts, proto
local result = {}
status, mounts = rpc.Helper.ShowMounts( host, port )
if port.service == "mountd" then
status, mounts = get_exports( host, port )
else
status, mounts = rpc.Helper.ShowMounts( host, port )
end
if not status or mounts == nil then
return stdnse.format_output(false, mounts)

View File

@@ -4,6 +4,7 @@ local stdnse = require "stdnse"
local string = require "string"
local tab = require "tab"
local table = require "table"
local nmap = require "nmap"
description = [[
Retrieves disk space statistics and information from a remote NFS share.
@@ -40,6 +41,35 @@ categories = {"discovery", "safe"}
portrule = shortport.port_or_service(111, "rpcbind", {"tcp", "udp"} )
local mountport = nil
local nfsport = nil
hostrule = function(host)
for _,proto in ipairs({"tcp","udp"}) do
local port = nmap.get_ports(host, nil, proto, "open")
while port do
if port.version then
if port.service == "mountd" then
mountport = port
elseif port.service == "nfs" then
nfsport = port
end
end
if mountport and nfsport then break end
port = nmap.get_ports(host, port, proto, "open")
end
if mountport and nfsport then break end
end
if nfsport == nil then return false end
if nfsport.version.rpc_highver == 4 and nfsport.version.rpc_lowver <= 3 then
nfsport.version.rpc_goodver = 3
else
nfsport.version.rpc_goodver = nfsport.version.rpc_highver
end
return (mountport and nfsport)
end
local procedures = { }
local function table_fsstat(nfs, mount, stats)
local fs, err = rpc.Util.calc_fsstat_table(stats, nfs.version, nfs.human)
if fs == nil then
@@ -111,12 +141,12 @@ local function nfs_filesystem_info(nfs, mount, filesystem)
local nfsobj = rpc.NFS:new()
local mnt_comm, nfs_comm, fhandle
mnt_comm, fhandle = rpc.Helper.MountPath(nfs.host, nfs.port, mount)
mnt_comm, fhandle = procedures.MountPath(nfs.host, mount)
if mnt_comm == nil then
return false, fhandle
end
local nfs_comm, status = rpc.Helper.NfsOpen(nfs.host, nfs.port)
local nfs_comm, status = procedures.NfsOpen(nfs.host)
if nfs_comm == nil then
rpc.Helper.UnmountPath(mnt_comm, mount)
return false, status
@@ -124,8 +154,8 @@ local function nfs_filesystem_info(nfs, mount, filesystem)
nfs.version = nfs_comm.version
-- use simple check since NFSv1 is not used anymore.
if (mnt_comm.version ~= nfs_comm.version) then
-- use simple check since NFSv1 is not used anymore, and NFSv4 not supported
if (nfs_comm.version <= 2 and mnt_comm.version > 2) then
rpc.Helper.UnmountPath(mnt_comm, mount)
return false, string.format("versions mismatch, nfs v%d - mount v%d",
nfs_comm.version, mnt_comm.version)
@@ -179,16 +209,15 @@ local function nfs_filesystem_info(nfs, mount, filesystem)
return true, nil
end
action = function(host, port)
mainaction = function(host)
local fs_info, mounts, status = {}, {}, {}
local nfs_info =
{
host = host,
port = port,
}
nfs_info.human = stdnse.get_script_args('nfs-statfs.human')
status, mounts = rpc.Helper.ShowMounts( host, port )
status, mounts = procedures.ShowMounts( host )
if (not(status)) then
return stdnse.format_output(false, mounts)
end
@@ -204,3 +233,85 @@ action = function(host, port)
return stdnse.format_output(true, report(nfs_info, fs_info))
end
hostaction = function(host)
procedures = {
ShowMounts = function(ahost)
local mnt_comm, status, result, mounts
local mnt = rpc.Mount:new()
mnt_comm = rpc.Comm:new('mountd', mountport.version.rpc_highver)
status, result = mnt_comm:Connect(ahost, mountport)
if ( not(status) ) then
stdnse.print_debug(4, "ShowMounts: %s", result)
return false, result
end
status, mounts = mnt:Export(mnt_comm)
mnt_comm:Disconnect()
if ( not(status) ) then
stdnse.print_debug(4, "ShowMounts: %s", mounts)
end
return status, mounts
end,
MountPath = function(ahost, path)
local fhandle, status, err
local mountd, mnt_comm
local mnt = rpc.Mount:new()
mnt_comm = rpc.Comm:new("mountd", mountport.version.rpc_highver)
status, err = mnt_comm:Connect(host, mountport)
if not status then
stdnse.print_debug(4, "MountPath: %s", err)
return nil, err
end
status, fhandle = mnt:Mount(mnt_comm, path)
if not status then
mnt_comm:Disconnect()
stdnse.print_debug(4, "MountPath: %s", fhandle)
return nil, fhandle
end
return mnt_comm, fhandle
end,
NfsOpen = function(ahost)
local nfs_comm, status, err
nfs_comm = rpc.Comm:new('nfs', nfsport.version.rpc_goodver)
status, err = nfs_comm:Connect(host, nfsport)
if not status then
stdnse.print_debug(4, "NfsOpen: %s", err)
return nil, err
end
return nfs_comm, nil
end,
}
return mainaction(host)
end
portaction = function(host, port)
procedures = {
ShowMounts = function(ahost)
return rpc.Helper.ShowMounts(ahost, port)
end,
MountPath = function(ahost, path)
return rpc.Helper.MountPath(ahost, port, path)
end,
NfsOpen = function(ahost)
return rpc.Helper.NfsOpen(ahost, port)
end,
}
return mainaction(host)
end
local ActionsTable = {
-- portrule: use rpcbind service
portrule = portaction,
-- hostrule: Talk to services directly
hostrule = hostaction
}
action = function(...) return ActionsTable[SCRIPT_TYPE](...) end