update with NVD
This commit is contained in:
319
script-v3.py
Normal file
319
script-v3.py
Normal file
@@ -0,0 +1,319 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import requests
|
||||
import re
|
||||
import math
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
|
||||
class CveObject:
|
||||
cve_no = '' # 漏洞编号
|
||||
cve_nvd_url = '' # 漏洞nvd url链接地址
|
||||
cve_description = '' # 漏洞描述
|
||||
cve_level = '' # 威胁等级
|
||||
cve_score = '' # 威胁评分
|
||||
cve_cna = '' # 漏洞分配的机构
|
||||
|
||||
def show(self):
|
||||
"""
|
||||
Show basic vul information
|
||||
:return: None
|
||||
"""
|
||||
print('----------------------------------')
|
||||
print('编号:', self.cve_no)
|
||||
print('漏洞描述:', self.cve_description)
|
||||
print('漏洞等级:', self.cve_level)
|
||||
print('漏洞评分:', self.cve_score)
|
||||
print('\n\n')
|
||||
|
||||
|
||||
# cve search url
|
||||
search_url = 'https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword='
|
||||
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0'
|
||||
}
|
||||
|
||||
# 漏洞等级对应
|
||||
level_dict = {
|
||||
'CRITICAL': '严重',
|
||||
'HIGH': '高',
|
||||
'MEDIUM': '中',
|
||||
'LOW': '低'
|
||||
}
|
||||
|
||||
cve_obj_list = [] # cve obj-s fill with detailed information
|
||||
cve_all = [] # cve no-s fetched from nvd
|
||||
|
||||
|
||||
def fill_with_nvd(cve, cve_obj):
|
||||
"""
|
||||
Fetch detailed information by search cve to fill cve_obj that can be fetch from NVD
|
||||
:param cve: cve no
|
||||
:param cve_obj: cve object to fill
|
||||
:return: None
|
||||
"""
|
||||
cve_obj.cve_no = cve
|
||||
|
||||
nvd_url = 'https://nvd.nist.gov/vuln/detail/'
|
||||
url = '{}{}'.format(nvd_url, cve)
|
||||
cve_obj.cve_nvd_url = url
|
||||
|
||||
try:
|
||||
print(url)
|
||||
response = requests.get(url, headers=headers, timeout=60)
|
||||
# print(response.status_code)
|
||||
if response.status_code == 200:
|
||||
# fill description
|
||||
content = response.text
|
||||
description = re.findall('<p data-testid="vuln-description">(.*).</p>?', content)
|
||||
cve_obj.cve_description = description[0]
|
||||
|
||||
soup = BeautifulSoup(content, "html.parser")
|
||||
severity = soup.find('a', id="Cvss3NistCalculatorAnchor").get_text()
|
||||
score, cve_level = severity.split(' ')
|
||||
cve_obj.cve_score = score
|
||||
cve_obj.cve_level = cve_level
|
||||
print(score, cve_level)
|
||||
except:
|
||||
print('v3 not scored, switch to v2...')
|
||||
|
||||
severity = soup.find('a', id="Cvss2CalculatorAnchor").get_text()
|
||||
score, cve_level = severity.split(' ')
|
||||
cve_obj.cve_score = score
|
||||
cve_obj.cve_level = cve_level
|
||||
print(score, cve_level)
|
||||
finally:
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
def fetch_all_cves(producer, software, banner):
|
||||
"""
|
||||
Query NVD to get specific version of software vulnerabilities
|
||||
:return: None
|
||||
"""
|
||||
# contruct query string
|
||||
if banner:
|
||||
keyword = '{}%3a{}'.format(software, banner)
|
||||
else:
|
||||
keyword = software
|
||||
url = 'https://nvd.nist.gov/vuln/search/results?form_type=Advanced&' \
|
||||
'cves=on&cpe_version=cpe%3a%2fa%3a{}%3a{}'.format(producer, keyword)
|
||||
print(url)
|
||||
|
||||
# to get cve number
|
||||
try:
|
||||
response = requests.get(url, timeout=60, headers=headers)
|
||||
if response.status_code == 200:
|
||||
num = re.findall('"vuln-matching-records-count">(.*)?</strong>', response.text)[0]
|
||||
msg = 'There are {} cves with {} {}...'.format(num, software, banner)
|
||||
print(msg)
|
||||
except:
|
||||
pass
|
||||
|
||||
# fetch all cve no
|
||||
start_index = index = 0
|
||||
while start_index < int(num):
|
||||
url = 'https://nvd.nist.gov/vuln/search/results?form_type=Advanced&' \
|
||||
'cves=on&cpe_version=cpe%3a%2fa%3a{}%3a{}&' \
|
||||
'startIndex={}'.format(producer, keyword, start_index)
|
||||
msg = 'processing page {}/{}...'.format(index+1, math.ceil(int(num) / 20))
|
||||
print(msg)
|
||||
index += 1
|
||||
start_index = index * 20
|
||||
try:
|
||||
response = requests.get(url, timeout=60, headers=headers)
|
||||
if response.status_code == 200:
|
||||
cves = re.findall('"vuln-detail-link-\d+">(.*)?</a>', response.text)
|
||||
cve_all.extend(cves)
|
||||
except:
|
||||
pass
|
||||
print('\n-------- CVEs ---------\n')
|
||||
for line in cve_all:
|
||||
print(line)
|
||||
print()
|
||||
|
||||
|
||||
def fetch_vul_info(producer, software, banner):
|
||||
|
||||
# get all cves
|
||||
fetch_all_cves(producer, software, banner)
|
||||
|
||||
i = 0
|
||||
for cve in cve_all:
|
||||
i += 1
|
||||
cve_obj = CveObject()
|
||||
|
||||
# if i == 4:
|
||||
# break
|
||||
msg = '[{}/{}] Fetching {} ...'.format(i, cve_all.__len__(), cve)
|
||||
print(msg)
|
||||
# fill cve object with information from nvd
|
||||
fill_with_nvd(cve, cve_obj)
|
||||
cve_obj_list.append(cve_obj)
|
||||
pass
|
||||
|
||||
|
||||
def save_cve_objs():
|
||||
"""
|
||||
Save cve info to a file
|
||||
:return: None
|
||||
"""
|
||||
for obj in cve_obj_list:
|
||||
cve_info = '{}|{}|{}|{}|{}|{}\n'.format(obj.cve_no, obj.cve_nvd_url,
|
||||
obj.cve_score, obj.cve_level, obj.cve_cna,
|
||||
obj.cve_description)
|
||||
# with open('cve.txt', 'a+') as fw:
|
||||
# fw.write(cve_info)
|
||||
|
||||
|
||||
def write2html():
|
||||
"""
|
||||
Write cve into to create a html file, this function is terriblely implemented, (^_^)
|
||||
:param keyword: software name
|
||||
:return: None
|
||||
"""
|
||||
print('write data to html')
|
||||
html = ''
|
||||
header = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">\
|
||||
<head>\
|
||||
<title>CVEs</title>\
|
||||
<meta content="text/html" charset="utf-8"></meta>\
|
||||
<link rel="stylesheet" type="text/css" href="list.css">\
|
||||
</head>\
|
||||
<body>\
|
||||
<div id="div_title" align="center">\
|
||||
<div id="div_title_inner"><h1>CVEs for {} {} </h1></div>\
|
||||
</div>\
|
||||
<div id="div_title_occupy"></div>'
|
||||
|
||||
header = header.format(software, banner)
|
||||
|
||||
body = '<div id="div_main">\
|
||||
<div id="div_content"> \
|
||||
<div id="div_content_body"><h3>漏洞列表</h3>\
|
||||
<div id="uri_list_div">'
|
||||
|
||||
vul_list = ''
|
||||
for obj in cve_obj_list:
|
||||
vul = '<a href="#{}">{} {}</a><br />'
|
||||
vul = vul.format(obj.cve_no, obj.cve_no, obj.cve_level)
|
||||
vul_list = '{}{}'.format(vul_list, vul)
|
||||
|
||||
vul_left = '</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div id="div_body">'
|
||||
|
||||
body = '{}{}{}'.format(body, vul_list, vul_left)
|
||||
|
||||
table = '<a name="vul-overview"></a><div id="div_get"> \
|
||||
<table class="uri_t" id="uri_table" border="1">\
|
||||
<tr align="center">\
|
||||
<td>等级</td>\
|
||||
<td>严重</td>\
|
||||
<td>高危</td>\
|
||||
<td>中危</td>\
|
||||
<td>低危</td>\
|
||||
</tr>\
|
||||
<tr align="center">\
|
||||
<td>个数({})</td>\
|
||||
<td>{}</td>\
|
||||
<td>{}</td>\
|
||||
<td>{}</td>\
|
||||
<td>{}</td>\
|
||||
</tr>\
|
||||
</table>\
|
||||
</div>'
|
||||
|
||||
a = b = c = d = e = 0
|
||||
for cve in cve_obj_list:
|
||||
if cve.cve_level == 'CRITICAL':
|
||||
a += 1
|
||||
elif cve.cve_level == 'HIGH':
|
||||
b += 1
|
||||
elif cve.cve_level == 'MEDIUM':
|
||||
c += 1
|
||||
elif cve.cve_level == 'LOW':
|
||||
d += 1
|
||||
else:
|
||||
e += 1
|
||||
|
||||
table = table.format(cve_obj_list.__len__(), a, b, c, d)
|
||||
|
||||
body = '{}{}'.format(body, table)
|
||||
|
||||
for obj in cve_obj_list:
|
||||
cve_body = '<a name="{}"></a>\
|
||||
<div id="div_get">\
|
||||
<table class="uri_t" id="uri_table">\
|
||||
<tr id="cve_no"><th>漏洞编号</th>\
|
||||
<td>{}</td>\
|
||||
</tr>\
|
||||
<tr id="vul_level"><th>威胁评分</th>\
|
||||
<td>{}</td>\
|
||||
</tr>\
|
||||
<tr id="cvss"><th>风险等级</th>\
|
||||
<td>{}</td>\
|
||||
</tr>\
|
||||
</table>\
|
||||
<p id="description">漏洞描述</p>\
|
||||
<div id="example_div"><a id="description">\
|
||||
{}\
|
||||
</a>\
|
||||
</div>\
|
||||
<p id="references">参考链接</p>\
|
||||
<div id="example_div"><a id="references">\
|
||||
{}<br />\
|
||||
</a>\
|
||||
</div>\
|
||||
</div>'
|
||||
|
||||
cve_body = cve_body.format(obj.cve_no, obj.cve_no, obj.cve_score, obj.cve_level,
|
||||
obj.cve_description, obj.cve_nvd_url)
|
||||
|
||||
body = '{}{}'.format(body, cve_body)
|
||||
|
||||
footer = '</div>\
|
||||
</div>\
|
||||
<script>\
|
||||
function AjustContentHeight(){\
|
||||
var div_content = document.getElementById("div_content");\
|
||||
var div_body = document.getElementById("div_body")\
|
||||
var clientHeight = document.documentElement.clientHeight;\
|
||||
clientHeight -= 69;\
|
||||
div_content.style.height = clientHeight + "px";\
|
||||
div_body.style.height = clientHeight + "px";\
|
||||
}\
|
||||
window.onload=function(){AjustContentHeight();}\
|
||||
window.onresize=function(){AjustContentHeight();\
|
||||
}\
|
||||
</script>\
|
||||
</body>\
|
||||
</html>'
|
||||
html = '{}{}{}'.format(header, body, footer)
|
||||
|
||||
# write to cve html file for showing results
|
||||
file = 'cve-{}-{}.html'.format(software, banner)
|
||||
with open(file, 'w', encoding='utf-8') as fw:
|
||||
fw.write(html)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
file = 'list.txt'
|
||||
with open(file, 'r') as fr:
|
||||
for line in fr:
|
||||
cve_obj_list = []
|
||||
cve_all = []
|
||||
producer, software, banner = line.strip().split(',')
|
||||
print(producer, software, banner)
|
||||
|
||||
fetch_vul_info(producer, software, banner)
|
||||
for obj in cve_obj_list:
|
||||
obj.show()
|
||||
write2html()
|
||||
save_cve_objs()
|
||||
pass
|
||||
Reference in New Issue
Block a user