Nmap Development mailing list archives

New NSE Library: "datafiles" for parsing nmap-*


From: Kris Katterjohn <katterjohn () gmail com>
Date: Fri, 28 Mar 2008 01:24:22 -0500

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hey everyone,

You may recall that I converted Sven's rpcinfo.nse from using a huge RPC
table to reading from the nmap-rpc with nmap.fetchfile().  I figure his
script isn't the only one that will ever want to read from nmap-rpc, so
why not move it to nselib?  In fact, why not add parsing functions for
other nmap-* data files as well?

I've attached the following: a "datafiles" library (name subject to
change with any suggestions), another patch against rpcinfo.nse, and a
very crude but straightforward NSE script to show how the datafiles
library behaves (a lot of output!).

The datafiles library has the following, cleverly-named functions:
parse_protocols(), parse_rpc(), and parse_services([proto]).

datafiles.parse_protocols() returns a table with the protocol numbers
indexing the protocol names.  Uses nmap-protocols.

datafiles.parse_rpc() returns a table with the RPC numbers indexing the
RPC names.  Uses nmap-rpc.

datafiles.parse_services([proto]) typically returns a table in the form
{tcp={}, udp{}}.  tcp{} is a table with the TCP port numbers indexing
the service names.  udp{} is the same, but with UDP ports and services.
 You can also call this function with the specified protocol to only
return that table (e.g. datafiles.parse_services("tcp") only returns
tcp{}).  Uses nmap-services.

In addition to returning the previously discussed tables, these
functions also return true/false values for exception handling.  If
false is returned, an error message is returned instead of the table:

<true|false>, <table|error message> = datafiles.parse_*()


Please try it out and let me know what you think!  Any comments or
suggestions are appreciated.  All of this seems straightforward and
works fine for me, and hopefully it will for everyone else as well.

Thanks,
Kris Katterjohn

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iQIVAwUBR+yPFP9K37xXYl36AQK1jg/9FUGbGXFAEu5XJHF+iUuzSJly8T65iJ8T
g1Z30Uz8sqC6icux6zt3wAIreDLb47a5fRXyZh9dovtY9VgraJkDwfpGCZyZYpRt
XAFG09iKVVrcjyYsHHeHRnG8MaAma+S9JhfAbD1KeQtRZuTokh0ki4y/X5msixZJ
Ag6YQwE5J/+VgxOI/L3/PTAXCE8JCoQXClwlgnr4HKYTJM6FrK3EQFA8R+dk+O2e
PN7UqSlSAgnLBMxeuDr1jV6RRQ/QSiTjG11eXYn4Vja/J2nCHP7jLUVUZe4blqkE
AVOr9FqkUCtV82HhniDo3cNF1kWYnGV4y4YmGAM/Iz17vgbU2jTieNh5oCNFtubn
5FXNFfOJ7Xoz6ndlzoWkbpZR4353iXX96oa/+y5jyCr7e8o53cbeZNFPaXiwbYV+
bNPWzAAApfw18LVBrR7cy3AzXkBZ2WQrVClQlUruoAbR6V4slgjm3nCn8oLbv0Xp
j5tPGZqnQtkhoRzBKL2fb59Hd+Bx8pgMYiemFtV4lWviAPJsjCviwx3Ni4Vz54r9
6Q5D0SBUuce2zyklhb6JSX8vnj1eJhQbD2gHHjYIPcBCxogLpiLlfJ6AYwkMW5Qu
4UAZlk7wVGkXpa/+dKGzd6ctgV2mHbiHKasLJHRAkbM+WSoMm7eEL7s2/du1LZDe
u8zrHwnefok=
=fGfY
-----END PGP SIGNATURE-----
-- Kris Katterjohn 03/2008

module(..., package.seeall)

require 'stdnse'

-- These tables are filled by the following fill* functions
local protocols_table = {}
local rpc_table = {}
local services_table = {tcp={}, udp={}}

-- Fills protocols_table{} with values read from nmap-protocols
local fillprotocols = function()
        if #protocols_table ~= 0 then
                return true
        end

        local path = nmap.fetchfile("nmap-protocols")

        if path == nil then
                return false
        end

        local file = io.open(path, "r")

        -- Loops through Protocols file line-by-line
        while true do
                local l = file:read()

                if not l then
                        break
                end

                l = l:gsub("%s*#.*", "")

                if l:len() ~= 0 then
                        local m = l:gsub("^([%a%d_]+)%s+(%d+).*", "%2=%1")

                        if m:match("=") then
                                local t = stdnse.strsplit("=", m)
                                protocols_table[tonumber(t[1])] = t[2]
                        end
                end
        end

        file:close()

        return true
end

-- Fills rpc_table{} with values read from nmap-rpc
local fillrpc = function()
        if #rpc_table ~= 0 then
                return true
        end

        local path = nmap.fetchfile("nmap-rpc")

        if path == nil then
                return false
        end

        local file = io.open(path, "r")

        -- Loops through RPC file line-by-line
        while true do
                local l = file:read()

                if not l then
                        break
                end

                l = l:gsub("%s*#.*", "")

                if l:len() ~= 0 then
                        local m = l:gsub("^([%a%d_]+)%s+(%d+).*", "%2=%1")

                        if m:match("=") then
                                local t = stdnse.strsplit("=", m)
                                rpc_table[tonumber(t[1])] = t[2]
                        end
                end
        end

        file:close()

        return true
end

-- Fills services_table{} with values read from nmap-services
local fillservices = function()
        if #services_table["tcp"] ~= 0 or #services_table["udp"] ~= 0 then
                return true
        end

        local path = nmap.fetchfile("nmap-services")

        if path == nil then
                return false
        end

        local file = io.open(path, "r")

        -- Loops through Services file line-by-line
        while true do
                local l = file:read()

                if not l then
                        break
                end

                l = l:gsub("%s*#.*", "")

                if l:len() ~= 0 then
                        local m = l:gsub("^([%a%d_]+)%s+([%a%d/]+).*", "%2=%1")

                        if m:match("=") and m:match("/") then
                                local t = stdnse.strsplit("=", m)
                                local s = stdnse.strsplit("/", t[1])

                                if s[2] ~= "tcp" and s[2] ~= "udp" then
                                        services_table = {tcp={}, udp={}}
                                        return false
                                end

                                services_table[s[2]][tonumber(s[1])] = t[2]
                        end
                end
        end

        file:close()

        return true
end

parse_protocols = function()
        if not fillprotocols() then
                return false, "Error parsing nmap-protocols"
        end

        return true, protocols_table
end

parse_rpc = function()
        if not fillrpc() then
                return false, "Error parsing nmap-rpc"
        end

        return true, rpc_table
end

parse_services = function(protocol)
        if protocol and protocol ~= "tcp" and protocol ~= "udp" then
                return false, "Bad protocol for nmap-services: use tcp or udp"
        end

        if not fillservices() then
                return false, "Error parsing nmap-services"
        end

        if protocol then
                return true, services_table[protocol]
        else
                return true, services_table
        end
end

Index: scripts/rpcinfo.nse
===================================================================
--- scripts/rpcinfo.nse (revision 7012)
+++ scripts/rpcinfo.nse (working copy)
@@ -8,44 +8,8 @@
 require "shortport"
 require "packet"
 require "stdnse"
+require "datafiles"
 
-local rpc_numbers = {}
-
--- Fills rpc_numbers with values read from RPC file - Kris Katterjohn
-local fillrpc = function()
-       local path = nmap.fetchfile("nmap-rpc")
-
-       if path == nil then
-               return false, "Can't read from RPC file!"
-       end
-
-       local file = io.open(path, "r")
-
-       -- Loops through RPC file line-by-line
-       while true do
-               local l = file:read()
-
-               if not l then
-                       break
-               end
-
-               l = l:gsub("%s*#.*", "")
-
-               if l:len() ~= 0 then
-                       local m = l:gsub("^([%a%d_]+)%s+(%d+).*", "%2=%1")
-
-                       if m:match("=") then
-                               local t = stdnse.strsplit("=", m)
-                               rpc_numbers[tonumber(t[1])] = t[2]
-                       end
-               end
-       end
-
-       file:close()
-
-       return true
-end
-
 portrule = shortport.port_or_service(111, "rpcbind")
 
 action = function(host, port)
@@ -53,10 +17,11 @@
   local transaction_id = "nmap"
   local socket = nmap.new_socket()
   local result = " \n"
+  local rpc_numbers
 
   catch = function() socket:close() end
   try = nmap.new_try( catch )
-  try( fillrpc() )
+  rpc_numbers = try(datafiles.parse_rpc())
 
   local request = string.char(0x80,0,0,40) -- fragment header
   request = request .. transaction_id -- transaction id
id = "datafiles testing"

description = "datafiles testing"

author = "kris katterjohn"

license = "meh"

categories = {"safe"}

require 'datafiles'

hostrule = function()
        return true
end

action = function(host, port)
        local i, v
        local pret, protos = datafiles.parse_protocols()
        local rret, rpc = datafiles.parse_rpc()
        local sret, services = datafiles.parse_services()
        local tret, tcpservs = datafiles.parse_services("tcp")
        local uret, udpservs = datafiles.parse_services("udp")

        if not pret then
                return "uhoh protos"
        end

        if not rret then
                return "uhoh rpc"
        end

        if not sret then
                return "uhoh services"
        end

        if not tret then
                return "uhoh tcpservs"
        end

        if not uret then
                return "uhoh udpservs"
        end

        for i,v in pairs(protos) do
                print("protos: " .. i .. " " .. v)
        end

        for i,v in pairs(rpc) do
                print("rpc: " .. i .. " " .. v)
        end

        for i,v in pairs(services["tcp"]) do
                print("services[tcp]: " .. i .. " " .. v)
        end

        for i,v in pairs(services["udp"]) do
                print("services[udp]: " .. i .. " " .. v)
        end

        for i,v in pairs(tcpservs) do
                print("tcpservs: " .. i .. " " .. v)
        end

        for i,v in pairs(udpservs) do
                print("udpservs: " .. i .. " " .. v)
        end
end


_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://SecLists.Org

Current thread: