/', api.port_details, name='api_port'),
- path('view/pdf/', pdf.reportPDFView, name='reportPDFView')
+ path('view/pdf/', pdf.reportPDFView, name='reportPDFView'),
+ path('view/network/', network.visjs, name='network_view')
]
diff --git a/views.py b/views.py
index 90c7df0..143db40 100644
--- a/views.py
+++ b/views.py
@@ -16,7 +16,7 @@ def setscanfile(request, scanfile):
if 'scanfile' in request.session:
del(request.session['scanfile'])
- return render(request, 'nmapreport/index.html', { 'out': '', 'table': '', 'scaninfo': '', 'scandetails': '', 'trhost': '' })
+ return render(request, 'nmapreport/nmap_hostdetails.html', { 'js': '' })
def port(request, port):
@@ -56,20 +56,7 @@ def details(request, address):
noteshost[m.group(1)][m.group(2)] = open('/opt/notes/'+nf, 'r').read()
# collect all cve in cvehost dict
- cvehost = {}
- cvefiles = os.listdir('/opt/notes')
- for cf in cvefiles:
- m = re.match('^('+scanmd5+')_([a-z0-9]{32,32})\.([0-9]+)\.cve$', cf)
- if m is not None:
- if m.group(1) not in cvehost:
- cvehost[m.group(1)] = {}
-
- if m.group(2) not in cvehost[m.group(1)]:
- cvehost[m.group(1)][m.group(2)] = {}
-
- cvehost[m.group(1)][m.group(2)][m.group(3)] = open('/opt/notes/'+cf, 'r').read()
-
-
+ cvehost = get_cve(scanmd5)
r['trhead'] = '| Port | Product / Version | Extra Info | |
'
pel=0
@@ -87,14 +74,21 @@ def details(request, address):
if ai['@addrtype'] == 'ipv4':
saddress = ai['@addr']
-
if str(saddress) == address:
- #r['out'] = json.dumps(i, indent=4)
- h = 'No Hostname'
- if 'hostnames' in i:
- if type(i['hostnames']) is dict and 'hostname' in i['hostnames']:
- if '@name' in i['hostnames']['hostname']:
- h = ''+i['hostnames']['hostname']['@name']+''
+ hostname = ''
+ if 'hostnames' in i and type(i['hostnames']) is dict:
+ # hostname = json.dumps(i['hostnames'])
+ if 'hostname' in i['hostnames']:
+ hostname += '
'
+ if type(i['hostnames']['hostname']) is list:
+ for hi in i['hostnames']['hostname']:
+ hostname += ''+hi['@type']+': '+hi['@name']+'
'
+ else:
+ hostname += ''+i['hostnames']['hostname']['@type']+': '+i['hostnames']['hostname']['@name']+'
'
+
+ r['address'] = html.escape(str(saddress))
+ r['hostname'] = hostname
+ r['scanfile'] = request.session['scanfile']
labelout = ''
if scanmd5 in labelhost:
@@ -103,14 +97,11 @@ def details(request, address):
labelmargin = labelToMargin(labelhost[scanmd5][addressmd5])
labelout = ''+html.escape(labelhost[scanmd5][addressmd5])+''
- r['scaninfo'] = ''+\
- '
Host Details:
'+html.escape(address)+'
'+h+labelout+''+\
- '
'+\
- '
'+\
- '
'+\
- '
'
+ r['label'] = html.escape(labelhost[scanmd5][addressmd5])
+ r['labelcolor'] = labelcolor
rmdupl = {}
+ r['tr'] = {}
for pobj in i['ports']['port']:
if type(pobj) is dict:
p = pobj
@@ -168,6 +159,17 @@ def details(request, address):
else:
cpe = ''+html.escape(p['service']['cpe'])+'
'
+ r['tr'][p['@portid']] = {
+ 'service': p['service']['@name'],
+ 'protocol': p['@protocol'],
+ 'portid': p['@portid'],
+ 'product': z,
+ 'version': v,
+ 'state': p['state']['@state'],
+ 'reason': p['state']['@reason'],
+ 'extrainfo': e,
+ 'pel': str(pel)
+ }
r['trhost'] += ''+\
''+p['service']['@name']+' '+\
@@ -183,11 +185,27 @@ def details(request, address):
' | '+\
'
'
elif p['state']['@state'] == 'filtered':
+ r['tr'][p['@portid']] = {
+ 'service': p['service']['@name'],
+ 'protocol': p['@protocol'],
+ 'portid': p['@portid'],
+ 'state': p['state']['@state'],
+ 'reason': p['state']['@reason'],
+ 'pel': str(pel)
+ }
r['trhost'] += ''+p['@protocol']+' / '+p['@portid']+' '+\
''+p['service']['@name']+' | '+\
'State: filtered Reason: '+p['state']['@reason']+' | '+\
' |
'
else:
+ r['tr'][p['@portid']] = {
+ 'service': p['service']['@name'],
+ 'protocol': p['@protocol'],
+ 'portid': p['@portid'],
+ 'state': p['state']['@state'],
+ 'reason': p['state']['@reason'],
+ 'pel': str(pel)
+ }
r['trhost'] += ''+p['@protocol']+' / '+p['@portid']+' '+\
''+p['service']['@name']+' | '+\
'State: '+p['state']['@state']+' Reason: '+p['state']['@reason']+' | '+\
@@ -207,43 +225,37 @@ def details(request, address):
' '+base64.b64decode(urllib.parse.unquote(notesb64)).decode('ascii')+\
' '+\
''
-
- #notesout = '
contains notes'
- #removenotes = 'Remove notes'
+ r['notes'] = base64.b64decode(urllib.parse.unquote(notesb64)).decode('ascii')
cveout = ''
if scanmd5 in cvehost:
if addressmd5 in cvehost[scanmd5]:
- for cveport in cvehost[scanmd5][addressmd5]:
- cvejson = json.loads(cvehost[scanmd5][addressmd5][cveport])
- # r['out'] = json.dumps(cvejson, indent=4)
- for cveobj in cvejson:
-
- cverefout = ''
- for cveref in cveobj['references']:
- cverefout += ''+cveref+'
'
-
- cveexdbout = ''
- if 'exploit-db' in cveobj:
- cveexdbout = '
'
-
- cveout += ''+\
- '
'+html.escape(cveobj['id'])+' '+html.escape(cveobj['summary'])+'
'+\
- '
References:
'+cverefout+'
'+\
- cveexdbout+\
- '
'
-
- r['table'] += ''+\
- '
CVE LIST:'+\
- cveout+\
- '
'+\
- '
'
-
- r['pretable'] = ''
- return render(request, 'nmapreport/index.html', r)
+ return render(request, 'nmapreport/nmap_portdetails.html', r)
def index(request, filterservice="", filterportid=""):
r = {}
+ gitcmd = os.popen('cd /opt/nmapdashboard/nmapreport && git rev-parse --abbrev-ref HEAD')
+ r['webmapver'] = 'WebMap '+gitcmd.read()+'
This project is currently a beta, please DO NOT expose WebMap to internet.
This version is NOT production ready.'
+
if 'scanfile' in request.session:
oo = xmltodict.parse(open('/opt/xml/'+request.session['scanfile'], 'r').read())
r['out2'] = json.dumps(oo['nmaprun'], indent=4)
@@ -270,39 +285,8 @@ def index(request, filterservice="", filterportid=""):
# no file selected
xmlfiles = os.listdir('/opt/xml')
- r['table'] = ''+\
- ' Put your Nmap XML files in
/opt/xml/ directory, example:
'+\
- '
nmap -A -T4 -oX myscan.xml 192.168.1.0/24
'+\
- ' mv myscan.xml <docker webmap xml dir>
'+\
- ' # or you can copy myscan.xml to the webmap container:
'+\
- ' docker cp myscan.xml webmap:/opt/xml/
'+\
- '
'
-
- r['table'] += ''+\
- '
'+\
- '

'+\
- '
Made with by Andrea theMiddle Menin'+\
- '
'+\
- '
'+\
- '

'+\
- '
A Rev3rse Security Project'+\
- ' '+\
- '
'+\
- '
'+\
- '
'
-
-
- r['trhost'] = ''
- r['trhead'] = '
| Filename | Scan Start Time | Hosts | |
'
+ r['tr'] = {}
+ r['stats'] = { 'po':0, 'pc':0, 'pf':0}
xmlfilescount = 0
for i in xmlfiles:
@@ -311,7 +295,12 @@ def index(request, filterservice="", filterportid=""):
xmlfilescount = (xmlfilescount + 1)
- oo = xmltodict.parse(open('/opt/xml/'+i, 'r').read())
+ try:
+ oo = xmltodict.parse(open('/opt/xml/'+i, 'r').read())
+ except:
+ r['tr'][i] = {'filename':html.escape(i), 'startstr': 'Incomplete / Invalid', 'hostnum':0, 'href':'#!', 'portstats':{'po':0,'pc':0,'pf':0}}
+ continue
+
r['out2'] = json.dumps(oo['nmaprun'], indent=4)
o = json.loads(r['out2'])
@@ -328,29 +317,23 @@ def index(request, filterservice="", filterportid=""):
else:
viewhref = '/" disabled="disabled'
- r['trhost'] += ''+\
- ' | '+html.escape(i)+' | '+\
- ' '+html.escape(o['@startstr'])+' | '+\
- ' '+hostnum+' | '+\
- ' view | '+\
- '
'
+ portstats = nmap_ports_stats(i)
- r['scaninfo'] = 'Select a Nmap XML fileNmap XML files: '+ str(xmlfilescount) +'
'
+ r['stats']['po'] = (r['stats']['po'] + portstats['po'])
+ r['stats']['pc'] = (r['stats']['pc'] + portstats['pc'])
+ r['stats']['pf'] = (r['stats']['pf'] + portstats['pf'])
- return render(request, 'nmapreport/index.html', r)
+ r['tr'][i] = {'filename':html.escape(i), 'startstr': html.escape(o['@startstr']), 'hostnum':hostnum, 'href':viewhref, 'portstats':portstats}
- scanmd5 = hashlib.md5(str(request.session['scanfile']).encode('utf-8')).hexdigest()
- r['topcontainer'] = ''
+ r['stats']['xmlcount'] = xmlfilescount
+
+ return render(request, 'nmapreport/nmap_xmlfiles.html', r)
+
+
+ scanmd5 = hashlib.md5(str(request.session['scanfile']).encode('utf-8')).hexdigest()
+ r['scanfile'] = html.escape(str(request.session['scanfile']))
+ r['scanmd5'] = scanmd5
# collect all labels in labelhost dict
labelhost = {}
@@ -373,18 +356,7 @@ def index(request, filterservice="", filterportid=""):
noteshost[m.group(1)][m.group(2)] = open('/opt/notes/'+nf, 'r').read()
# collect all cve in cvehost dict
- cvehost = {}
- cvefiles = os.listdir('/opt/notes')
- for cf in cvefiles:
- m = re.match('^('+scanmd5+')_([a-z0-9]{32,32})\.([0-9]+)\.cve$', cf)
- if m is not None:
- if m.group(1) not in cvehost:
- cvehost[m.group(1)] = {}
-
- if m.group(2) not in cvehost[m.group(1)]:
- cvehost[m.group(1)][m.group(2)] = {}
-
- cvehost[m.group(1)][m.group(2)][m.group(3)] = open('/opt/notes/'+cf, 'r').read()
+ cvehost = get_cve(scanmd5)
tableout = ''
hostsup = 0
@@ -392,8 +364,8 @@ def index(request, filterservice="", filterportid=""):
ports = { 'open': 0, 'closed': 0, 'filtered': 0 }
allostypelist, sscount, picount, cpe = {}, {}, {}, {}
- r['trhost'] = ''
- r['trhead'] = '| Host | Port State | Tot Ports | Services | Ports | |
'
+ r['tr'] = {}
+ r['stats'] = {}
for ik in o['host']:
@@ -404,9 +376,15 @@ def index(request, filterservice="", filterportid=""):
i = o['host']
hostname = ''
-
if 'hostnames' in i and type(i['hostnames']) is dict:
- hostname += '
'+str(i['hostnames']['hostname']['@name'])+''
+ # hostname = json.dumps(i['hostnames'])
+ if 'hostname' in i['hostnames']:
+ hostname += '
'
+ if type(i['hostnames']['hostname']) is list:
+ for hi in i['hostnames']['hostname']:
+ hostname += ''+hi['@type']+': '+hi['@name']+'
'
+ else:
+ hostname += ''+i['hostnames']['hostname']['@type']+': '+i['hostnames']['hostname']['@name']+'
'
if i['status']['@state'] == 'up':
hostsup = (hostsup + 1)
@@ -423,6 +401,7 @@ def index(request, filterservice="", filterportid=""):
address = ai['@addr']
addressmd5 = hashlib.md5(str(address).encode('utf-8')).hexdigest()
+ cpe[address] = {}
striggered = False
if 'ports' in i and 'port' in i['ports']:
@@ -447,19 +426,13 @@ def index(request, filterservice="", filterportid=""):
pp[p['@portid']] = p['@portid']
# cpehtml = ''
- cpe[address] = {}
if 'cpe' in p['service']:
if type(p['service']['cpe']) is list:
for cpei in p['service']['cpe']:
- if p['@portid'] not in cpe[address]:
- cpe[address][p['@portid']] = {}
-
- cpe[address][p['@portid']][cpei] = cpei
+ cpe[address][cpei] = cpei
else:
- if p['@portid'] not in cpe[address]:
- cpe[address][p['@portid']] = {}
-
- cpe[address][p['@portid']][p['service']['cpe']] = p['service']['cpe']
+ cpe[address][p['service']['cpe']] = p['service']['cpe']
+
if '@ostype' in p['service']:
if p['service']['@ostype'] in allostypelist:
@@ -512,11 +485,14 @@ def index(request, filterservice="", filterportid=""):
poclass = 'zeroportopen'
labelout = ''
+ newlabelout = ''
if scanmd5 in labelhost:
if addressmd5 in labelhost[scanmd5]:
labelcolor = labelToColor(labelhost[scanmd5][addressmd5])
labelmargin = labelToMargin(labelhost[scanmd5][addressmd5])
labelout = ''+html.escape(labelhost[scanmd5][addressmd5])+''
+ newlabelout = ''+html.escape(labelhost[scanmd5][addressmd5])+'
'+\
+ ''
notesout,notesb64,removenotes = '','',''
if scanmd5 in noteshost:
@@ -529,50 +505,44 @@ def index(request, filterservice="", filterportid=""):
cvecount = 0
if scanmd5 in cvehost:
if addressmd5 in cvehost[scanmd5]:
- for cveport in cvehost[scanmd5][addressmd5]:
- cvejson = json.loads(cvehost[scanmd5][addressmd5][cveport])
- for cveobj in cvejson:
- cvecount = (cvecount + 1)
+ cvejson = json.loads(cvehost[scanmd5][addressmd5])
+ for cveobj in cvejson:
+ cvecount = (cvecount + 1)
cveout = '
'+str(cvecount)+' CVE found'
- # removenotes = 'Remove notes'
if (filterservice != "" and striggered is True) or (filterportid != "" and striggered is True) or (filterservice == "" and filterportid == ""):
- portstateout = ''+\
- ' '+str(po)+' '+\
+ portstateout = ' | '
if (filterservice != "" and striggered is True):
- portstateout = ' '+\
- ' '+str(po)+' '+\
+ portstateout = ' | '
- r['trhost'] += ' '+\
- ' '+str(hostindex)+''+\
- ' '+ostype+' '+\
- ' '+str(address)+''+hostname+''+\
- notesout+\
- cveout+\
- ' | '+\
- portstateout+\
- ' '+str((po + pf + pc))+' | '+\
- ' '+str(services[0:-2])+' | '+\
- ' '+str(tdports[0:-2])+' | '+\
- ' '+\
- ' '+\
- ' - Vulnerable
'+\
- ' - Critical
'+\
- ' - Warning
'+\
- ' - Checked
'+\
- ' - Remove label
'+\
- ' '+\
- ' - Insert notes
'+\
- ' '+removenotes+\
- ' '+\
- labelout+\
- ' '+\
- ' | '+\
- ' '
+ r['tr'][address] = {
+ 'hostindex': str(hostindex),
+ 'hostname': hostname,
+ 'ostype': ostype,
+ 'notes': notesout,
+ 'cve': cveout,
+ 'portstate': portstateout,
+ 'po': po,
+ 'pc': pc,
+ 'pf': pf,
+ 'totports': str((po + pf + pc)),
+ 'services': str(services[0:-2]),
+ 'ports': str(tdports[0:-2]),
+ 'addressmd5': addressmd5,
+ 'removenotes': removenotes,
+ 'labelout': labelout,
+ 'newlabelout': newlabelout,
+ 'notesb64': notesb64,
+ 'notesout': notesout,
+ 'cveout': cveout
+ }
+
hostindex = (hostindex + 1)
# this fix single host report
@@ -584,43 +554,28 @@ def index(request, filterservice="", filterportid=""):
scaninfobox2 = ' '
scaninfobox3 = ' '
else:
- scaninfobox2 = ''+\
- ' Filter port / service: '+html.escape(filterportid+filterservice)+' '+\
- ' Total Ports: '+str(totports)+' '+\
- ' Open Ports: '+str(ports['open'])+' '+\
- ' Closed Ports: '+str(ports['closed'])+' '+\
- ' Filtered Ports: '+str(ports['filtered'])+' '
+ scaninfobox2 = ' '+\
+ ' Filter port / service: '+html.escape(filterportid+filterservice)+' '+\
+ ' Total Ports: '+str(totports)+' '+\
+ ' Open Ports: '+str(ports['open'])+' '+\
+ ' Closed Ports: '+str(ports['closed'])+' '+\
+ ' Filtered Ports: '+str(ports['filtered'])+' '
scaninfobox3 = ' '
- r['scaninfo'] = ''+\
- ' '+\
- ' Scan Information '+\
- ' Ports Status '+\
- ' Top Ports / Services '+\
- ' '+\
- ' '+\
- ' '+\
- ' Start: '+o['@startstr']+' '+\
- ' Scan Type: '+o['scaninfo']['@type']+' '+\
- ' Scan Protocol: '+o['scaninfo']['@protocol']+' '+\
- ' Nmap Command: view details'+\
- ' '+\
- ' '+\
- scaninfobox2+\
- ' '+\
- ' '+\
- scaninfobox3+\
- ' '+\
- ' '
-
- r['scandetails'] = ' '+\
- ' '+o['@args']+' '+\
- ' '+\
- ' version: '+o['@version']+' '+\
- ' xmloutputversion: '+o['@xmloutputversion']+' '+\
- ' '+\
- ' '
-
+ r['stats'] = {
+ 'scaninfobox2': scaninfobox2,
+ 'scaninfobox3': scaninfobox3,
+ 'startstr': o['@startstr'],
+ 'scantype': o['scaninfo']['@type'],
+ 'protocol': o['scaninfo']['@protocol'],
+ 'nmapver': o['@version'],
+ 'nmapargs': o['@args'],
+ 'xmlver': o['@xmloutputversion'],
+ 'hostsup': str(hostsup),
+ 'popen': ports['open'],
+ 'pclosed': ports['closed'],
+ 'pfiltered': ports['filtered']
+ }
allss = ''
allsslabels = ''
@@ -656,48 +611,35 @@ def index(request, filterservice="", filterportid=""):
allostypelinks += ' '+str(i)+', '
+ r['stats']['services'] = allss[0:-2]
+ r['stats']['portids'] = allpilinks[0:-2]
+ r['stats']['ostypes'] = allostypelinks[0:-2]
+
r['pretable'] = ''
+ r['js'] = ''
if filterservice == "" and filterportid == "":
- r['pretable'] += ' '+\
- ' '+\
- ' '+str(ports['open'])+'OPEN PORTS'+\
- ' '+str(ports['closed'])+'CLOSED PORTS'+\
- ' '+str(ports['filtered'])+'FILTERED PORTS'+\
- ' '+\
- ' '+\
- ' '+\
- ' '+\
- ' Services: Services: '+\
- ' '+\
- ' '+allss[0:-2]+'
'+\
- ' Top 10 Ports: '+allpilinks[0:-2]+'
'+\
- ' OS Type List: '+allostypelinks[0:-2]+''+\
- ' '+\
- ' '+\
- ' '+\
- ' '+\
- ' '
-
- r['pretable'] += ''
+ else:
+ r['pretablestyle'] = 'display:none;'
- r['pretable'] += ''
- #r['pretable'] += ' '+\
- #' '+\
- #' '
- r['pretable'] += ' '
+ cpedict = {}
+ #r['cpestring'] = ''
+ for cpeaddr in cpe:
+ for cpei in cpe[cpeaddr]:
+ if re.search('^cpe:.+:.+:.+:.+$', cpei) is not None:
+ #r['cpestring'] += cpei+' '
+ if cpei not in cpedict:
+ cpedict[cpei] = {}
+ if cpeaddr not in cpedict[cpei]:
+ cpedict[cpei][cpeaddr] = 1
+
+ r['cpestring'] = ' '
- return render(request, 'nmapreport/index.html', r)
+ return render(request, 'nmapreport/nmap_hostdetails.html', r)
+
+def about(request):
+ r = {}
+ return render(request, 'nmapreport/nmap_about.html', r)
From 3d7470cebaafab641176cefe99d112999e679569 Mon Sep 17 00:00:00 2001
From: theMiddleBlue
Date: Sun, 4 Nov 2018 17:53:59 +0000
Subject: [PATCH 19/77] update README
---
README.md | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 1ac6067..9455cac 100644
--- a/README.md
+++ b/README.md
@@ -3,11 +3,9 @@
A Web Dashbord for Nmap XML Report
-
+
-
-
-
+
## Table Of Contents
- [Usage](#usage)
@@ -41,6 +39,21 @@ Now point your browser to http://localhost:8000
$ curl -sL http://bit.ly/webmapsetup | bash
```
+### Upgrade from previous release
+```bash
+$ # stop running webmap container
+$ docker stop webmap
+
+$ # remove webmap container
+$ docker rm webmap
+
+$ # pull new image from dockerhub
+$ docker pull rev3rse/webmap
+
+$ # run WebMap
+$ curl -sL http://bit.ly/webmapsetup | bash
+```
+
## Video
-- coming soon...
@@ -69,6 +82,9 @@ thanks to the amazing API services by circl.lu, WebMap is able to looking for CV
Not all CPE are checked over the circl.lu API, but only when a specific version is specified
(for example: `cpe:/a:microsoft:iis:7.5` and not `cpe:/o:microsoft:windows`).
+## Network View
+
+
## Third Parts
- [Django](https://www.djangoproject.com)
- [Materialize CSS](https://materializecss.com)
From 142ef0ce62dc1f3531d293895396139b14a25c4f Mon Sep 17 00:00:00 2001
From: theMiddleBlue
Date: Sun, 4 Nov 2018 17:56:02 +0000
Subject: [PATCH 20/77] update README
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 9455cac..7201d64 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ A Web Dashbord for Nmap XML Report
- [Features](#features)
- [XML Filenames](#xml-filenames)
- [CVE and Exploits](#cve-and-exploits)
+- [Network View](#network-view)
- [Third Parts](#third-parts)
- [Security Issues](#security-issues)
- [Contributors](#contributors)
From 89f73a1da9df0d8d5c7f82fe1da6fe819973db0e Mon Sep 17 00:00:00 2001
From: theMiddleBlue
Date: Sun, 4 Nov 2018 18:01:18 +0000
Subject: [PATCH 21/77] fix and update dockerfile
---
docker/Dockerfile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 5b14b0c..c2de1c3 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -28,8 +28,8 @@ RUN mkdir /opt/xml && mkdir /opt/notes && \
RUN pip3 install Django requests xmltodict && \
cd /opt/ && django-admin startproject nmapdashboard && cd /opt/nmapdashboard && \
- git clone https://github.com/Rev3rseSecurity/WebMap.git && \
- mv WebMap nmapreport && cd nmapreport && git checkout v2/master
+ git clone https://github.com/Rev3rseSecurity/WebMap.git nmapreport && \
+ cd nmapreport && git checkout v2.1/master
COPY settings.py /opt/nmapdashboard/nmapdashboard/
COPY urls.py /opt/nmapdashboard/nmapdashboard/
From dcdad7004e73d74df8ff38c63eaa61576f6b8c28 Mon Sep 17 00:00:00 2001
From: theMiddleBlue
Date: Sun, 4 Nov 2018 18:07:04 +0000
Subject: [PATCH 22/77] update readme
---
README.md | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/README.md b/README.md
index 7201d64..7d4a7d3 100644
--- a/README.md
+++ b/README.md
@@ -68,6 +68,12 @@ $ curl -sL http://bit.ly/webmapsetup | bash
- Copy to clipboard as Nikto, Curl or Telnet commands
- Search for CVE and Exploits based on CPE collected by Nmap
+## Changes on v2.1
+- Better usage of Django template
+- Fixed some Nmap XML parse problems
+- Fixed CVE and Exploit collecting problems
+- Add new Network View
+
## XML Filenames
When creating the PDF version of the Nmap XML Report, the XML filename is used as document title on the first page.
WebMap will replace some parts of the filename as following:
@@ -93,6 +99,7 @@ Not all CPE are checked over the circl.lu API, but only when a specific version
- [Chart.js](https://www.chartjs.org)
- [Wkhtmltopdf](https://wkhtmltopdf.org)
- [API cve.circl.lu](https://cve.circl.lu)
+- [vis.js](http://visjs.org/)
## Security Issues
This app is not intended to be exposed on the internet. Please, **DO NOT expose** this app to the internet, use your localhost or,
@@ -109,5 +116,6 @@ I'll mention all contributors in this section of the README file.
- Neetx [@Neetx](https://github.com/Neetx) (bug on xml with no host up)
## Contacts
+In order to receive updates about this project, please follow me on twitter:
Twitter: [@Menin_TheMiddle](https://twitter.com/Menin_TheMiddle)
YouTube: [Rev3rseSecurity](https://www.youtube.com/rev3rsesecurity)
From a78e06ed4c945f364e784177414fced9a55fe756 Mon Sep 17 00:00:00 2001
From: theMiddleBlue
Date: Sun, 4 Nov 2018 18:12:23 +0000
Subject: [PATCH 23/77] update readme
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index 7d4a7d3..39382c5 100644
--- a/README.md
+++ b/README.md
@@ -55,6 +55,10 @@ $ # run WebMap
$ curl -sL http://bit.ly/webmapsetup | bash
```
+### Run without Docker
+This project is designed to run on a Docker container. IMHO it isn't a good idea to run this on a custom Django installation,
+but if you need it you can find all building steps inside the [Dockerfile](https://github.com/Rev3rseSecurity/WebMap/blob/v2.1/master/docker/Dockerfile).
+
## Video
-- coming soon...
From 1a83344ab6328a5b03160d1e2fb6b706d063a3d6 Mon Sep 17 00:00:00 2001
From: theMiddleBlue
Date: Sun, 4 Nov 2018 18:14:11 +0000
Subject: [PATCH 24/77] update readme
---
README.md | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 39382c5..1aa5f66 100644
--- a/README.md
+++ b/README.md
@@ -9,8 +9,8 @@ A Web Dashbord for Nmap XML Report
## Table Of Contents
- [Usage](#usage)
-- [Video](#video)
- [Features](#features)
+- [Changes on v2.1](#changes-on-v21)
- [XML Filenames](#xml-filenames)
- [CVE and Exploits](#cve-and-exploits)
- [Network View](#network-view)
@@ -59,9 +59,6 @@ $ curl -sL http://bit.ly/webmapsetup | bash
This project is designed to run on a Docker container. IMHO it isn't a good idea to run this on a custom Django installation,
but if you need it you can find all building steps inside the [Dockerfile](https://github.com/Rev3rseSecurity/WebMap/blob/v2.1/master/docker/Dockerfile).
-## Video
--- coming soon...
-
## Features
- Import and parse Nmap XML files
- Statistics and Charts on discovered services, ports, OS, etc...
From 1fbcdabe5df10e9f0dd31d2968ee22f737f39759 Mon Sep 17 00:00:00 2001
From: theMiddleBlue
Date: Sun, 4 Nov 2018 18:17:49 +0000
Subject: [PATCH 25/77] update readme
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index 1aa5f66..890b263 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,7 @@ A Web Dashbord for Nmap XML Report
- [Usage](#usage)
- [Features](#features)
- [Changes on v2.1](#changes-on-v21)
+- [PDF Report](#pdf-report)
- [XML Filenames](#xml-filenames)
- [CVE and Exploits](#cve-and-exploits)
- [Network View](#network-view)
@@ -75,6 +76,9 @@ but if you need it you can find all building steps inside the [Dockerfile](https
- Fixed CVE and Exploit collecting problems
- Add new Network View
+## PDF Report
+
+
## XML Filenames
When creating the PDF version of the Nmap XML Report, the XML filename is used as document title on the first page.
WebMap will replace some parts of the filename as following:
From 160b092e9b0473a345a4d92e79343c94cfd420f8 Mon Sep 17 00:00:00 2001
From: theMiddleBlue
Date: Sun, 4 Nov 2018 19:02:05 +0000
Subject: [PATCH 26/77] fix error when host not found
---
functions.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/functions.py b/functions.py
index 1938d22..dd672a8 100644
--- a/functions.py
+++ b/functions.py
@@ -46,6 +46,9 @@ def nmap_ports_stats(scanfile):
po,pc,pf = 0,0,0
+ if 'host' not in o:
+ return {'po':0,'pc':0,'pf':0}
+
for ik in o['host']:
if type(ik) is dict:
i = ik
From 4bc5be62abed9d1f8e4cadcf639c6c56e8c84af5 Mon Sep 17 00:00:00 2001
From: theMiddleBlue
Date: Sun, 4 Nov 2018 19:11:41 +0000
Subject: [PATCH 27/77] fix disabled link
---
views.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/views.py b/views.py
index 143db40..2e83e0c 100644
--- a/views.py
+++ b/views.py
@@ -315,7 +315,7 @@ def index(request, filterservice="", filterportid=""):
if hostnum != '0':
viewhref = '/setscanfile/'+html.escape(i)
else:
- viewhref = '/" disabled="disabled'
+ viewhref = '#!'
portstats = nmap_ports_stats(i)
From afd75ebb36dfc8ee625068e9f1c8917687e518f4 Mon Sep 17 00:00:00 2001
From: Rev3rse Security <36775664+Rev3rseSecurity@users.noreply.github.com>
Date: Mon, 5 Nov 2018 10:10:27 +0100
Subject: [PATCH 28/77] Update issue templates
---
.github/ISSUE_TEMPLATE/bug_report.md | 25 +++++++++++++++++++++++
.github/ISSUE_TEMPLATE/feature_request.md | 17 +++++++++++++++
2 files changed, 42 insertions(+)
create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md
create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..60e05c5
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,25 @@
+---
+name: Bug report
+about: Create a report to help us improve
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior, including the Nmap syntax used:
+
+1. Nmap syntax: ...
+2. WebMap in docker container: [x] Yes / [ ] No
+3. WebMap version or branch: ... (example: v2.1/master)
+3. Step to reproduce: ...
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..066b2d9
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,17 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
From 398607289b36015691d29347b5d25345af3769fc Mon Sep 17 00:00:00 2001
From: theMiddleBlue
Date: Thu, 8 Nov 2018 09:55:11 +0000
Subject: [PATCH 29/77] API v1
---
api.py | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
urls.py | 3 ++
views.py | 1 -
3 files changed, 160 insertions(+), 1 deletion(-)
diff --git a/api.py b/api.py
index cfd1c8d..92a99c3 100644
--- a/api.py
+++ b/api.py
@@ -2,6 +2,7 @@
from django.http import HttpResponse
import xmltodict, json, html, os, hashlib, re, requests, base64, urllib.parse
from collections import OrderedDict
+from nmapreport.functions import *
def rmNotes(request, hashstr):
scanfilemd5 = hashlib.md5(str(request.session['scanfile']).encode('utf-8')).hexdigest()
@@ -144,3 +145,159 @@ def getCVE(request):
f.close()
return HttpResponse(json.dumps(res), content_type="application/json")
+
+def apiv1_hostdetails(request, scanfile, faddress=""):
+ oo = xmltodict.parse(open('/opt/xml/'+scanfile, 'r').read())
+ out2 = json.dumps(oo['nmaprun'], indent=4)
+ o = json.loads(out2)
+
+ r = {'file':scanfile, 'hosts': {}}
+ scanmd5 = hashlib.md5(str(scanfile).encode('utf-8')).hexdigest()
+
+ # collect all labels in labelhost dict
+ labelhost = {}
+ labelfiles = os.listdir('/opt/notes')
+ for lf in labelfiles:
+ m = re.match('^('+scanmd5+')_([a-z0-9]{32,32})\.host\.label$', lf)
+ if m is not None:
+ if m.group(1) not in labelhost:
+ labelhost[m.group(1)] = {}
+ labelhost[m.group(1)][m.group(2)] = open('/opt/notes/'+lf, 'r').read()
+
+ # collect all notes in noteshost dict
+ noteshost = {}
+ notesfiles = os.listdir('/opt/notes')
+ for nf in notesfiles:
+ m = re.match('^('+scanmd5+')_([a-z0-9]{32,32})\.notes$', nf)
+ if m is not None:
+ if m.group(1) not in noteshost:
+ noteshost[m.group(1)] = {}
+ noteshost[m.group(1)][m.group(2)] = open('/opt/notes/'+nf, 'r').read()
+
+ # collect all cve in cvehost dict
+ cvehost = get_cve(scanmd5)
+
+ for ik in o['host']:
+
+ # this fix single host report
+ if type(ik) is dict:
+ i = ik
+ else:
+ i = o['host']
+
+ hostname = {}
+ if 'hostnames' in i and type(i['hostnames']) is dict:
+ # hostname = json.dumps(i['hostnames'])
+ if 'hostname' in i['hostnames']:
+ # hostname += ' '
+ if type(i['hostnames']['hostname']) is list:
+ for hi in i['hostnames']['hostname']:
+ hostname[hi['@type']] = hi['@name']
+ else:
+ hostname[i['hostnames']['hostname']['@type']] = i['hostnames']['hostname']['@name'];
+
+ if i['status']['@state'] == 'up':
+ po,pc,pf = 0,0,0
+ ss,pp,ost = {},{},{}
+ lastportid = 0
+
+ if '@addr' in i['address']:
+ address = i['address']['@addr']
+ elif type(i['address']) is list:
+ for ai in i['address']:
+ if ai['@addrtype'] == 'ipv4':
+ address = ai['@addr']
+
+ if faddress != "" and faddress != address:
+ continue
+
+ addressmd5 = hashlib.md5(str(address).encode('utf-8')).hexdigest()
+ #cpe[address] = {}
+
+ labelout = ''
+ if scanmd5 in labelhost:
+ if addressmd5 in labelhost[scanmd5]:
+ labelout = labelhost[scanmd5][addressmd5]
+
+ notesout,notesb64,removenotes = '','',''
+ if scanmd5 in noteshost:
+ if addressmd5 in noteshost[scanmd5]:
+ notesb64 = noteshost[scanmd5][addressmd5]
+ # notesout = ' contains notes'
+ # removenotes = 'Remove notes'
+
+ cveout = ''
+ #cvecount = 0
+ if scanmd5 in cvehost:
+ if addressmd5 in cvehost[scanmd5]:
+ cveout = json.loads(cvehost[scanmd5][addressmd5])
+ # for cveobj in cvejson:
+ # cvecount = (cvecount + 1)
+
+
+ r['hosts'][address] = {'ports':[], 'hostname':hostname, 'label':labelout, 'notes':notesb64, 'CVE':cveout}
+
+ if 'ports' in i and 'port' in i['ports']:
+ for pobj in i['ports']['port']:
+ if type(pobj) is dict:
+ p = pobj
+ else:
+ p = i['ports']['port']
+
+ if lastportid == p['@portid']:
+ continue
+ else:
+ lastportid = p['@portid']
+
+ ss[p['service']['@name']] = p['service']['@name']
+ pp[p['@portid']] = p['@portid']
+
+ r['hosts'][address]['ports'].append({
+ 'port': p['@portid'],
+ 'name': p['service']['@name'],
+ 'state': p['state']['@state']
+ })
+
+ return HttpResponse(json.dumps(r, indent=4), content_type="application/json")
+
+
+def apiv1_scan(request):
+ r = {}
+
+ gitcmd = os.popen('cd /opt/nmapdashboard/nmapreport && git rev-parse --abbrev-ref HEAD')
+ r['webmap_version'] = gitcmd.read().strip()
+
+ xmlfiles = os.listdir('/opt/xml')
+
+ r['scans'] = {}
+
+ xmlfilescount = 0
+ for i in xmlfiles:
+ if re.search('\.xml$', i) is None:
+ continue
+
+ xmlfilescount = (xmlfilescount + 1)
+
+ try:
+ oo = xmltodict.parse(open('/opt/xml/'+i, 'r').read())
+ except:
+ r['scans'][i] = {'filename':html.escape(i), 'startstr': '', 'nhost':0, 'port_stats':{'open':0,'closed':0,'filtered':0}}
+ continue
+
+ rout = json.dumps(oo['nmaprun'], indent=4)
+ o = json.loads(rout)
+
+ if 'host' in o:
+ if type(o['host']) is not dict:
+ hostnum = str(len(o['host']))
+ else:
+ hostnum = '1'
+ else:
+ hostnum = '0'
+
+ portstats = nmap_ports_stats(i)
+
+ r['scans'][i] = {'filename':html.escape(i), 'startstr': html.escape(o['@startstr']), 'nhost':hostnum, 'port_stats':{'open':portstats['po'],'closed':portstats['pc'],'filtered':portstats['pf']}}
+
+ return HttpResponse(json.dumps(r, indent=4), content_type="application/json")
+
diff --git a/urls.py b/urls.py
index bd0b362..e942e1d 100644
--- a/urls.py
+++ b/urls.py
@@ -8,6 +8,9 @@
path('port//', views.port, name='port'),
path('service//', views.index, name='service'),
path('portid//', views.index, name='portid'),
+ path('api/v1/scan//', api.apiv1_hostdetails, name='apiv1_hostdetails'),
+ path('api/v1/scan/', api.apiv1_hostdetails, name='apiv1_hostdetails'),
+ path('api/v1/scan', api.apiv1_scan, name='apiv1_scan'),
path('api/setlabel//
+ {% endfor %}
{% endblock %}
diff --git a/views.py b/views.py
index 741c52e..bd1fd21 100644
--- a/views.py
+++ b/views.py
@@ -378,12 +378,12 @@ def index(request, filterservice="", filterportid=""):
if 'hostnames' in i and type(i['hostnames']) is dict:
# hostname = json.dumps(i['hostnames'])
if 'hostname' in i['hostnames']:
- hostname += ' '
+ #hostname += ' '
if type(i['hostnames']['hostname']) is list:
for hi in i['hostnames']['hostname']:
- hostname += ''+hi['@type']+': '+hi['@name']+' '
+ hostname += ''+hi['@type']+': '+hi['@name']+' '
else:
- hostname += ''+i['hostnames']['hostname']['@type']+': '+i['hostnames']['hostname']['@name']+' '
+ hostname += ''+i['hostnames']['hostname']['@type']+': '+i['hostnames']['hostname']['@name']+' '
if i['status']['@state'] == 'up':
hostsup = (hostsup + 1)
@@ -403,6 +403,7 @@ def index(request, filterservice="", filterportid=""):
cpe[address] = {}
striggered = False
+ e = ''
if 'ports' in i and 'port' in i['ports']:
for pobj in i['ports']['port']:
if type(pobj) is dict:
@@ -424,6 +425,9 @@ def index(request, filterservice="", filterportid=""):
ss[p['service']['@name']] = p['service']['@name']
pp[p['@portid']] = p['@portid']
+ if '@extrainfo' in p['service']:
+ e = p['service']['@extrainfo']
+
# cpehtml = ''
if 'cpe' in p['service']:
if type(p['service']['cpe']) is list:
@@ -491,14 +495,14 @@ def index(request, filterservice="", filterportid=""):
labelmargin = labelToMargin(labelhost[scanmd5][addressmd5])
labelout = ''+html.escape(labelhost[scanmd5][addressmd5])+''
newlabelout = ''+html.escape(labelhost[scanmd5][addressmd5])+' '+\
- ''
+ ''
notesout,notesb64,removenotes = '','',''
if scanmd5 in noteshost:
if addressmd5 in noteshost[scanmd5]:
notesb64 = noteshost[scanmd5][addressmd5]
- notesout = ' contains notes'
- removenotes = 'Remove notes'
+ notesout = ' contains notes'
+ removenotes = 'Remove notes'
cveout = ''
cvecount = 0
@@ -508,17 +512,25 @@ def index(request, filterservice="", filterportid=""):
for cveobj in cvejson:
cvecount = (cvecount + 1)
- cveout = ' '+str(cvecount)+' CVE found'
+ cveout = ' '+str(cvecount)+' CVE found'
if (filterservice != "" and striggered is True) or (filterportid != "" and striggered is True) or (filterservice == "" and filterportid == ""):
- portstateout = ' | | '
+ ' '
if (filterservice != "" and striggered is True):
- portstateout = ' | | '
+ '