diff --git a/nselib/mssql.lua b/nselib/mssql.lua
index 1553806fe..466bd77fd 100644
--- a/nselib/mssql.lua
+++ b/nselib/mssql.lua
@@ -74,12 +74,19 @@
-- argument is not given but mssql.username, a blank password
-- is used.
--
--- @args mssql.instance-name The name of the instance to connect to.
+-- @args mssql.instance-name In addition to instances discovered via port
+-- scanning and version detection, run scripts on
+-- these named instances (string or list of strings)
--
--- @args mssql.instance-port The port of the instance to connect to.
+-- @args mssql.instance-port In addition to instances discovered via port
+-- scanning and version detection, run scripts on
+-- the instances running on these ports (number or list of numbers)
--
--- @args mssql.instance-all Targets all SQL server instances discovered
--- through the browser service.
+-- @args mssql.instance-all In addition to instances discovered via port
+-- scanning and version detection, run scripts on all
+-- discovered instances. These include named-pipe
+-- instances via SMB and those discovered via the
+-- browser service.
--
-- @args mssql.domain The domain against which to perform integrated
-- authentication. When set, the scripts assume integrated authentication
@@ -107,13 +114,14 @@ local math = require "math"
local match = require "match"
local nmap = require "nmap"
local datetime = require "datetime"
-local shortport = require "shortport"
+local outlib = require "outlib"
local smb = require "smb"
local smbauth = require "smbauth"
local stdnse = require "stdnse"
local strbuf = require "strbuf"
local string = require "string"
local table = require "table"
+local tableaux = require "tableaux"
local unicode = require "unicode"
_ENV = stdnse.module("mssql", stdnse.seeall)
@@ -150,12 +158,25 @@ do
end
MSSQL_TIMEOUT = timeout
- SCANNED_PORTS_ONLY = false
- if ( stdnse.get_script_args( "mssql.scanned-ports-only" ) ) then
- SCANNED_PORTS_ONLY = true
- end
end
+-- Make args either a list or nil
+local function list_of (input, transform)
+ if not input then return nil end
+ if type(input) ~= "table" then
+ return {transform(input)}
+ end
+ for i, v in ipairs(input) do
+ input[i] = transform(v)
+ end
+ return input
+end
+
+local SCANNED_PORTS_ONLY = not not stdnse.get_script_args("mssql.scanned-ports-only")
+local targetInstanceNames = list_of(stdnse.get_script_args("mssql.instance-name"), string.upper)
+local targetInstancePorts = list_of(stdnse.get_script_args("mssql.instance-port"), tonumber)
+local targetAllInstances = not not stdnse.get_script_args("mssql.instance-all")
+
-- This constant is number of seconds from 1900-01-01 to 1970-01-01
local tds_offset_seconds = -2208988800 - datetime.utc_offset()
@@ -2561,6 +2582,9 @@ Helper =
--- Gets a table containing SqlServerInstanceInfo objects discovered on
-- the specified host (and port, if specified).
--
+ -- This table is the NSE registry table itself, not a copy, so do not alter
+ -- it unintentionally.
+ --
-- @param host A host table for the target host
-- @param port (Optional) If omitted, all of the instances for the host
-- will be returned.
@@ -2570,12 +2594,12 @@ Helper =
nmap.registry.mssql.instances = nmap.registry.mssql.instances or {}
nmap.registry.mssql.instances[ host.ip ] = nmap.registry.mssql.instances[ host.ip ] or {}
+ local instances = nmap.registry.mssql.instances[ host.ip ]
if ( not port ) then
- local instances = nmap.registry.mssql.instances[ host.ip ]
if ( instances and #instances == 0 ) then instances = nil end
return instances
else
- for _, instance in ipairs( nmap.registry.mssql.instances[ host.ip ] ) do
+ for _, instance in ipairs(instances) do
if ( instance.port and instance.port.number == port.number and
instance.port.protocol == port.protocol ) then
return { instance }
@@ -2660,29 +2684,32 @@ Helper =
DiscoverByTcp = function( host, port )
local version, instance, status
-- Check to see if we've already discovered an instance on this port
- instance = Helper.GetDiscoveredInstances( host, port )
- if ( not instance ) then
- instance = SqlServerInstanceInfo:new()
- instance.host = host
- instance.port = port
+ local instance = Helper.GetDiscoveredInstances(host, port)
+ if instance then
+ return true, {instance}
+ end
+ instance = SqlServerInstanceInfo:new()
+ instance.host = host
+ instance.port = port
- -- -sV may have gotten a version, but for now, it doesn't extract subBuild.
- status, version = Helper.GetInstanceVersion( instance )
- if ( status ) then
- Helper.AddOrMergeInstance( instance )
- -- The point of this wasn't to get the version, just to use the
- -- pre-login packet to determine whether there was a SQL Server on
- -- the port. However, since we have the version now, we'll store it.
- instance.version = version
- -- Give some version info back to Nmap
- if ( instance.port and instance.version ) then
- instance.version:PopulateNmapPortVersion( instance.port )
- nmap.set_port_version( host, instance.port)
- end
- end
+ -- -sV may have gotten a version, but for now, it doesn't extract subBuild.
+ status, version = Helper.GetInstanceVersion( instance )
+ if not status then
+ return false, version
end
- return (instance ~= nil), { instance }
+ Helper.AddOrMergeInstance( instance )
+ -- The point of this wasn't to get the version, just to use the
+ -- pre-login packet to determine whether there was a SQL Server on
+ -- the port. However, since we have the version now, we'll store it.
+ instance.version = version
+ -- Give some version info back to Nmap
+ if ( instance.port and instance.version ) then
+ instance.version:PopulateNmapPortVersion( instance.port )
+ nmap.set_port_version( host, instance.port)
+ end
+
+ return true, { instance }
end,
--- Attempts to discover SQL Server instances listening on default named
@@ -2743,48 +2770,37 @@ Helper =
end
nmap.registry.mssql.discovery_performed[ host.ip ] = false
- -- Check all ports that -sV discovered
- -- First SSRP browser ports, then TCP instances
- for _, c in ipairs({
- {proto="udp", name="ms-sql-m", method="DiscoverBySsrp"},
- {proto="tcp", name="ms-sql-s", method="DiscoverByTcp"},
- }) do
- -- (no need to check open|filtered because -sV marks it as open if it gets a response)
- local port = nmap.get_ports(host, nil, c.proto, "open")
- while port do
- if port.version and port.version.name == c.name then
- Helper[c.method]( host, port )
- end
- port = nmap.get_ports(host, port, c.proto, "open")
+ -- First, do SSRP discovery. Check any open (got response) ports first:
+ local port = nmap.get_ports(host, nil, "udp", "open")
+ while port do
+ if port.version and port.version.name == "ms-sql-m" then
+ Helper.DiscoverBySsrp(host, port)
end
+ port = nmap.get_ports(host, port, "udp", "open")
+ end
+ -- Then check if default SSRP port hasn't been done yet.
+ port = nmap.get_port_state(host, SSRP.PORT)
+ if not port or port.state == "open|filtered" then
+ -- Either it wasn't scanned or it wasn't strictly "open" so we missed it above
+ Helper.DiscoverBySsrp(host, port)
+ end
+
+ -- Next, do TCP discovery. Check any ports with an appropriate service name
+ port = nmap.get_ports(host, nil, "tcp", "open")
+ while port do
+ if port.version and port.version.name == "ms-sql-s" then
+ Helper.DiscoverByTcp(host, port)
+ end
+ port = nmap.get_ports(host, port, "tcp", "open")
end
- local sqlDefaultPort = nmap.get_port_state( host, {number = 1433, protocol = "tcp"} ) or {number = 1433, protocol = "tcp"}
- local sqlBrowserPort = nmap.get_port_state( host, {number = 1434, protocol = "udp"} ) or {number = 1434, protocol = "udp"}
- local smbPort
-- smb.get_port() will return nil if no SMB port was scanned OR if SMB ports were scanned but none was open
- local smbPortNumber = smb.get_port( host )
- if ( smbPortNumber ) then
- smbPort = nmap.get_port_state( host, {number = smbPortNumber, protocol = "tcp"} )
- -- There's no use in manually setting an SMB port; if no SMB port was
- -- scanned and found open, the SMB library won't work
+ if smb.get_port(host) then
+ Helper.DiscoverBySmb( host )
end
- -- if the user has specified ports, we'll check those too
- local targetInstancePorts = stdnse.get_script_args( "mssql.instance-port" )
- if ( sqlBrowserPort and sqlBrowserPort.state ~= "closed" ) then
- Helper.DiscoverBySsrp( host, sqlBrowserPort )
- end
- if ( sqlDefaultPort and sqlDefaultPort.state ~= "closed" ) then
- Helper.DiscoverByTcp( host, sqlDefaultPort )
- end
- if ( smbPort ) then
- Helper.DiscoverBySmb( host, smbPort )
- end
+ -- if the user has specified ports, we'll check those too
if ( targetInstancePorts ) then
- if ( type( targetInstancePorts ) == "string" ) then
- targetInstancePorts = { targetInstancePorts }
- end
for _, portNumber in ipairs( targetInstancePorts ) do
portNumber = tonumber( portNumber )
Helper.DiscoverByTcp( host, {number = portNumber, protocol = "tcp"} )
@@ -3142,27 +3158,18 @@ Helper =
-- more SqlServerInstanceInfo objects. If status is false, this will be
-- an error message.
GetTargetInstances = function( host, port )
- if ( port ) then
- local status = true
- local instance = Helper.GetDiscoveredInstances( host, port )
+ -- Perform discovery. This won't do anything if it's already been done.
+ -- It's important because otherwise we might miss some ports when not using -sV
+ Helper.Discover( host )
- if ( not instance ) then
- status, instance = Helper.DiscoverByTcp( host, port )
- end
- if ( instance ) then
- return true, instance
+ if ( port ) then
+ local status, instances = Helper.GetDiscoveredInstances(host, port)
+ if status then
+ return true, instances
else
return false, "No SQL Server instance detected on this port"
end
else
- local targetInstanceNames = stdnse.get_script_args( "mssql.instance-name" )
- local targetInstancePorts = stdnse.get_script_args( "mssql.instance-port" )
- local targetAllInstances = stdnse.get_script_args( "mssql.instance-all" )
-
- if ( targetInstanceNames and targetInstancePorts ) then
- return false, "Connections can be made either by instance name or port."
- end
-
if ( targetAllInstances and ( targetInstanceNames or targetInstancePorts ) ) then
return false, "All instances cannot be specified together with an instance name or port."
end
@@ -3171,51 +3178,43 @@ Helper =
return false, "No instance(s) specified."
end
- -- Perform discovery. This won't do anything if it's already been done.
- Helper.Discover( host )
-
local instanceList = Helper.GetDiscoveredInstances( host )
if ( not instanceList ) then
return false, "No instances found on target host"
end
local targetInstances = {}
- if ( targetAllInstances ) then
- targetInstances = instanceList
- else
- -- We want an easy way to look up whether an instance's name was
- -- in our target list. So, we'll make a table of { instanceName = true, ... }
- local temp = {}
- if ( targetInstanceNames ) then
- if ( type( targetInstanceNames ) == "string" ) then
- targetInstanceNames = { targetInstanceNames }
- end
- for _, instanceName in ipairs( targetInstanceNames ) do
- temp[ string.upper( instanceName ) ] = true
- end
- end
- targetInstanceNames = temp
- -- Do the same for the target ports
- temp = {}
- if ( targetInstancePorts ) then
- if ( type( targetInstancePorts ) == "string" ) then
- targetInstancePorts = { targetInstancePorts }
+ for _, instance in ipairs( instanceList ) do
+ repeat -- just so we can use break
+ if instance.port then
+ local scanport = nmap.get_port_state(host, instance.port)
+ -- If scanned-ports-only and it's on a non-scanned port
+ if (SCANNED_PORTS_ONLY and not scanport)
+ -- or if a portrule script will run on it
+ or (scanport and scanport.state == "open") then
+ break -- not interested
+ end
+ -- If they want everything
+ if targetAllInstances or
+ -- or if it's in the instance-port arg
+ (targetInstancePorts and
+ tableaux.contains(targetInstancePorts, instance.port.number)) then
+ -- keep it and move on
+ targetInstances[#targetInstances+1] = instance
+ break
+ end
end
- for _, portNumber in ipairs( targetInstancePorts ) do
- portNumber = tonumber( portNumber )
- temp[portNumber] = true
+ -- If they want everything
+ if targetAllInstances or
+ -- or if it's in the instance-name arg
+ (instance.instanceName and targetInstanceNames and
+ tableaux.contains(targetInstanceNames, string.upper(instance.instanceName))) then
+ --keep it and move on
+ targetInstances[#targetInstances+1] = instance
+ break
end
- end
- targetInstancePorts = temp
-
- for _, instance in ipairs( instanceList ) do
- if ( instance.instanceName and targetInstanceNames[ string.upper( instance.instanceName ) ] ) then
- table.insert( targetInstances, instance )
- elseif ( instance.port and targetInstancePorts[ tonumber( instance.port.number ) ] ) then
- table.insert( targetInstances, instance )
- end
- end
+ until false
end
if ( #targetInstances > 0 ) then
@@ -3232,14 +3231,17 @@ Helper =
-- the database when normal connection attempts fail, for example, when
-- the server is hanging, out of memory or other bad states.
--
- -- @param host Host table as received by the script action function
- -- @param instanceName the instance name to probe for a DAC port
+ -- @param instance the SqlServerInstanceInfo object to probe for a DAC port
-- @return number containing the DAC port on success or nil on failure
- DiscoverDACPort = function(host, instanceName)
- local socket = nmap.new_socket()
+ DiscoverDACPort = function(instance)
+ local instanceName = instance.instanceName or instance.pipeName
+ if not instanceName then
+ return nil
+ end
+ local socket = nmap.new_socket("udp")
socket:set_timeout(5000)
- if ( not(socket:connect(host, 1434, "udp")) ) then
+ if ( not(socket:connect(instance.host, 1434, "udp")) ) then
return false, "Failed to connect to sqlbrowser service"
end
@@ -3249,11 +3251,10 @@ Helper =
end
local status, data = socket:receive_buf(match.numbytes(6), true)
+ socket:close()
if ( not(status) ) then
- socket:close()
return nil
end
- socket:close()
if ( #data < 6 ) then
return nil
@@ -3261,42 +3262,47 @@ Helper =
return string.unpack("mssql.instance
- -- script argument.
+ --- Returns an action, portrule, and hostrule for standard SQL Server scripts
--
- -- However, if a previous script has failed to find any
- -- SQL Server instances on the host, the hostrule function will return
- -- false to keep further scripts from running unnecessarily on that host.
+ -- The action function performs discovery if necessary and dispatches the
+ -- process_instance function on all discovered instances.
--
- -- @return A hostrule function (use as hostrule = mssql.GetHostrule_Standard())
- GetHostrule_Standard = function()
- return function( host )
- if ( stdnse.get_script_args( {"mssql.instance-all", "mssql.instance-name", "mssql.instance-port"} ) ~= nil ) then
- if ( Helper.WasDiscoveryPerformed( host ) ) then
- return Helper.GetDiscoveredInstances( host ) ~= nil
- else
- return true
- end
- else
- return false
+ -- The portrule returns true if the port has been identified as "ms-sql-s" or
+ -- discovery has found an instance on that port.
+ --
+ -- The hostrule returns true if any of the mssql.instance-*
+ -- script-args has been set and either a matching instance exists or
+ -- discovery has not yet been done.
+ -- @usage action, portrule, hostrule = mssql.Helper.InitScript(do_something)
+ --
+ -- @param process_instance A function that takes a single parameter, a
+ -- SqlServerInstanceInfo object, and
+ -- returns output suitable for an action function to
+ -- return.
+ --
+ -- @return An action function
+ -- @return A portrule function
+ -- @return A hostrule function
+ InitScript = function(process_instance)
+ local action = function(host, port)
+ local status, instances = Helper.GetTargetInstances(host, port)
+ if not status then
+ stdnse.debug1("GetTargetInstances: %s", instances)
+ return nil
end
+ local output = {}
+ for _, instance in ipairs(instances) do
+ output[instance:GetName()] = process_instance(instance)
+ end
+ if #output > 0 then
+ return outlib.sorted_by_key(output)
+ end
+ return nil
end
- end,
-
- --- Returns a portrule for standard SQL Server scripts
- --
- -- The portrule return true if BOTH of the following conditions are met:
- -- * The port has been identified as "ms-sql-s"
- -- * The mssql.instance script argument has NOT been used
- --
- -- @return A portrule function (use as portrule = mssql.GetPortrule_Standard())
- GetPortrule_Standard = function()
- return function( host, port )
- return ( shortport.service( "ms-sql-s" )(host, port) and
- stdnse.get_script_args( {"mssql.instance-all", "mssql.instance-name", "mssql.instance-port"} ) == nil)
- end
+ -- GetTargetInstances does the right thing depending on whether port is
+ -- provided, which corresponds to portrule vs hostrule.
+ return action, Helper.GetTargetInstances, Helper.GetTargetInstances
end,
}
@@ -3371,11 +3377,11 @@ Auth = {
Util =
{
--- Takes a table as returned by Query and does some fancy formatting
- -- better suitable for stdnse.output_result
+ -- better suitable for stdnse.format_output
--
-- @param tbl as received by Helper.Query
-- @param with_headers boolean true if output should contain column headers
- -- @return table suitable for stdnse.output_result
+ -- @return table suitable for stdnse.format_output
FormatOutputTable = function ( tbl, with_headers )
local new_tbl = {}
local col_names = {}
diff --git a/scripts/ms-sql-brute.nse b/scripts/ms-sql-brute.nse
index 86f2a5304..71d7f0d44 100644
--- a/scripts/ms-sql-brute.nse
+++ b/scripts/ms-sql-brute.nse
@@ -77,13 +77,7 @@ author = "Patrik Karlsson"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"brute", "intrusive"}
-dependencies = {"ms-sql-empty-password"}
-
-
-
-hostrule = mssql.Helper.GetHostrule_Standard()
-portrule = mssql.Helper.GetPortrule_Standard()
-
+dependencies = {"broadcast-ms-sql-discover", "ms-sql-empty-password"}
--- Returns formatted output for the given instance
local function create_instance_output_table( instance )
@@ -132,7 +126,7 @@ local function create_instance_output_table( instance )
end
end
- return instanceOutput
+ return stdnse.format_output(true, instanceOutput)
end
@@ -199,7 +193,7 @@ local function test_credentials( instance, helper, username, password )
end
--- Processes a single instance, attempting to detect an empty password for "sa"
-local function process_instance( instance )
+process_instance = function ( instance )
-- One of this script's features is that it will report an instance's
-- in both the port-script results and the host-script results. In order to
@@ -275,10 +269,10 @@ local function process_instance( instance )
end
+local do_action
+do_action, portrule, hostrule = mssql.Helper.InitScript(process_instance)
-action = function( host, port )
- local scriptOutput = {}
- local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
+action = function(...)
local domain, bruteWindows = stdnse.get_script_args("mssql.domain", "ms-sql-brute.brute-windows-accounts")
@@ -292,16 +286,5 @@ action = function( host, port )
return ret
end
- if ( not status ) then
- return stdnse.format_output( false, instanceList )
- else
- for _, instance in pairs( instanceList ) do
- local instanceOutput = process_instance( instance )
- if instanceOutput then
- table.insert( scriptOutput, instanceOutput )
- end
- end
- end
-
- return stdnse.format_output( true, scriptOutput )
+ return do_action(...)
end
diff --git a/scripts/ms-sql-config.nse b/scripts/ms-sql-config.nse
index dad49cf91..83db0306f 100644
--- a/scripts/ms-sql-config.nse
+++ b/scripts/ms-sql-config.nse
@@ -70,12 +70,7 @@ license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"}
-dependencies = {"ms-sql-brute", "ms-sql-empty-password"}
-
-
-hostrule = mssql.Helper.GetHostrule_Standard()
-portrule = mssql.Helper.GetPortrule_Standard()
-
+dependencies = {"broadcast-ms-sql-discover", "ms-sql-brute", "ms-sql-empty-password"}
--- Processes a set of instances
local function process_instance( instance )
@@ -130,28 +125,8 @@ local function process_instance( instance )
helper:Disconnect()
- local instanceOutput = {}
- instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
- table.insert( instanceOutput, result )
-
- return instanceOutput
+ -- TODO: structured output instead of format_output
+ return stdnse.format_output(true, result)
end
-
-action = function( host, port )
- local scriptOutput = {}
- local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
-
- if ( not status ) then
- return stdnse.format_output( false, instanceList )
- else
- for _, instance in pairs( instanceList ) do
- local instanceOutput = process_instance( instance )
- if instanceOutput then
- table.insert( scriptOutput, instanceOutput )
- end
- end
- end
-
- return stdnse.format_output( true, scriptOutput )
-end
+action, portrule, hostrule = mssql.Helper.InitScript(process_instance)
diff --git a/scripts/ms-sql-dac.nse b/scripts/ms-sql-dac.nse
index 121e7242b..ab8ee20a6 100644
--- a/scripts/ms-sql-dac.nse
+++ b/scripts/ms-sql-dac.nse
@@ -1,8 +1,6 @@
-local coroutine = require "coroutine"
local mssql = require "mssql"
local nmap = require "nmap"
local stdnse = require "stdnse"
-local table = require "table"
description = [[
Queries the Microsoft SQL Browser service for the DAC (Dedicated Admin
@@ -28,75 +26,60 @@ accessible or not.
--
-- @output
-- | ms-sql-dac:
--- |_ Instance: SQLSERVER; DAC port: 1533
+-- | SQLSERVER:
+-- | port: 1533
+-- |_ state: open
--
author = "Patrik Karlsson"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"}
-hostrule = function(host)
- if ( mssql.Helper.WasDiscoveryPerformed( host ) ) then
- return mssql.Helper.GetDiscoveredInstances( host ) ~= nil
- else
- local sqlBrowserPort = nmap.get_port_state( host, {number = 1434, protocol = "udp"} )
- if ( (stdnse.get_script_args( {"mssql.instance-all", "mssql.instance-name", "mssql.instance-port"} ) ~= nil) or
- (sqlBrowserPort and (sqlBrowserPort.state == "open" or sqlBrowserPort.state == "open|filtered")) ) then
- return true
- end
- end
-end
+dependencies = {"broadcast-ms-sql-discover"}
local function checkPort(host, port)
+ local scanport = nmap.get_port_state(host, {number=port, protocol="tcp"})
+ if scanport then
+ return scanport.state
+ end
local s = nmap.new_socket()
s:set_timeout(5000)
- local status = s:connect(host, port, "tcp")
+ local status, err = s:connect(host, port, "tcp")
s:close()
- return status
+ return (status and "open" or "closed"), err
end
-local function discoverDAC(host, name, result)
- local condvar = nmap.condvar(result)
- stdnse.debug2("Discovering DAC port on instance: %s", name)
- local port = mssql.Helper.DiscoverDACPort( host, name )
- if ( port ) then
- if ( checkPort(host, port) ) then
- table.insert(result, ("Instance: %s; DAC port: %s"):format(name, port))
- else
- table.insert(result, ("Instance: %s; DAC port: %s (connection failed)"):format(name, port))
- end
+local function discoverDAC(instance)
+ stdnse.debug2("Discovering DAC port on instance: %s", instance:GetName())
+ local port = mssql.Helper.DiscoverDACPort(instance)
+ if not port then
+ return nil
end
- condvar "signal"
+
+ local result = stdnse.output_table()
+ result.port = port
+ local state, err = checkPort(instance.host, port)
+ result.state = state
+ result.error = err
+ return result
end
-action = function( host )
- local result, threads = {}, {}
- local condvar = nmap.condvar(result)
+local lib_portrule, lib_hostrule
+action, lib_portrule, lib_hostrule = mssql.Helper.InitScript(discoverDAC)
- local status, instanceList = mssql.Helper.GetTargetInstances( host )
- -- if no instances were targeted, then display info on all
- if ( not status ) then
- mssql.Helper.Discover( host )
- instanceList = mssql.Helper.GetDiscoveredInstances( host )
- end
-
- for _, instance in ipairs(instanceList or {}) do
- local name = instance:GetName():match("^[^\\]*\\(.*)$")
- if ( name ) then
- local co = stdnse.new_thread(discoverDAC, host, name, result)
- threads[co] = true
+local function rule_if_browser_open(lib_rule)
+ return function (host, ...)
+ if not lib_rule(host, ...) then
+ return false
end
+ local bport = nmap.get_port_state(host, {number=1434, protocol="udp"})
+ -- If port is nil, we don't know the state
+ return bport == nil or (
+ -- we know the state, so it has to be a good one
+ bport.state == "open" or bport.state == "open|filtered"
+ )
end
-
- while(next(threads)) do
- for t in pairs(threads) do
- threads[t] = ( coroutine.status(t) ~= "dead" ) and true or nil
- end
- if ( next(threads) ) then
- condvar "wait"
- end
- end
-
- return stdnse.format_output( true, result )
end
+portrule = rule_if_browser_open(lib_portrule)
+hostrule = rule_if_browser_open(lib_hostrule)
diff --git a/scripts/ms-sql-dump-hashes.nse b/scripts/ms-sql-dump-hashes.nse
index 7993dc037..c895b02ee 100644
--- a/scripts/ms-sql-dump-hashes.nse
+++ b/scripts/ms-sql-dump-hashes.nse
@@ -40,29 +40,19 @@ author = "Patrik Karlsson"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"auth", "discovery", "safe"}
-
-dependencies = {"ms-sql-brute", "ms-sql-empty-password"}
-
-hostrule = mssql.Helper.GetHostrule_Standard()
-portrule = mssql.Helper.GetPortrule_Standard()
+dependencies = {"broadcast-ms-sql-discover", "ms-sql-brute", "ms-sql-empty-password"}
local function process_instance(instance)
local helper = mssql.Helper:new()
local status, errorMessage = helper:ConnectEx( instance )
if ( not(status) ) then
- return false, {
- ['name'] = string.format( "[%s]", instance:GetName() ),
- "ERROR: " .. errorMessage
- }
+ return "ERROR: " .. errorMessage
end
status, errorMessage = helper:LoginEx( instance )
if ( not(status) ) then
- return false, {
- ['name'] = string.format( "[%s]", instance:GetName() ),
- "ERROR: " .. errorMessage
- }
+ return "ERROR: " .. errorMessage
end
local result
@@ -83,12 +73,7 @@ local function process_instance(instance)
end
helper:Disconnect()
- local instanceOutput = {}
- instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
- table.insert( instanceOutput, output )
-
- return true, instanceOutput
-
+ return output
end
-- Saves the hashes to file
@@ -110,31 +95,19 @@ local function saveToFile(filename, response)
return true
end
-action = function( host, port )
- local dir = stdnse.get_script_args("ms-sql-dump-hashes.dir")
- local scriptOutput = {}
- local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
+local dir = stdnse.get_script_args("ms-sql-dump-hashes.dir")
- if ( not status ) then
- return stdnse.format_output( false, instanceList )
- else
- for _, instance in pairs( instanceList ) do
- local status, instanceOutput = process_instance( instance )
- if ( status ) then
- local filename
- if ( dir ) then
- local instance = instance:GetName():match("%\\+(.+)$") or instance:GetName()
- filename = dir .. "/" .. stringaux.filename_escape(("%s_%s_ms-sql_hashes.txt"):format(host.ip, instance))
- saveToFile(filename, instanceOutput[1])
- end
- end
- table.insert( scriptOutput, instanceOutput )
- end
+local function process_and_save (instance)
+ local instanceOutput = process_instance( instance )
+ if type(instanceOutput) == "table" then
+ local inst = instance:GetName():gsub(".*\\", "")
+ local filename = dir .. "/" .. stringaux.filename_escape(
+ ("%s_%s_ms-sql_hashes.txt"):format(instance.host.ip, inst))
+ saveToFile(filename, instanceOutput)
end
-
- if ( #scriptOutput == 0 ) then return end
-
- local output = ( #scriptOutput > 1 and scriptOutput or scriptOutput[1] )
-
- return stdnse.format_output( true, output )
+ return instanceOutput
end
+
+local do_instance = dir and process_and_save or process_instance
+
+action, portrule, hostrule = mssql.Helper.InitScript(do_instance)
diff --git a/scripts/ms-sql-empty-password.nse b/scripts/ms-sql-empty-password.nse
index d35e3f7c8..0b52db510 100644
--- a/scripts/ms-sql-empty-password.nse
+++ b/scripts/ms-sql-empty-password.nse
@@ -59,9 +59,7 @@ author = "Patrik Karlsson"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"auth","intrusive"}
-
-hostrule = mssql.Helper.GetHostrule_Standard()
-portrule = mssql.Helper.GetPortrule_Standard()
+dependencies = {"broadcast-ms-sql-discover"}
local function test_credentials( instance, helper, username, password )
local database = "tempdb"
@@ -150,7 +148,6 @@ local function process_instance( instance )
local instanceOutput
if ( instance.ms_sql_empty ) then
instanceOutput = {}
- instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
for _, message in ipairs( instance.ms_sql_empty ) do
table.insert( instanceOutput, message )
end
@@ -163,21 +160,4 @@ local function process_instance( instance )
end
-
-action = function( host, port )
- local scriptOutput = {}
- local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
-
- if ( not status ) then
- return stdnse.format_output( false, instanceList )
- else
- for _, instance in pairs( instanceList ) do
- local instanceOutput = process_instance( instance )
- if instanceOutput then
- table.insert( scriptOutput, instanceOutput )
- end
- end
- end
-
- return stdnse.format_output( true, scriptOutput )
-end
+action, portrule, hostrule = mssql.Helper.InitScript(process_instance)
diff --git a/scripts/ms-sql-hasdbaccess.nse b/scripts/ms-sql-hasdbaccess.nse
index 7e362c205..3d28f3771 100644
--- a/scripts/ms-sql-hasdbaccess.nse
+++ b/scripts/ms-sql-hasdbaccess.nse
@@ -73,11 +73,7 @@ license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"auth", "discovery","safe"}
-dependencies = {"ms-sql-brute", "ms-sql-empty-password"}
-
-
-hostrule = mssql.Helper.GetHostrule_Standard()
-portrule = mssql.Helper.GetPortrule_Standard()
+dependencies = {"broadcast-ms-sql-discover", "ms-sql-brute", "ms-sql-empty-password"}
local function process_instance( instance )
@@ -146,30 +142,9 @@ local function process_instance( instance )
end
end
-
- local instanceOutput = {}
- instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
- table.insert( instanceOutput, output )
-
- return instanceOutput
-
+ -- TODO: structured output, not format_output
+ return stdnse.format_output(true, output)
end
-action = function( host, port )
- local scriptOutput = {}
- local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
-
- if ( not status ) then
- return stdnse.format_output( false, instanceList )
- else
- for _, instance in pairs( instanceList ) do
- local instanceOutput = process_instance( instance )
- if instanceOutput then
- table.insert( scriptOutput, instanceOutput )
- end
- end
- end
-
- return stdnse.format_output( true, scriptOutput )
-end
+action, portrule, hostrule = mssql.Helper.InitScript(process_instance)
diff --git a/scripts/ms-sql-info.nse b/scripts/ms-sql-info.nse
index df76b6737..445e6941d 100644
--- a/scripts/ms-sql-info.nse
+++ b/scripts/ms-sql-info.nse
@@ -150,25 +150,7 @@ license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default", "discovery", "safe"}
-
-hostrule = function(host)
- if ( mssql.Helper.WasDiscoveryPerformed( host ) ) then
- return mssql.Helper.GetDiscoveredInstances( host ) ~= nil
- else
- local sqlDefaultPort = nmap.get_port_state( host, {number = 1433, protocol = "tcp"} )
- local sqlBrowserPort = nmap.get_port_state( host, {number = 1434, protocol = "udp"} )
- -- smb.get_port() will return nil if no SMB port was scanned OR if SMB ports were scanned but none was open
- local smbPortNumber = smb.get_port( host )
-
- if ( (stdnse.get_script_args( {"mssql.instance-all", "mssql.instance-name", "mssql.instance-port"} ) ~= nil) or
- (sqlBrowserPort and (sqlBrowserPort.state == "open" or sqlBrowserPort.state == "open|filtered")) or
- (sqlDefaultPort and (sqlDefaultPort.state == "open" or sqlDefaultPort.state == "open|filtered")) or
- (smbPortNumber ~= nil) ) then
- return true
- end
- end
-end
-
+dependencies = {"broadcast-ms-sql-discover"}
--- Returns formatted output for the given version data
local function create_version_output_table( versionInfo )
@@ -247,33 +229,9 @@ local function process_instance( instance )
end
-
-action = function( host )
- local scriptOutput = stdnse.output_table()
-
- local status, instanceList = mssql.Helper.GetTargetInstances( host )
- -- if no instances were targeted, then display info on all
- if ( not status ) then
- mssql.Helper.Discover( host )
- instanceList = mssql.Helper.GetDiscoveredInstances( host )
- end
-
-
- if ( not instanceList ) then
- return stdnse.format_output( false, instanceList or "" )
- else
- for _, instance in ipairs( instanceList ) do
- if instance.serverName then
- scriptOutput["Windows server name"] = instance.serverName
- break
- end
- end
- for _, instance in pairs( instanceList ) do
- process_instance( instance )
- scriptOutput[instance:GetName()] = create_instance_output_table( instance )
- end
- end
-
- return scriptOutput
+local function do_instance (instance)
+ process_instance( instance )
+ return create_instance_output_table( instance )
end
+action, portrule, hostrule = mssql.Helper.InitScript(do_instance)
diff --git a/scripts/ms-sql-ntlm-info.nse b/scripts/ms-sql-ntlm-info.nse
index 4dd987d3f..6ff3db5a6 100644
--- a/scripts/ms-sql-ntlm-info.nse
+++ b/scripts/ms-sql-ntlm-info.nse
@@ -1,7 +1,6 @@
local os = require "os"
local datetime = require "datetime"
local mssql = require "mssql"
-local shortport = require "shortport"
local stdnse = require "stdnse"
local smbauth = require "smbauth"
local string = require "string"
@@ -46,9 +45,9 @@ author = "Justin Cacak"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default", "discovery", "safe"}
-portrule = shortport.port_or_service(1433, "ms-sql-s")
+dependencies = {"broadcast-ms-sql-discover"}
-action = function(host, port)
+local do_action = function(host, port)
local output = stdnse.output_table()
@@ -127,3 +126,9 @@ action = function(host, port)
return output
end
+
+local function process_instance(instance)
+ return do_action(instance.host, instance.port)
+end
+
+action, portrule = mssql.Helper.InitScript(process_instance)
diff --git a/scripts/ms-sql-query.nse b/scripts/ms-sql-query.nse
index aa8904111..8096da1d3 100644
--- a/scripts/ms-sql-query.nse
+++ b/scripts/ms-sql-query.nse
@@ -60,10 +60,7 @@ license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"}
-dependencies = {"ms-sql-brute", "ms-sql-empty-password"}
-
-hostrule = mssql.Helper.GetHostrule_Standard()
-portrule = mssql.Helper.GetPortrule_Standard()
+dependencies = {"broadcast-ms-sql-discover", "ms-sql-brute", "ms-sql-empty-password"}
---
local function process_instance( instance )
@@ -92,30 +89,18 @@ local function process_instance( instance )
result = mssql.Util.FormatOutputTable( result, true )
result["name"] = string.format( "Query: %s", query )
end
- local instanceOutput = {}
- instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
- table.insert( instanceOutput, result )
- return instanceOutput
+ return result
end
+local do_action
+do_action, portrule, hostrule = mssql.Helper.InitScript(process_instance)
-action = function( host, port )
- local scriptOutput = {}
- local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
+action = function(...)
+ local scriptOutput = do_action(...)
- if ( not status ) then
- return stdnse.format_output( false, instanceList )
- else
- for _, instance in pairs( instanceList ) do
- local instanceOutput = process_instance( instance )
- if instanceOutput then
- table.insert( scriptOutput, instanceOutput )
- end
- end
- if ( not( stdnse.get_script_args( {'ms-sql-query.query', 'mssql-query.query' } ) ) ) then
- table.insert(scriptOutput, 1, "(Use --script-args=ms-sql-query.query='' to change query.)")
- end
+ if ( not( stdnse.get_script_args( {'ms-sql-query.query', 'mssql-query.query' } ) ) ) then
+ table.insert(scriptOutput, 1, "(Use --script-args=ms-sql-query.query='' to change query.)")
end
return stdnse.format_output( true, scriptOutput )
diff --git a/scripts/ms-sql-tables.nse b/scripts/ms-sql-tables.nse
index dbeb3e538..caf0a822a 100644
--- a/scripts/ms-sql-tables.nse
+++ b/scripts/ms-sql-tables.nse
@@ -98,10 +98,7 @@ license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"}
-dependencies = {"ms-sql-brute", "ms-sql-empty-password"}
-
-hostrule = mssql.Helper.GetHostrule_Standard()
-portrule = mssql.Helper.GetPortrule_Standard()
+dependencies = {"broadcast-ms-sql-discover", "ms-sql-brute", "ms-sql-empty-password"}
local function process_instance( instance )
@@ -248,25 +245,9 @@ local function process_instance( instance )
instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
table.insert( instanceOutput, output )
- return instanceOutput
+ return stdnse.format_ouptut(true, instanceOutput)
end
-action = function( host, port )
- local scriptOutput = {}
- local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
-
- if ( not status ) then
- return stdnse.format_output( false, instanceList )
- else
- for _, instance in pairs( instanceList ) do
- local instanceOutput = process_instance( instance )
- if instanceOutput then
- table.insert( scriptOutput, instanceOutput )
- end
- end
- end
-
- return stdnse.format_output( true, scriptOutput )
-end
+action, portrule, hostrule = mssql.Helper.InitScript(process_instance)
diff --git a/scripts/ms-sql-xp-cmdshell.nse b/scripts/ms-sql-xp-cmdshell.nse
index ab1632b4c..b5dc4a3f3 100644
--- a/scripts/ms-sql-xp-cmdshell.nse
+++ b/scripts/ms-sql-xp-cmdshell.nse
@@ -86,10 +86,7 @@ license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"intrusive"}
-dependencies = {"ms-sql-brute", "ms-sql-empty-password"}
-
-hostrule = mssql.Helper.GetHostrule_Standard()
-portrule = mssql.Helper.GetPortrule_Standard()
+dependencies = {"broadcast-ms-sql-discover", "ms-sql-brute", "ms-sql-empty-password"}
local function process_instance( instance )
@@ -143,23 +140,13 @@ local function process_instance( instance )
end
-action = function( host, port )
- local scriptOutput = {}
- local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
+local do_action
+do_action, portrule, hostrule = mssql.Helper.InitScript(process_instance)
- if ( not status ) then
- return stdnse.format_output( false, instanceList )
- else
- for _, instance in pairs( instanceList ) do
- local instanceOutput = process_instance( instance )
- if instanceOutput then
- table.insert( scriptOutput, instanceOutput )
- end
- end
-
- if ( not(stdnse.get_script_args( {'ms-sql-xp-cmdshell.cmd', 'mssql-xp-cmdshell.cmd'} ) ) ) then
- table.insert(scriptOutput, 1, "(Use --script-args=ms-sql-xp-cmdshell.cmd='' to change command.)")
- end
+action = function(...)
+ local scriptOutput = do_action(...)
+ if ( not(stdnse.get_script_args( {'ms-sql-xp-cmdshell.cmd', 'mssql-xp-cmdshell.cmd'} ) ) ) then
+ table.insert(scriptOutput, 1, "(Use --script-args=ms-sql-xp-cmdshell.cmd='' to change command.)")
end
return stdnse.format_output( true, scriptOutput )