Adding my Datafiles NSElib for parsing the nmap-* data files for scripts and also update rpcinfo.nse to use this library. Includes CHANGELOG and docs/scripting.xml updates

This commit is contained in:
kris 2008-03-30 20:33:33 +00:00
parent 5f81cca485
commit 8530569047
4 changed files with 199 additions and 39 deletions

View file

@ -8,6 +8,12 @@ o Reformat Nmap COPYING file (e.g. remove C comment markers, reduce
when presented by the Windows executable (NSIS) installer. Thanks
to Jah for the patch (which was modified slightly by Fyodor).
o Added NSE Datafiles library which reads and parses Nmap's nmap-*
data files for scripts. The functions (parse_protocols(),
parse_rpc() and parse_services()) return tables with numbers
(e.g. port numbers) indexing names (e.g. service names). The
rpcinfo.nse script was also updated to use this library. [Kris]
o Changed the NSE function nmap.set_port_state() so that it checks to
see if the requested port is already in the requested state. This
prevents "Duplicate port" messages during the script scan and the

View file

@ -1399,6 +1399,68 @@ if(s) code_to_be_done_on_match end
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="nse-lib-datafiles">
<title>Data File Parsing Functions</title>
<para>
The <literal>datafiles</literal> module provides functions for reading and parsing
Nmap's data files (e.g. <filename>nmap-protocol</filename>, <filename>nmap-rpc</filename>,
etc.). These functions' return values are setup for use with exception handling via
<literal>nmap.new_try()</literal>.
</para>
<variablelist>
<varlistentry>
<term><option>bool, table = datafiles.parse_protocols()</option>
<indexterm><primary>parse_protocols</primary></indexterm></term>
<listitem>
<para>
This function reads and parses Nmap's <filename>nmap-protocols</filename>
file. <literal>bool</literal> is a boolen value indicating success.
If <literal>bool</literal> is true, then the second returned
value is a table with protocol numbers indexing the protocol
names. If <literal>bool</literal> is false, an error message
is returned as the second value instead of the table.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>bool, table = datafiles.parse_rpc()</option>
<indexterm><primary>parse_rpc</primary></indexterm></term>
<listitem>
<para>
This function reads and parses Nmap's <filename>nmap-rpc</filename>
file. <literal>bool</literal> is a boolen value indicating success.
If <literal>bool</literal> is true, then the second returned
value is a table with RPC numbers indexing the RPC names. If
<literal>bool</literal> is false, an error message is returned
as the second value instead of the table.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>bool, table = datafiles.parse_services([protocol])</option>
<indexterm><primary>parse_services</primary></indexterm></term>
<listitem>
<para>
This function reads and parses Nmap's <filename>nmap-services</filename>
file. <literal>bool</literal> is a boolen value indicating success.
If <literal>bool</literal> is true, then the second returned
value is a table containing two other tables:
<literal>tcp{}</literal> and <literal>udp{}</literal>.
<literal>tcp{}</literal> contains services indexed by TCP port
numbers. <literal>udp{}</literal> is the same, but for UDP.
You can pass "tcp" or "udp" as an argument to
<literal>parse_services()</literal> to only get the corresponding
table. If <literal>bool</literal> is false, an error message is
returned as the second value instead of the table.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="nse-lib-stdnse">
<title>Various Utility Functions</title>

128
nselib/datafiles.lua Normal file
View file

@ -0,0 +1,128 @@
-- 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 or rpc table with values read from the nmap-* files
local filltable = function(filename, table)
if #table ~= 0 then
return true
end
local path = nmap.fetchfile(filename)
if path == nil then
return false
end
local file = io.open(path, "r")
-- Loops through 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)
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 nmap-services 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 filltable("nmap-protocols", protocols_table) then
return false, "Error parsing nmap-protocols"
end
return true, protocols_table
end
parse_rpc = function()
if not filltable("nmap-rpc", rpc_table) 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]
end
return true, services_table
end

View file

@ -7,44 +7,7 @@ categories = {"safe","discovery"}
require "shortport"
require "packet"
require "stdnse"
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
require "datafiles"
portrule = shortport.port_or_service(111, "rpcbind")
@ -53,10 +16,11 @@ action = function(host, port)
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