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

Change how ms-sql NSE scripts run

MS SQL NSE scripts run on database instances, which can be TCP or named
pipes. With this change, all TCP instances on scanned ports will have
script output attached under the port as a portrule script. Named pipe
instances and TCP instances on unscanned ports will be displayed in the
hostrule script output at the end of the host's output. Utility function
mssql.Helper.InitScript makes it easy to write scripts that just work on
a per-instance basis, without bothering where to put the output.
Discovery will be done once per host, regardless of how many scripts are
run, and can be guaranteed to be done before the script's action takes
place.
This commit is contained in:
dmiller
2022-01-03 21:08:52 +00:00
parent 33405fcfb5
commit c3d54f1fac
12 changed files with 265 additions and 474 deletions

View File

@@ -74,12 +74,19 @@
-- argument is not given but <code>mssql.username</code>, 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,11 +158,24 @@ do
end
MSSQL_TIMEOUT = timeout
SCANNED_PORTS_ONLY = false
if ( stdnse.get_script_args( "mssql.scanned-ports-only" ) ) then
SCANNED_PORTS_ONLY = true
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 {}
if ( not port ) then
local instances = nmap.registry.mssql.instances[ host.ip ]
if ( not port ) then
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,15 +2684,20 @@ 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
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
if not status then
return false, version
end
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
@@ -2679,10 +2708,8 @@ Helper =
instance.version:PopulateNmapPortVersion( instance.port )
nmap.set_port_version( host, instance.port)
end
end
end
return (instance ~= nil), { instance }
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")
-- 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 == c.name then
Helper[c.method]( host, port )
if port.version and port.version.name == "ms-sql-m" then
Helper.DiscoverBySsrp(host, port)
end
port = nmap.get_ports(host, port, c.proto, "open")
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 }
end
for _, portNumber in ipairs( targetInstancePorts ) do
portNumber = tonumber( portNumber )
temp[portNumber] = true
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 )
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
-- 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
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 <code>SqlServerInstanceInfo</code> 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)
if ( not(status) ) then
socket:close()
if ( not(status) ) then
return nil
end
socket:close()
if ( #data < 6 ) then
return nil
@@ -3261,42 +3262,47 @@ Helper =
return string.unpack("<I2", data, 5)
end,
--- Returns a hostrule for standard SQL Server scripts, which will return
-- true if one or more instances have been targeted with the <code>mssql.instance</code>
-- 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 <code>hostrule = mssql.GetHostrule_Standard()</code>)
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
-- 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 <code>mssql.instance-*</code>
-- 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
-- <code>SqlServerInstanceInfo</code> 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
else
return false
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 <code>mssql.instance</code> script argument has NOT been used
--
-- @return A portrule function (use as <code>portrule = mssql.GetPortrule_Standard()</code>)
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 <code>stdnse.output_result</code>
-- better suitable for <code>stdnse.format_output</code>
--
-- @param tbl as received by <code>Helper.Query</code>
-- @param with_headers boolean true if output should contain column headers
-- @return table suitable for <code>stdnse.output_result</code>
-- @return table suitable for <code>stdnse.format_output</code>
FormatOutputTable = function ( tbl, with_headers )
local new_tbl = {}
local col_names = {}

View File

@@ -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

View File

@@ -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)

View File

@@ -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
end
condvar "signal"
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
action = function( host )
local result, threads = {}, {}
local condvar = nmap.condvar(result)
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 )
local result = stdnse.output_table()
result.port = port
local state, err = checkPort(instance.host, port)
result.state = state
result.error = err
return result
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 lib_portrule, lib_hostrule
action, lib_portrule, lib_hostrule = mssql.Helper.InitScript(discoverDAC)
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
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)

View File

@@ -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 )
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 )
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
return instanceOutput
end
if ( #scriptOutput == 0 ) then return end
local do_instance = dir and process_and_save or process_instance
local output = ( #scriptOutput > 1 and scriptOutput or scriptOutput[1] )
return stdnse.format_output( true, output )
end
action, portrule, hostrule = mssql.Helper.InitScript(do_instance)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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
local function do_instance (instance)
process_instance( instance )
scriptOutput[instance:GetName()] = create_instance_output_table( instance )
end
end
return scriptOutput
return create_instance_output_table( instance )
end
action, portrule, hostrule = mssql.Helper.InitScript(do_instance)

View File

@@ -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)

View File

@@ -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,31 +89,19 @@ 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='<QUERY>' to change query.)")
end
end
return stdnse.format_output( true, scriptOutput )
end

View File

@@ -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)

View File

@@ -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,24 +140,14 @@ 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
local do_action
do_action, portrule, hostrule = mssql.Helper.InitScript(process_instance)
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='<CMD>' to change command.)")
end
end
return stdnse.format_output( true, scriptOutput )
end