Извлечение информации CVE с регулярным выражением Python 3 - PullRequest
0 голосов
/ 12 февраля 2020

Мне часто нужен список CVE, перечисленных на странице бюллетеня по безопасности поставщика. Иногда это просто скопировать, но часто они смешиваются с кучей текста.

Я давно не трогал Python, поэтому я подумал, что это было бы отличным упражнением для определения как извлечь эту информацию - тем более что я продолжаю делать это вручную.

Вот мой текущий код:

#!/usr/bin/env python3

# REQUIREMENTS
#   python3
#   BeautifulSoup (pip3 install beautifulsoup)
#   python 3 certificates (Applications/Python 3.x/ Install Certificates.command) <-- this one took me forever to figure out!

import sys
if sys.version_info[0] < 3:
    raise Exception("Use Python 3:  python3 " + sys.argv[0])
from urllib.request import urlopen
from bs4 import BeautifulSoup
import re

#specify/get the url to scrape
#url ='https://chromereleases.googleblog.com/2020/02/stable-channel-update-for-desktop.html'
#url = 'https://source.android.com/security/bulletin/2020-02-01.html'
url = input("What is the URL?  ") or 'https://chromereleases.googleblog.com/2020/02/stable-channel-update-for-desktop.html'
print("Checking URL: " + url)

# CVE regular expression
cve_pattern = 'CVE-\d{4}-\d{4,7}'

# query the website and return the html
page = urlopen(url).read()

# parse the html returned using beautiful soup
soup = BeautifulSoup(page, 'html.parser')

count = 0

############################################################
# ANDROID === search for CVE references within <td> tags ===

# find all <td> tags
all_tds = soup.find_all("td")

#print all_tds

for td in all_tds:
    if "cve" in td.text.lower():
        print(td.text)


############################################################
# CHROME === search for CVE reference within <span> tags ===

# find all <span> tags
all_spans = soup.find_all("span")

for span in all_spans:
    # this code returns results in triplicate
    for i in re.finditer(cve_pattern, span.text):
        count += 1
        print(count, i.group())


    # this code works, but only returns the first match
#   match = re.search(cve_pattern,span.text)
#   if match:
#       print(match.group(0))

То, что у меня работает для URL Android, работает нормально; у меня проблема с Chrome URL. Они содержат информацию CVE внутри тегов <span>, и я пытаюсь использовать регулярные выражения, чтобы вытащить это.

Используя подход re.finditer, я получаю результаты в трех экземплярах. Используя подход re.search, он пропускает CVE-2019-19925 - они перечислили два CVE на одной и той же строке.

Можете ли вы дать какой-нибудь совет о том, как лучше всего это работает?

1 Ответ

1 голос
/ 14 февраля 2020

Я наконец-то решил это сам. Нет необходимости в BeautifulSoup; все сейчас RegEx. Чтобы обойти повторяющиеся / повторяющиеся результаты, которые я видел ранее, я преобразовываю результат списка re.findall в словарь (сохраняя порядок уникальных значений) и обратно в список.

import sys
if sys.version_info[0] < 3:
    raise Exception("Use Python 3:  python3 " + sys.argv[0])
import requests
import re

# Specify/get the url to scrape (included a default for easier testing)
### there is no input validation taking place here ###
url = input("What is the URL?  ") #or 'https://chromereleases.googleblog.com/2020/02/stable-channel-update-for-desktop.html'
print()

# CVE regular expression
cve_pattern = r'CVE-\d{4}-\d{4,7}'

# query the website and return the html
page = requests.get(url)

# initialize count to 0
count = 0

#search for CVE references using RegEx
cves = re.findall(cve_pattern, page.text)

# after several days of fiddling, I was still getting double and sometimes triple results on certain pages.  This next line
# converts the list of objects returned from re.findall to a dictionary (which retains order) to get unique values, then back to a list.
# (thanks to https://stackoverflow.com/a/48028065/9205677)
# I found order to be important sometimes, as the most severely rated CVEs are often listed first on the page
cves = list(dict.fromkeys(cves))

# print the results to the screen
for cve in cves:
    print(cve)
    count += 1

print()
print(str(count) + " CVEs found at " + url)
print()
...