Skip to content

Commit a918606

Browse files
authoredFeb 20, 2024··
Merge pull request #443 from Patrowl/ARS-286-Various-nmap-bugs-with-RI
ARS-286 various nmap bugs with RI
2 parents f331a8e + bf0acd2 commit a918606

12 files changed

+2016
-69
lines changed
 

‎VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.5.21
1+
1.5.22-rc1

‎engines/nmap/Dockerfile

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
FROM alpine:3.16.3
2-
LABEL Name="Nmap\ \(Patrowl engine\)" Version="1.4.48"
2+
LABEL Name="Nmap\ \(Patrowl engine\)" Version="1.4.49-rc1"
33

44
# Set the working directory
55
RUN mkdir -p /opt/patrowl-engines/nmap
@@ -40,5 +40,7 @@ RUN pip3 install --trusted-host pypi.python.org -r requirements.txt
4040
EXPOSE 5001
4141
#USER alpine #Can't set properly env vars from Docker because it sets root env only
4242

43+
COPY fixed_script/* /usr/share/nmap/scripts/
44+
4345
# Run app when the container launches
4446
CMD ["gunicorn", "engine-nmap:app", "-b", "0.0.0.0:5001", "--access-logfile", "-", "-k", "gevent"]

‎engines/nmap/VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.4.48
1+
1.4.49-rc1

‎engines/nmap/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# -*- coding: utf-8 -*-
33

44
__title__ = 'patrowl_engine_nmap'
5-
__version__ = '1.4.34'
5+
__version__ = '1.4.49-rc1'
66
__author__ = 'Nicolas MATTIOCCO'
77
__license__ = 'AGPLv3'
88
__copyright__ = 'Copyright (C) 2018-2022 Nicolas Mattiocco - @MaKyOtOx'

‎engines/nmap/engine-nmap.py

+6-64
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,12 @@ def _parse_report(filename, scan_id):
859859
except Exception:
860860
product = ""
861861

862+
script_output = ""
863+
864+
#Get Result from Port Script.
865+
for port_script in port.findall("script"):
866+
script_output += port_script.get("output")+"\n"
867+
port_data.update({"script_output":script_output})
862868
res.append(
863869
deepcopy(
864870
_add_issue(
@@ -897,70 +903,6 @@ def _parse_report(filename, scan_id):
897903
)
898904
)
899905

900-
for port_script in port.findall("script"):
901-
script_id = port_script.get("id")
902-
script_output = port_script.get("output")
903-
# Disable hash for some script_id
904-
# if script_id in ["fingerprint-strings"]:
905-
# script_hash = "None"
906-
# else:
907-
# script_hash = hashlib.sha1(str(script_output).encode('utf-8')).hexdigest()[:6]
908-
909-
if script_id == "vulners":
910-
(
911-
port_max_cvss,
912-
port_cve_list,
913-
port_cve_links,
914-
port_cpe,
915-
) = _get_vulners_findings(script_output)
916-
917-
port_severity = "info"
918-
if port_max_cvss >= 7.5:
919-
port_severity = "high"
920-
elif port_max_cvss >= 5.0 and port_max_cvss < 7.5:
921-
port_severity = "medium"
922-
elif port_max_cvss >= 3.0 and port_max_cvss < 5.0:
923-
port_severity = "low"
924-
925-
res.append(
926-
deepcopy(
927-
_add_issue(
928-
scan_id,
929-
target,
930-
ts,
931-
"Nmap script '{}' detected findings on port {}/{}".format(
932-
script_id, proto, portid
933-
),
934-
"The script '{}' detected following findings:\n{}".format(
935-
script_id, script_output
936-
),
937-
severity=port_severity,
938-
type="port_script",
939-
tags=[script_id],
940-
risk={"cvss_base_score": port_max_cvss},
941-
vuln_refs={"CVE": port_cve_list, "CPE": port_cpe},
942-
links=port_cve_links,
943-
)
944-
)
945-
)
946-
else:
947-
res.append(
948-
deepcopy(
949-
_add_issue(
950-
scan_id,
951-
target,
952-
ts,
953-
"Nmap script '{}' detected findings on port {}/{}".format(
954-
script_id, proto, portid
955-
),
956-
"The script '{}' detected following findings:\n{}".format(
957-
script_id, script_output
958-
),
959-
type="port_script",
960-
tags=[script_id],
961-
)
962-
)
963-
)
964906
if (
965907
not openports
966908
and "ports" in this.scans[scan_id]["options"].keys()
+266
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
local mssql = require "mssql"
2+
local nmap = require "nmap"
3+
local smb = require "smb"
4+
local shortport = require "shortport"
5+
local stdnse = require "stdnse"
6+
7+
-- -*- mode: lua -*-
8+
-- vim: set filetype=lua :
9+
10+
description = [[
11+
Attempts to determine configuration and version information for Microsoft SQL
12+
Server instances.
13+
14+
SQL Server credentials required: No (will not benefit from
15+
<code>mssql.username</code> & <code>mssql.password</code>).
16+
Run criteria:
17+
* Host script: Will always run.
18+
* Port script: N/A
19+
20+
NOTE: Unlike previous versions, this script will NOT attempt to log in to SQL
21+
Server instances. Blank passwords can be checked using the
22+
<code>ms-sql-empty-password</code> script. E.g.:
23+
<code>nmap -sn --script ms-sql-empty-password --script-args mssql.instance-all <host></code>
24+
25+
The script uses two means of getting version information for SQL Server instances:
26+
* Querying the SQL Server Browser service, which runs by default on UDP port
27+
1434 on servers that have SQL Server 2000 or later installed. However, this
28+
service may be disabled without affecting the functionality of the instances.
29+
Additionally, it provides imprecise version information.
30+
* Sending a probe to the instance, causing the instance to respond with
31+
information including the exact version number. This is the same method that
32+
Nmap uses for service versioning; however, this script can also do the same for
33+
instances accessible via Windows named pipes, and can target all of the
34+
instances listed by the SQL Server Browser service.
35+
36+
In the event that the script can connect to the SQL Server Browser service
37+
(UDP 1434) but is unable to connect directly to the instance to obtain more
38+
accurate version information (because ports are blocked or the <code>mssql.scanned-ports-only</code>
39+
argument has been used), the script will rely only upon the version number
40+
provided by the SQL Server Browser/Monitor, which has the following limitations:
41+
* For SQL Server 2000 and SQL Server 7.0 instances, the RTM version number is
42+
always given, regardless of any service packs or patches installed.
43+
* For SQL Server 2005 and later, the version number will reflect the service
44+
pack installed, but the script will not be able to tell whether patches have
45+
been installed.
46+
47+
Where possible, the script will determine major version numbers, service pack
48+
levels and whether patches have been installed. However, in cases where
49+
particular determinations can not be made, the script will report only what can
50+
be confirmed.
51+
52+
NOTE: Communication with instances via named pipes depends on the <code>smb</code>
53+
library. To communicate with (and possibly to discover) instances via named pipes,
54+
the host must have at least one SMB port (e.g. TCP 445) that was scanned and
55+
found to be open. Additionally, named pipe connections may require Windows
56+
authentication to connect to the Windows host (via SMB) in addition to the
57+
authentication required to connect to the SQL Server instances itself. See the
58+
documentation and arguments for the <code>smb</code> library for more information.
59+
60+
NOTE: By default, the ms-sql-* scripts may attempt to connect to and communicate
61+
with ports that were not included in the port list for the Nmap scan. This can
62+
be disabled using the <code>mssql.scanned-ports-only</code> script argument.
63+
]]
64+
---
65+
-- @usage
66+
-- nmap -p 445 --script ms-sql-info <host>
67+
-- nmap -p 1433 --script ms-sql-info --script-args mssql.instance-port=1433 <host>
68+
--
69+
-- @output
70+
-- | ms-sql-info:
71+
-- | Windows server name: WINXP
72+
-- | 192.168.100.128\PROD:
73+
-- | Instance name: PROD
74+
-- | Version:
75+
-- | name: Microsoft SQL Server 2000 SP3
76+
-- | number: 8.00.760
77+
-- | Product: Microsoft SQL Server 2000
78+
-- | Service pack level: SP3
79+
-- | Post-SP patches applied: No
80+
-- | TCP port: 1278
81+
-- | Named pipe: \\192.168.100.128\pipe\MSSQL$PROD\sql\query
82+
-- | Clustered: No
83+
-- | 192.168.100.128\SQLFIREWALLED:
84+
-- | Instance name: SQLFIREWALLED
85+
-- | Version:
86+
-- | name: Microsoft SQL Server 2008 RTM
87+
-- | Product: Microsoft SQL Server 2008
88+
-- | Service pack level: RTM
89+
-- | TCP port: 4343
90+
-- | Clustered: No
91+
-- | \\192.168.100.128\pipe\sql\query:
92+
-- | Version:
93+
-- | name: Microsoft SQL Server 2005 SP3+
94+
-- | number: 9.00.4053
95+
-- | Product: Microsoft SQL Server 2005
96+
-- | Service pack level: SP3
97+
-- | Post-SP patches applied: Yes
98+
-- |_ Named pipe: \\192.168.100.128\pipe\sql\query
99+
--
100+
-- @xmloutput
101+
-- <elem key="Windows server name">WINXP</elem>
102+
-- <table key="192.168.100.128\PROD">
103+
-- <elem key="Instance name">PROD</elem>
104+
-- <table key="Version">
105+
-- <elem key="name">Microsoft SQL Server 2000 SP3</elem>
106+
-- <elem key="number">8.00.760</elem>
107+
-- <elem key="Product">Microsoft SQL Server 2000</elem>
108+
-- <elem key="Service pack level">SP3</elem>
109+
-- <elem key="Post-SP patches applied">No</elem>
110+
-- </table>
111+
-- <elem key="TCP port">1278</elem>
112+
-- <elem key="Named pipe">\\192.168.100.128\pipe\MSSQL$PROD\sql\query</elem>
113+
-- <elem key="Clustered">No</elem>
114+
-- </table>
115+
-- <table key="192.168.100.128\SQLFIREWALLED">
116+
-- <elem key="Instance name">SQLFIREWALLED</elem>
117+
-- <table key="Version">
118+
-- <elem key="name">Microsoft SQL Server 2008 RTM</elem>
119+
-- <elem key="Product">Microsoft SQL Server 2008</elem>
120+
-- <elem key="Service pack level">RTM</elem>
121+
-- </table>
122+
-- <elem key="TCP port">4343</elem>
123+
-- <elem key="Clustered">No</elem>
124+
-- </table>
125+
-- <table key="\\192.168.100.128\pipe\sql\query">
126+
-- <table key="Version">
127+
-- <elem key="name">Microsoft SQL Server 2005 SP3+</elem>
128+
-- <elem key="number">9.00.4053</elem>
129+
-- <elem key="Product">Microsoft SQL Server 2005</elem>
130+
-- <elem key="Service pack level">SP3</elem>
131+
-- <elem key="Post-SP patches applied">Yes</elem>
132+
-- </table>
133+
-- <elem key="Named pipe">\\192.168.100.128\pipe\sql\query</elem>
134+
-- </table>
135+
136+
-- rev 1.0 (2007-06-09)
137+
-- rev 1.1 (2009-12-06 - Added SQL 2008 identification T Sellers)
138+
-- rev 1.2 (2010-10-03 - Added Broadcast support <patrik@cqure.net>)
139+
-- rev 1.3 (2010-10-10 - Added prerule and newtargets support <patrik@cqure.net>)
140+
-- rev 1.4 (2011-01-24 - Revised logic in order to get version data without logging in;
141+
-- added functionality to interpret version in terms of SP level, etc.
142+
-- added script arg to prevent script from connecting to ports that
143+
-- weren't in original Nmap scan <chris3E3@gmail.com>)
144+
-- rev 1.5 (2011-02-01 - Moved discovery functionality into ms-sql-discover.nse and
145+
-- broadcast-ms-sql-discovery.nse <chris3E3@gmail.com>)
146+
-- rev 1.6 (2014-09-04 - Added structured output Daniel Miller)
147+
148+
author = {"Chris Woodbury", "Thomas Buchanan"}
149+
150+
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
151+
152+
categories = {"default", "discovery", "safe"}
153+
154+
portrule = shortport.port_or_service(1433, "ms-sql-s")
155+
156+
157+
158+
--- Returns formatted output for the given version data
159+
local function create_version_output_table( versionInfo )
160+
local versionOutput = stdnse.output_table()
161+
162+
versionOutput["name"] = versionInfo:ToString()
163+
if ( versionInfo.source ~= "SSRP" ) then
164+
versionOutput["number"] = versionInfo.versionNumber
165+
end
166+
versionOutput["Product"] = versionInfo.productName
167+
versionOutput["Service pack level"] = versionInfo.servicePackLevel
168+
versionOutput["Post-SP patches applied"] = versionInfo.patched
169+
170+
return versionOutput
171+
end
172+
173+
174+
--- Returns formatted output for the given instance
175+
local function create_instance_output_table( instance )
176+
177+
-- if we didn't get anything useful (due to errors or the port not actually
178+
-- being SQL Server), don't report anything
179+
if not ( instance.instanceName or instance.version ) then return nil end
180+
181+
local instanceOutput = stdnse.output_table()
182+
183+
instanceOutput["Instance name"] = instance.instanceName
184+
if instance.version then
185+
instanceOutput["Version"] = create_version_output_table( instance.version )
186+
end
187+
if instance.port then instanceOutput["TCP port"] = instance.port.number end
188+
instanceOutput["Named pipe"] = instance.pipeName
189+
instanceOutput["Clustered"] = instance.isClustered
190+
191+
return instanceOutput
192+
193+
end
194+
195+
196+
--- Processes a single instance, attempting to determine its version, etc.
197+
local function process_instance( instance )
198+
199+
local foundVersion = false
200+
local ssnetlibVersion
201+
202+
-- If possible and allowed (see 'mssql.scanned-ports-only' argument), we'll
203+
-- connect to the instance to get an accurate version number
204+
if ( instance:HasNetworkProtocols() ) then
205+
local ssnetlibVersion
206+
foundVersion, ssnetlibVersion = mssql.Helper.GetInstanceVersion( instance )
207+
if ( foundVersion ) then
208+
instance.version = ssnetlibVersion
209+
stdnse.debug1("Retrieved SSNetLib version for %s.", instance:GetName() )
210+
else
211+
stdnse.debug1("Could not retrieve SSNetLib version for %s.", instance:GetName() )
212+
end
213+
end
214+
215+
-- If we didn't get a version from SSNetLib, give the user some detail as to why
216+
if ( not foundVersion ) then
217+
if ( not instance:HasNetworkProtocols() ) then
218+
stdnse.debug1("%s has no network protocols enabled.", instance:GetName() )
219+
end
220+
if ( instance.version ) then
221+
stdnse.debug1("Using version number from SSRP response for %s.", instance:GetName() )
222+
else
223+
stdnse.debug1("Version info could not be retrieved for %s.", instance:GetName() )
224+
end
225+
end
226+
227+
-- Give some version info back to Nmap
228+
if ( instance.port and instance.version ) then
229+
instance.version:PopulateNmapPortVersion( instance.port )
230+
nmap.set_port_version( instance.host, instance.port)
231+
end
232+
233+
end
234+
235+
236+
action = function( host )
237+
local scriptOutput = stdnse.output_table()
238+
239+
local status, instanceList = mssql.Helper.GetTargetInstances( host )
240+
-- if no instances were targeted, then display info on all
241+
if ( not status ) then
242+
if ( not mssql.Helper.WasDiscoveryPerformed( host ) ) then
243+
mssql.Helper.Discover( host )
244+
end
245+
instanceList = mssql.Helper.GetDiscoveredInstances( host )
246+
end
247+
248+
249+
if ( not instanceList ) then
250+
return stdnse.format_output( false, instanceList or "" )
251+
else
252+
for _, instance in ipairs( instanceList ) do
253+
if instance.serverName then
254+
scriptOutput["Windows server name"] = instance.serverName
255+
break
256+
end
257+
end
258+
for _, instance in pairs( instanceList ) do
259+
process_instance( instance )
260+
scriptOutput[instance:GetName()] = create_instance_output_table( instance )
261+
end
262+
end
263+
264+
return scriptOutput
265+
end
266+

0 commit comments

Comments
 (0)
Please sign in to comment.