1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00

Move in_port_range to shortport.port_range, expand portnumber to match ranges

This commit is contained in:
dmiller
2018-10-11 05:11:13 +00:00
parent 8c0880836c
commit 03639761c3
4 changed files with 88 additions and 94 deletions

View File

@@ -25,6 +25,29 @@ local function includes(t, value)
return false
end
-- Just like includes, but can match simple port ranges
local function port_includes(t, value)
for _, elem in ipairs(t) do
if elem == value then
return true
elseif type(elem) == "string" then
local pstart, pend = elem:match("^(%d+)%-(%d+)$")
if not pstart then
pstart = elem:match("^(%d+)$")
pend = pstart
end
pstart, pend = tonumber(pstart), tonumber(pend)
assert(pstart,"Incorrect port range specification.")
assert(pstart<=pend,"Incorrect port range specification, the starting port should have a smaller value than the ending port.")
assert(pstart>-1 and pend<65536, "Port range number out of range (0-65535).")
if value >= pstart and value <= pend then
return true
end
end
end
return false
end
--- Check if the port and its protocol are in the exclude directive.
--
-- @param port A port number.
@@ -60,7 +83,7 @@ portnumber = function(ports, protos, states)
end
return function(host, port)
return includes(ports, port.number)
return port_includes(ports, port.number)
and includes(protos, port.protocol)
and includes(states, port.state)
end
@@ -281,4 +304,54 @@ function ssl(host, port)
return false
end
--- Return a portrule that returns true when given an open port matching a port range
--
--@param range A port range string in Nmap standard format (ex. "T:80,1-30,U:31337,21-25")
--@return Function for the portrule.
function port_range(range)
assert(type(range)=="string" and range~="","Incorrect port range specification.")
local ports = {
tcp = {},
udp = {},
}
local proto = "both"
local pos = 1
repeat
local i, j, protspec = range:find("^%s*([TU:]+)", pos)
if i then
pos = j + 1
if protspec == "U:" then
proto = "udp"
elseif protspec == "T:" then
proto = "tcp"
else
assert(protspec == "", "Incorrect port range specification.")
end
end
repeat
local i, j, portspec = range:find("^%s*([%d%-]+),?", pos)
if not i then break end
pos = j + 1
portspec = tonumber(portspec) or portspec
if proto == "both" then
local ttab = ports.tcp
ttab[#ttab+1] = portspec
local utab = ports.udp
utab[#utab+1] = portspec
else
local ptab = ports[proto]
ptab[#ptab+1] = portspec
end
until pos >= #range
until pos >= #range
local tcp_rule = portnumber(ports.tcp, "tcp")
local udp_rule = portnumber(ports.udp, "udp")
return function(host, port)
return tcp_rule(host, port) or udp_rule(host, port)
end
end
return _ENV;

View File

@@ -944,77 +944,6 @@ do end -- no function here, see nse_main.lua
do end -- no function here, see nse_main.lua
---Checks if the port is in the port range
--
-- For example, calling:
-- <code>in_port_range({number=31337,protocol="udp"},"T:15,50-75,U:31334-31339")</code>
-- would result in a true value
--@param port a port structure containing keys port number(number) and protocol(string)
--@param port_range a port range string in Nmap standard format (ex. "T:80,1-30,U:31337,21-25")
--@returns boolean indicating whether the port is in the port range
function in_port_range(port,port_range)
assert(port and type(port.number)=="number" and type(port.protocol)=="string" and
(port.protocol=="udp" or port.protocol=="tcp"),"Port structure missing or invalid: port={ number=<port_number>, protocol=<port_protocol> }")
assert((type(port_range)=="string" or type(port_range)=="number") and port_range~="","Incorrect port range specification.")
-- Proto - true for TCP, false for UDP
local proto
if(port.protocol=="tcp") then proto = true else proto = false end
--TCP flag for iteration - true for TCP, false for UDP, if not specified we presume TCP
local tcp_flag = true
-- in case the port_range is a single number
if type(port_range)=="number" then
if proto and port_range==port.number then return true
else return false
end
end
--clean the string a bit
port_range=port_range:gsub("%s+","")
-- single_pr - single port range
for i, single_pr in ipairs(strsplit(",",port_range)) do
if single_pr:match("T:") then
tcp_flag = true
single_pr = single_pr:gsub("T:","")
else
if single_pr:match("U:") then
tcp_flag = false
single_pr = single_pr:gsub("U:","")
end
end
-- compare ports only when the port's protocol is the same as
-- the current single port range
if tcp_flag == proto then
local pone = single_pr:match("^(%d+)$")
if pone then
pone = tonumber(pone)
assert(pone>-1 and pone<65536, "Port range number out of range (0-65535).")
if pone == port.number then
return true
end
else
local pstart, pend = single_pr:match("^(%d+)%-(%d+)$")
pstart, pend = tonumber(pstart), tonumber(pend)
assert(pstart,"Incorrect port range specification.")
assert(pstart<=pend,"Incorrect port range specification, the starting port should have a smaller value than the ending port.")
assert(pstart>-1 and pstart<65536 and pend>-1 and pend<65536, "Port range number out of range (0-65535).")
if port.number >=pstart and port.number <= pend then
return true
end
end
end
end
-- if no match is found then the port doesn't belong to the port_range
return false
end
--- Module function that mimics some behavior of Lua 5.1 module function.
--
-- This convenience function returns a module environment to set the _ENV

View File

@@ -49,20 +49,16 @@ categories = {"intrusive", "brute"}
-- This portrule succeeds only when the open|filtered port is in the port range
-- which is specified by the ports script argument
portrule = function(host, port)
if not stdnse.get_script_args(SCRIPT_NAME .. ".ports") then
stdnse.debug3("Skipping '%s' %s, 'ports' argument is missing.",SCRIPT_NAME, SCRIPT_TYPE)
return false
end
local ports = stdnse.get_script_args(SCRIPT_NAME .. ".ports")
--print out a debug message if port 31337/udp is open
if port.number==31337 and port.protocol == "udp" and not(ports) then
stdnse.debug1("Port 31337/udp is open. Possibility of version detection and password bruteforcing using the backorifice-brute script")
if not ports then
stdnse.verbose1("Skipping '%s' %s, 'ports' argument is missing.",SCRIPT_NAME, SCRIPT_TYPE)
return false
end
return port.protocol == "udp" and stdnse.in_port_range(port, ports:gsub(",",",") ) and
-- ensure UDP
portarg = portarg:gsub("^[U:]*", "U:")
return port.protocol == "udp" and shortport.port_range(ports)(host, port) and
not(shortport.port_is_excluded(port.number,port.protocol))
end

View File

@@ -1,6 +1,7 @@
local comm = require "comm"
local nmap = require "nmap"
local stdnse = require "stdnse"
local shortport = require "shortport"
local table = require "table"
local U = require "lpeg-utility"
@@ -28,20 +29,15 @@ categories = {"discovery", "safe"}
local portarg = stdnse.get_script_args(SCRIPT_NAME .. ".ports")
if portarg then
if portarg == "common" then
portarg = "13,17,21-23,25,129,194,587,990,992,994,6667,6697"
end
---
-- Script is executed for any TCP port.
portrule = function( host, port )
if port.protocol == "tcp" then
if portarg then
return stdnse.in_port_range(port, portarg)
end
return true
end
return false
-- ensure TCP
portarg = portarg:gsub("^[T:]*", "T:")
portrule = shortport.port_range(portarg)
else
portrule = function(host, port) return port.protocol == "tcp" end
end