Using Nmap As a Lightweight Vulnerability Scanner
Yesterday, Bojan wrote a nice diary[1] about the power of the Nmap scripting language (based on LUA). The well-known port scanner can be extended with plenty of scripts that are launched depending on the detected ports. When I read Bojan's diary, it reminded me of an old article[2] that I wrote on my blog a long time ago. The idea was to use Nmap as a lightweight vulnerability scanner. Nmap has a scan type that tries to determine the service/version information running behind an open port (enabled with the '-sV' flag). Based on this information, the script looks for interesting CVE in a flat database. Unfortunately, the script was developed by a third-party developer and was never integrated into the official list of scripts.
However, a second project was kicked off and integrated into Nmap: The vulners[3] script. The principle is the same: You scan the host (with '-sV') and, for each identified service, the script performs a lookup in the CVE database. Example:
root@kali:~# nmap -sV --script=vulners -v x.x.x.x
Starting Nmap 7.80 ( https://nmap.org ) at 2020-05-07 17:28 CEST
NSE: Loaded 46 scripts for scanning.
NSE: Script Pre-scanning.
Initiating NSE at 17:28
Completed NSE at 17:28, 0.00s elapsed
Initiating NSE at 17:28
Completed NSE at 17:28, 0.00s elapsed
Initiating Ping Scan at 17:28
Scanning x.x.x.x [4 ports]
Completed Ping Scan at 17:28, 0.19s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 17:28
Completed Parallel DNS resolution of 1 host. at 17:28, 2.17s elapsed
Initiating SYN Stealth Scan at 17:28
Scanning x.x.x.x [1000 ports]
Discovered open port 443/tcp on x.x.x.x
Discovered open port 3389/tcp on x.x.x.x
Discovered open port 445/tcp on x.x.x.x
Discovered open port 21/tcp on x.x.x.x
Discovered open port 3306/tcp on x.x.x.x
Discovered open port 135/tcp on x.x.x.x
Discovered open port 139/tcp on x.x.x.x
Discovered open port 80/tcp on x.x.x.x
Discovered open port 49158/tcp on x.x.x.x
Discovered open port 3800/tcp on x.x.x.x
Discovered open port 49160/tcp on x.x.x.x
Discovered open port 49154/tcp on x.x.x.x
Discovered open port 49152/tcp on x.x.x.x
Discovered open port 49153/tcp on x.x.x.x
Discovered open port 49155/tcp on x.x.x.x
Discovered open port 49157/tcp on x.x.x.x
Completed SYN Stealth Scan at 17:28, 5.58s elapsed (1000 total ports)
Initiating Service scan at 17:28
Scanning 16 services on x.x.x.x
Service scan Timing: About 56.25% done; ETC: 17:30 (0:00:44 remaining) [70/1471]
Completed Service scan at 17:30, 84.04s elapsed (16 services on 1 host)
NSE: Script scanning x.x.x.x.
Initiating NSE at 17:30
Completed NSE at 17:30, 6.91s elapsed
Initiating NSE at 17:30
Completed NSE at 17:30, 1.55s elapsed
Nmap scan report for x.x.x.x
Host is up (0.19s latency).
Not shown: 984 closed ports
PORT STATE SERVICE VERSION
21/tcp open ftp FileZilla ftpd 0.9.41 beta
80/tcp open http Apache httpd 2.4.17 ((Win32) OpenSSL/1.0.2d PHP/5.6.20)
|_http-server-header: Apache/2.4.17 (Win32) OpenSSL/1.0.2d PHP/5.6.20
| vulners:
| cpe:/a:apache:http_server:2.4.17:
| CVE-2017-7679 7.5 https://vulners.com/cve/CVE-2017-7679
| CVE-2017-7668 7.5 https://vulners.com/cve/CVE-2017-7668
| CVE-2017-3169 7.5 https://vulners.com/cve/CVE-2017-3169
| CVE-2017-3167 7.5 https://vulners.com/cve/CVE-2017-3167
| CVE-2019-0211 7.2 https://vulners.com/cve/CVE-2019-0211
| CVE-2018-1312 6.8 https://vulners.com/cve/CVE-2018-1312
| CVE-2017-15715 6.8 https://vulners.com/cve/CVE-2017-15715
| CVE-2017-9788 6.4 https://vulners.com/cve/CVE-2017-9788
| CVE-2019-0217 6.0 https://vulners.com/cve/CVE-2019-0217
| CVE-2020-1927 5.8 https://vulners.com/cve/CVE-2020-1927
| CVE-2019-10098 5.8 https://vulners.com/cve/CVE-2019-10098
| CVE-2020-1934 5.0 https://vulners.com/cve/CVE-2020-1934
| CVE-2019-0220 5.0 https://vulners.com/cve/CVE-2019-0220
| CVE-2019-0196 5.0 https://vulners.com/cve/CVE-2019-0196
| CVE-2018-17199 5.0 https://vulners.com/cve/CVE-2018-17199
| CVE-2017-9798 5.0 https://vulners.com/cve/CVE-2017-9798
| CVE-2017-15710 5.0 https://vulners.com/cve/CVE-2017-15710
| CVE-2016-8743 5.0 https://vulners.com/cve/CVE-2016-8743
| CVE-2016-8740 5.0 https://vulners.com/cve/CVE-2016-8740
| CVE-2019-0197 4.9 https://vulners.com/cve/CVE-2019-0197
| CVE-2019-10092 4.3 https://vulners.com/cve/CVE-2019-10092 | CVE-2018-11763 4.3 https://vulners.com/cve/CVE-2018-11763
| CVE-2016-4975 4.3 https://vulners.com/cve/CVE-2016-4975
| CVE-2016-1546 4.3 https://vulners.com/cve/CVE-2016-1546
| CVE-2018-1283 3.5 https://vulners.com/cve/CVE-2018-1283
|_ CVE-2016-8612 3.3 https://vulners.com/cve/CVE-2016-8612
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
443/tcp open ssl/http Apache httpd 2.4.17 ((Win32) OpenSSL/1.0.2d PHP/5.6.20)
|_http-server-header: Apache/2.4.17 (Win32) OpenSSL/1.0.2d PHP/5.6.20
| vulners:
| cpe:/a:apache:http_server:2.4.17:
| CVE-2017-7679 7.5 https://vulners.com/cve/CVE-2017-7679
| CVE-2017-7668 7.5 https://vulners.com/cve/CVE-2017-7668
| CVE-2017-3169 7.5 https://vulners.com/cve/CVE-2017-3169
| CVE-2017-3167 7.5 https://vulners.com/cve/CVE-2017-3167
| CVE-2019-0211 7.2 https://vulners.com/cve/CVE-2019-0211
| CVE-2018-1312 6.8 https://vulners.com/cve/CVE-2018-1312
| CVE-2017-15715 6.8 https://vulners.com/cve/CVE-2017-15715
| CVE-2017-9788 6.4 https://vulners.com/cve/CVE-2017-9788
| CVE-2019-0217 6.0 https://vulners.com/cve/CVE-2019-0217
| CVE-2020-1927 5.8 https://vulners.com/cve/CVE-2020-1927
| CVE-2019-10098 5.8 https://vulners.com/cve/CVE-2019-10098
| CVE-2020-1934 5.0 https://vulners.com/cve/CVE-2020-1934
| CVE-2019-0220 5.0 https://vulners.com/cve/CVE-2019-0220
| CVE-2019-0196 5.0 https://vulners.com/cve/CVE-2019-0196
| CVE-2018-17199 5.0 https://vulners.com/cve/CVE-2018-17199
| CVE-2017-9798 5.0 https://vulners.com/cve/CVE-2017-9798
| CVE-2017-15710 5.0 https://vulners.com/cve/CVE-2017-15710
| CVE-2016-8743 5.0 https://vulners.com/cve/CVE-2016-8743
| CVE-2016-8740 5.0 https://vulners.com/cve/CVE-2016-8740
| CVE-2019-0197 4.9 https://vulners.com/cve/CVE-2019-0197
| CVE-2019-10092 4.3 https://vulners.com/cve/CVE-2019-10092
| CVE-2018-11763 4.3 https://vulners.com/cve/CVE-2018-11763
| CVE-2016-4975 4.3 https://vulners.com/cve/CVE-2016-4975
| CVE-2016-1546 4.3 https://vulners.com/cve/CVE-2016-1546
| CVE-2018-1283 3.5 https://vulners.com/cve/CVE-2018-1283
|_ CVE-2016-8612 3.3 https://vulners.com/cve/CVE-2016-8612
445/tcp open microsoft-ds Microsoft Windows Server 2008 R2 - 2012 microsoft-ds
3306/tcp open mysql MariaDB (unauthorized)
3389/tcp open ssl/ms-wbt-server?
3800/tcp open tcpwrapped
49152/tcp open msrpc Microsoft Windows RPC
49153/tcp open msrpc Microsoft Windows RPC
49154/tcp open msrpc Microsoft Windows RPC
49155/tcp open msrpc Microsoft Windows RPC
49157/tcp open msrpc Microsoft Windows RPC
49158/tcp open msrpc Microsoft Windows RPC
49160/tcp open msrpc Microsoft Windows RPC
Service Info: OSs: Windows, Windows Server 2008 R2 - 2012; CPE: cpe:/o:microsoft:windows
NSE: Script Post-scanning.
Initiating NSE at 17:30
Completed NSE at 17:30, 0.00s elapsed
Initiating NSE at 17:30
Completed NSE at 17:30, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 100.83 seconds
Raw packets sent: 1022 (44.944KB) | Rcvd: 1001 (40.108KB)
The difference between the two scripts is the way they search for CVE. In this case, the script requires Internet access to query the Vulners API[4].
Note that the script accepts one parameter: You can specify the minimum CVSS ("Common Vulnerability Scoring System") score to display:
root@kali:~# nmap -sV --script=vulners --script-args mincvss=8 x.x.x.x
Once you get some results, our next goal could be to automatically process the results. Let's use a few lines of Python to parse the Nmap XML output (that is created via the '-oX' flag):
root@kali:~# nmap -sV --script=vulners -oX x.x.x.x.xml x.x.x.x
root@kali:~# python3
Python 3.7.7 (default, Mar 10 2020, 13:18:53)
[GCC 9.2.1 20200306] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from libnmap.parser import NmapParser
>>> p = NmapParser.parse_fromfile("x.x.x.x.xml")
>>> for host in p.hosts:
... for svc in host.services:
... for script in svc.scripts_results:
... output = script.get("output")
... print(output)
...
cpe:/a:microsoft:sql_server:2014:
CVE-2015-1763 8.5 https://vulners.com/cve/CVE-2015-1763
CVE-2015-1762 7.1 https://vulners.com/cve/CVE-2015-1762
CVE-2020-0618 6.5 https://vulners.com/cve/CVE-2020-0618
CVE-2019-1068 6.5 https://vulners.com/cve/CVE-2019-1068
CVE-2016-7253 6.5 https://vulners.com/cve/CVE-2016-7253
CVE-2016-7250 6.5 https://vulners.com/cve/CVE-2016-7250
CVE-2015-1761 6.5 https://vulners.com/cve/CVE-2015-1761
CVE-2017-8516 5.0 https://vulners.com/cve/CVE-2017-8516
CVE-2014-1820 4.3 https://vulners.com/cve/CVE-2014-1820
Nice! So, we have a lightweight vulnerability scanner and we can automate the reporting. Another idea could be to perform a diff of a first scan - used as a baseline - and a second one (performed at regular intervals. Ndiff[5] is a great tool to achieve this.
In conclusion, a tool can be for multiple purposes, offensive VS. defensive security!
[1] https://isc.sans.edu/forums/diary/Scanning+with+nmaps+NSE+scripts/26096/
[2] https://blog.rootshell.be/2010/06/03/vulnerability-scanner-within-nmap/
[3] https://github.com/vulnersCom/nmap-vulners
[4] https://vulners.com/api/v3/
[5] https://nmap.org/ndiff/
Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key
| Reverse-Engineering Malware: Advanced Code Analysis | Online | Greenwich Mean Time | Oct 27th - Oct 31st 2025 |

Comments