From 03639761c33d7108394e61a8fb9215b8a83f008b Mon Sep 17 00:00:00 2001 From: dmiller Date: Thu, 11 Oct 2018 05:11:13 +0000 Subject: [PATCH] Move in_port_range to shortport.port_range, expand portnumber to match ranges --- nselib/shortport.lua | 75 ++++++++++++++++++++++++++++++++++- nselib/stdnse.lua | 71 --------------------------------- scripts/backorifice-brute.nse | 14 +++---- scripts/banner.nse | 22 +++++----- 4 files changed, 88 insertions(+), 94 deletions(-) diff --git a/nselib/shortport.lua b/nselib/shortport.lua index 455a69b36..5da0ca101 100644 --- a/nselib/shortport.lua +++ b/nselib/shortport.lua @@ -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; diff --git a/nselib/stdnse.lua b/nselib/stdnse.lua index 3e6d171d2..e8f5fc2d1 100644 --- a/nselib/stdnse.lua +++ b/nselib/stdnse.lua @@ -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: --- in_port_range({number=31337,protocol="udp"},"T:15,50-75,U:31334-31339") --- 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=, 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 diff --git a/scripts/backorifice-brute.nse b/scripts/backorifice-brute.nse index 8b27174d2..9f8372493 100644 --- a/scripts/backorifice-brute.nse +++ b/scripts/backorifice-brute.nse @@ -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 diff --git a/scripts/banner.nse b/scripts/banner.nse index e8ec7f162..1482d16df 100644 --- a/scripts/banner.nse +++ b/scripts/banner.nse @@ -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 == "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 +if portarg then + if portarg == "common" then + portarg = "13,17,21-23,25,129,194,587,990,992,994,6667,6697" 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