Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Full Tutorial is available here - [Nmap Dashboard using Grafana](https://hackertarget.com/nmap-dashboard-with-grafana/)

![Grafana Dashboard](https://hackertarget.com/images/nmap-grafana-dashboard.webp)

<img width="1471" height="857" alt="ss" src="https://github.com/user-attachments/assets/d31776b1-9cb5-44b7-aaed-918a24461118" />
## Overview

The project consists of two main components:
Expand Down Expand Up @@ -61,6 +61,17 @@ Once the container is up and running, access the Grafana dashboard through your
http://localhost:3000
```

5. **Auto-Nmap Usage**

Once the container is up and running, access the Grafana dashboard through your web browser:

```
cd data
source nmap_auto.sh
nmap {target}
```


Use the default Grafana credentials (admin/admin) unless changed in the configuration. The Nmap dashboard should be loaded with the data from your Nmap scans.

Multiple scans can be reviewed within the DB and the Nmap Dashboard time filters can be used to the view the scan information based on the time stamps from the scans.
Expand Down
62 changes: 62 additions & 0 deletions data/nmap-auto.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/bin/bash
# nmap_auto.sh

original_nmap() {
local args=("$@")
local has_script=false
local has_sv=false
local has_xml=false

for arg in "${args[@]}"; do
case "$arg" in
--script=*|--script) has_script=true ;;
-sV) has_sv=true ;;
-oX*) has_xml=true ;;
esac
done

if [ "$has_script" = false ]; then
args+=(--script=vulners,http-title,ssl-cert)
echo "Auto-added: --script=vulners,http-title,ssl-cert"
fi

if [ "$has_sv" = false ]; then
args+=(-sV)
echo "Auto-added: -sV"
fi

if [ "$has_xml" = false ]; then
args+=(-oX output.xml)
echo "Auto-added: -oX output.xml"
fi

echo "Running: nmap ${args[*]}"
command nmap "${args[@]}"
local exit_code=$?

if [ $exit_code -eq 0 ]; then
echo "Scan was completed"

if [ -f "nmap-to-sqlite.py" ]; then
if ls *.xml 1> /dev/null 2>&1; then
echo "Python script is running..."
xml_file=$(ls *.xml | head -n 1)
python3 nmap-to-sqlite.py "$xml_file"
echo 'Run successful!'

rm *.xml
echo "XML files deleted"
else
echo "No XML output found"
fi
else
echo "nmap-to-sqlite.py can't find"
fi
else
echo "Nmap failed"
fi

return $exit_code
}

alias nmap='original_nmap'
40 changes: 36 additions & 4 deletions data/nmap-to-sqlite.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,31 @@ def parse_nmap_xml(xml_file):
service_ostype = service.get('ostype', None) if service else None
service_info = (service_product if service_product else '') + (' ' + service_version if service_version else '')
http_title = None
http_headers = None
ssl_common_name = None
ssl_issuer = None

scripts = port.findall('script')
exploit_info = []
for script in scripts:
if script.get('id') == 'http-title':
http_title = script.get('output')
elif script.get('id') == 'http-headers':
http_headers = script.get('output')
elif script.get('id') == 'vulners':
for i in script.findall('.//table'):
if i.find("elem[@key='type']") is None or i.find("elem[@key='type']").text != 'cve':
continue
else:
exc_dic = {}
for x in i.findall('elem'):
key = x.get('key')
val = x.text
if key and val:
exc_dic[key] = val
if exc_dic:
exploit_info.append(exc_dic)

elif script.get('id') == 'ssl-cert':
for table in script.findall('table'):
if table.get('key') == 'subject':
Expand All @@ -88,6 +106,14 @@ def parse_nmap_xml(xml_file):
if 'commonName' in issuer_elems:
ssl_issuer = f"{issuer_elems.get('commonName')} {issuer_elems.get('organizationName', '')}".strip()

if service is not None:
cpes = [cpe.text for cpe in service.findall('cpe')]
cpes_str = ",".join(cpes) if cpes else ""

exploit_str = None
if exploit_info:
exploit_str = "; ".join(", ".join(f"{k}={v}" for k, v in e.items()) for e in exploit_info)

if service_ostype and os == 'Unknown':
os = service_ostype

Expand All @@ -98,12 +124,15 @@ def parse_nmap_xml(xml_file):
'service_name': service_name,
'service_info': service_info,
'http_title': http_title,
'http_headers': http_headers,
'ssl_common_name': ssl_common_name,
'ssl_issuer': ssl_issuer
'ssl_issuer': ssl_issuer,
'cpes': cpes_str,
'exploit': exploit_str
})

extraports = ports_element.find('extraports')
if len(extraports):
if extraports is not None and len(extraports):
extraports_count = int(extraports.get('count', '0'))
extraports_state = extraports.get('state', '')
if extraports_state == 'closed':
Expand Down Expand Up @@ -178,8 +207,11 @@ def create_database(db_name):
service_name TEXT,
service_info TEXT,
http_title TEXT,
http_headers TEXT,
ssl_common_name TEXT,
ssl_issuer TEXT,
cpes TEXT,
exploit TEXT,
FOREIGN KEY (scan_id) REFERENCES scans (id),
FOREIGN KEY (host_id) REFERENCES hosts (id))''')

Expand All @@ -199,8 +231,8 @@ def insert_data(conn, scan, hosts):
host_id = c.lastrowid

for port in host['ports']:
c.execute("INSERT INTO ports (scan_id, host_id, port, protocol, state, service_name, service_info, http_title, ssl_common_name, ssl_issuer) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
(scan_id, host_id, port['port'], port['protocol'], port['state'], port['service_name'], port['service_info'], port['http_title'], port['ssl_common_name'], port['ssl_issuer']))
c.execute("INSERT INTO ports (scan_id, host_id, port, protocol, state, service_name, service_info, http_title, http_headers, cpes, exploit, ssl_common_name, ssl_issuer) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
(scan_id, host_id, port['port'], port['protocol'], port['state'], port['service_name'], port['service_info'], port['http_title'], port['http_headers'], port['cpes'], port['exploit'], port['ssl_common_name'], port['ssl_issuer']))

conn.commit()

Expand Down
Loading