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
19 changes: 18 additions & 1 deletion dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@ FROM python:3.7-slim
WORKDIR /apps
COPY msyh.ttc /usr/share/fonts/

# 更换国内源
RUN rm -rf /etc/apt/sources.list.d/debian.sources && printf "%s\n" \
"deb https://mirrors.aliyun.com/debian/ bookworm main contrib non-free non-free-firmware" \
"deb-src https://mirrors.aliyun.com/debian/ bookworm main contrib non-free non-free-firmware" \
"deb https://mirrors.aliyun.com/debian/ bookworm-updates main contrib non-free non-free-firmware" \
"deb-src https://mirrors.aliyun.com/debian/ bookworm-updates main contrib non-free non-free-firmware" \
"deb https://mirrors.aliyun.com/debian/ bookworm-backports main contrib non-free non-free-firmware" \
"deb-src https://mirrors.aliyun.com/debian/ bookworm-backports main contrib non-free non-free-firmware" \
"deb https://mirrors.aliyun.com/debian-security/ bookworm-security main contrib non-free non-free-firmware" \
"deb-src https://mirrors.aliyun.com/debian-security/ bookworm-security main contrib non-free non-free-firmware" \
> /etc/apt/sources.list

# 更新软件包列表并安装必要的软件包
RUN apt-get update && apt-get install -y \
libexif-dev \
Expand Down Expand Up @@ -37,5 +49,10 @@ RUN echo 'Asia/Shanghai' >/etc/timezone
# 设置编码
ENV LANG C.UTF-8

# 使用tini解决容器中截图及调用任何插件可能导致的僵尸进程问题,原理可参考:https://cn.linux-console.net/?p=20630
ENV TINI_VERSION v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini

# 运行golang程序的命令
ENTRYPOINT ["/apps/ScopeSentry"]
ENTRYPOINT ["/tini", "--", "/apps/ScopeSentry"]
199 changes: 199 additions & 0 deletions libs/gonmap/cpe2cve/cpe2cve.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
#!/usr/bin/python3

"""
Part of SubZero project:
Written by David SORIA (Sibwara, [email protected]) in 2021
Do not sell in a commercial package
"""


from cpe import CPE
import argparse
import requests
import time
import pdfkit
import matplotlib.pyplot as plt

API = "https://services.nvd.nist.gov/rest/json/cves/1.0"

"""
format:
{'cpe:/a:apache:tomcat:7.0.27': {
'friendlyname': 'Tomcat 7.0.27', # A human way to describe the porduct
'total':15, # number of CVE concerning this CPE
'highest': 9.8, # highest CVSS score in all the CVEs
'remotelyExploitable': True # True if there is an available exploit for a network vector
'dangerous': 3 # number of CVE with CVSS > 9 and remotely exploitable
'cve': {
'CVE-2021-25329': {
'score': 4.4, # The CVSSv2 or CVSSv3 score
'vector': 'AV:L/AC:M/Au:N/C:P/I:P/A:P' # The full CVSS vector
'exploit': False # True if exploits are available
}
}
}
"""

def cpe2cve(cpe, api):
# Check the format upside to understand how the data are stored in the vulns dict
vulns = {}
for c in cpe:
vulns[c.cpe_str] = {"total":0, "cve":{}, "highest":0.0, "remotelyExploitable":False, "dangerous": 0, "friendlyname": f"{c.get_product()[0]} {c.get_version()[0]}"}
# call to the NIST APÏ
req = requests.get(f"{api}?cpeMatchString={c.cpe_str}&resultsPerPage=100")
if req.status_code != 200:
print(f"[!] An error occured with {c.cpe_str}: {req.text}")
continue
else:
print(f"[+] {c.cpe_str} OK")
# Sleep to avoid blacklist by the NIST servers
time.sleep(0.5)
vulns[c.cpe_str]['total'] = req.json().get('totalResults')
cves = req.json()['result'].get('CVE_Items')
if cves:
for cve in cves:
cveid = cve['cve']['CVE_data_meta']['ID']
vulns[c.cpe_str]["cve"][cveid] = {"score": 0, "vector": '', "exploit": "Unknown"}
# manage the case depending on the CVSS to be V2 or V3
metric = "3" if "baseMetricV3" in cve['impact'] else "2"
cvss = cve['impact'][f"baseMetricV{metric}"][f"cvssV{metric}"]
vulns[c.cpe_str]["cve"][cveid]["score"] = cvss['baseScore']
vulns[c.cpe_str]["cve"][cveid]["vector"] = cvss['vectorString']
# check if vuln is exploitable from network
if "AV:N" in cvss['vectorString']:
vulns[c.cpe_str]["remotelyExploitable"] = True
if cvss['baseScore'] > 9.0 :
vulns[c.cpe_str]["dangerous"] += 1
# Update the highest risk if necessary
vulns[c.cpe_str]['highest'] = max(vulns[c.cpe_str]['highest'], cvss['baseScore'])
return vulns

def getCriticality(cvss):
""" color convention fot the cells of the PDF """
if cvss < 3.1:
return ("low", "#ffff00", (255, 255, 0))
if cvss < 6.1:
return ("medium", "#ffc800", (255, 200, 0))
if cvss < 9.1:
return ("high", "#ff6400", (255, 100, 0))
return ("critical", "#cc0000", (200, 0, 0))

def export2pdf(vulns, output):
html = "<h1 style='font-size:40px;'>Vulnerability report</h1>"
html += f"<p>Date: {time.ctime(time.time())}<br/></p>"
html += f"<p style='background-color:#f8f8f8;padding:10px 10px;'><strong>{len(vulns)}</strong> products were <strong>submited</strong><br/>"
vulnproduct = sum([vulns[i]['total']>0 for i in vulns])
html += f"<strong>{vulnproduct}</strong> of them are <strong>vulnerable</strong><br/>"
sumvuln = sum([vulns[i]['total'] for i in vulns])
html += f"A total of <strong>{sumvuln}</strong> vulnerabilities were found<br/>"
sumdangerous = sum([vulns[i]['dangerous'] for i in vulns])
html += f"<strong>{sumdangerous}</strong> of them are critical AND remotely exploitable</p>"
html += "<h2>Status by product</h2>"
html += "<table><thead><tr><th>Product</th><th>CPE</th><th>CVE</th><th>Risk</th><th>Remotely exploitable</th></tr></thead><tbody>"
fig, ax = plt.subplots()
values = []
labels = []
colors = []
maxgraph = 0
for cpe,details in sorted(vulns.items(), reverse=True, key=lambda k_v: k_v[1]['highest']):
crit = getCriticality(details['highest'])
html += f"<tr><td>{details['friendlyname']}</td><td>{cpe}</td><td>{details['total']}</td><td style='background-color:{crit[1]};'>{details['highest']}</td><td>{details['remotelyExploitable']}</td></tr>"
if sumvuln and details['total']/sumvuln > 0.02 and maxgraph < 11:
maxgraph += 1
values.append(details['total'])
labels.append(details['friendlyname'])
colors.append(crit[1])
html += "</tbody></table>"
ax.pie(values, labels=labels, colors=colors, autopct='%1i%%', wedgeprops={"edgecolor":"white",'linewidth': 1, 'linestyle': 'solid', 'antialiased': True} )
plt.tight_layout()
plt.savefig("/tmp/graph.png", bbox_inches='tight', transparent=True)
if sumvuln:
html += "<h2>Main vulnerabilities distribution</h2>"
html += f"<p><img src ='/tmp/graph.png' width='65%' style='display:block;margin-left:auto;margin-right:auto;'/></p>"
html += "<h2>Vulnerabilities details</h2>"
html += "<table><thead><tr><th>CVE</th><th>Score</th><th>Remotely exploitable</th><th>Target</th><th>Vector</th></tr></thead><tbody>"
for cpe, details in vulns.items():
for cve, detailscve in details["cve"].items():
crit = getCriticality(detailscve['score'])
html += f"<tr><td>{cve}</td><td style='background-color:{crit[1]};'>{detailscve['score']}</td><td>{'AV:N' in detailscve['vector']}</td><td>{cpe}</td><td>{detailscve['vector']}</td></tr>"
html += "</tbody></table>"
if output:
try:
pdfkit.from_string(html, output, css="github.css", options={"enable-local-file-access": ""})
except Exception as e:
print(f"[!] an error occured during PDF generation: {e}\nAn html output is produced instead: {output}.html")
with open(output+'.html', "w") as f:
f.write(html)

def export2csv(vulns, output):
lines = ["cpe,highestrisk,remotelyexploitable,vulnerabilities,cve,score,remote,exploit,vector"]
for cpe,details in vulns.items():
# counter for each vulnerability associated with a unique cpe
cpt = 0
# if there is no vuln, we put a line with a risk of 0.0 and 0 vuln
if details["total"] == 0:
lines.append(f"{cpe},0.0,False,0/0,,,,")
for cve, detailscve in details["cve"].items():
cpt += 1
lines.append(f"{cpe},{details['highest']},{details['remotelyExploitable']},{cpt}/{details['total']},{cve},{detailscve['score']},{'AV:N' in detailscve['vector']},{detailscve['exploit']},{detailscve['vector']}")
# if a filename was provided, write to a file
if output:
with open(output, "w") as f:
for l in lines:
f.write(l + '\n')
# default is to print to stdout
else:
print(*(lines),sep='\n')

def export(vulns, output):
# if a filename was provided we check its extension
if output:
filename = output.split('.')
# if the extension is in PDF we use the PDF export function
if len(filename) > 1 and filename[-1].lower() == "pdf":
export2pdf(vulns, output)
# if the extension is not explicitely PDF wu use CSV as default
else:
export2csv(vulns, output)
# if no ouput was provided we print a CSV format to stdout
# export2csv will recognize that output is empty and print to stdout instead of file
else:
export2csv(vulns, output)

def main():
global API
parser = argparse.ArgumentParser(description='Giving the CVEs that affect a given CPE', add_help=True)
parser.add_argument('--cpe', '-c', action="store", default=None,
help="Give one CPE string to the tool")
parser.add_argument('--file', '-f', action="store", default=None,
help="Import multiple CPE from a file (one per line)")
parser.add_argument('--output', '-o', action="store", default=None,
help="Write results in an output file. Extension is read to choice between PDF and CSV. Default is CSV")
args = parser.parse_args()
cpe = []
print("[*] Check if CPE is well formed ...")
try:
if args.cpe:
cpe.append(CPE(args.cpe))
elif args.file:
with open(args.file) as f:
for line in f.readlines():
#remove space and newlines char from each line
l = line.lower().strip(' \n\r')
cpe.append(CPE(l))
else:
print("[!] indicate at least a CPE (--cpe) or an input file with one CPE per line (--file)")
exit(1)
except Exception as e:
print(f"[!] Bad CPE format: {e}")
exit(1)
print("[+] Valid CPE")
print(f"[*] Searching vulnerabilities for the {len(cpe)} CPE given")
vulns = cpe2cve(cpe, API)
print("[+] Vulnerabilities computed")
print(f"[*] Export to {args.output if args.output else 'stdout'}")
export(vulns, args.output)
print("[+] Export completed !")

if __name__ == '__main__':
main()
18 changes: 18 additions & 0 deletions libs/gonmap/cpe2cve/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
certifi==2025.1.31
charset-normalizer==3.4.1
cpe==1.3.1
cycler==0.11.0
fonttools==4.38.0
idna==3.10
kiwisolver==1.4.5
matplotlib==3.5.3
numpy==1.21.6
packaging==24.0
pdfkit==1.0.0
Pillow==9.5.0
pyparsing==3.1.4
python-dateutil==2.9.0.post0
requests==2.31.0
six==1.17.0
typing_extensions==4.7.1
urllib3==2.0.7
5 changes: 5 additions & 0 deletions libs/gonmap/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/lcvvvv/gonmap

go 1.16

require github.com/miekg/dns v1.1.50
35 changes: 35 additions & 0 deletions libs/gonmap/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 h1:BonxutuHCTL0rBDnZlKjpGIQFTjyUVTexFOdWkB6Fg0=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Loading