From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 16907158083 for ; Thu, 26 Sep 2024 02:36:59 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 27F142BC013; Thu, 26 Sep 2024 02:36:58 +0000 (UTC) Received: from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 01EC72BC013 for ; Thu, 26 Sep 2024 02:36:57 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id E7A85340B57 for ; Thu, 26 Sep 2024 02:36:56 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 4510016EF for ; Thu, 26 Sep 2024 02:36:55 +0000 (UTC) From: "Matt Jolly" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Matt Jolly" Message-ID: <1727318184.df1cdd52ddf34c0c0650169b34ea332b23aae90e.kangie@gentoo> Subject: [gentoo-commits] proj/chromium-tools:master commit in: / X-VCS-Repository: proj/chromium-tools X-VCS-Files: get-edge-cves.py X-VCS-Directories: / X-VCS-Committer: kangie X-VCS-Committer-Name: Matt Jolly X-VCS-Revision: df1cdd52ddf34c0c0650169b34ea332b23aae90e X-VCS-Branch: master Date: Thu, 26 Sep 2024 02:36:55 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: de055a7b-9bb0-4e3f-b8f7-314da22b2c94 X-Archives-Hash: b02eba2d61774b49143a609f206c7c37 commit: df1cdd52ddf34c0c0650169b34ea332b23aae90e Author: Matt Jolly gentoo org> AuthorDate: Thu Sep 26 02:34:18 2024 +0000 Commit: Matt Jolly gentoo org> CommitDate: Thu Sep 26 02:36:24 2024 +0000 URL: https://gitweb.gentoo.org/proj/chromium-tools.git/commit/?id=df1cdd52 get-edge-cves.py: new script This script currently grabs the current month's CVRF from MS and filters for Edge (Chromium-based) CVEs, then does some magick to identify the version that it was fixed in if the API is for some reason deficient... Signed-off-by: Matt Jolly gentoo.org> get-edge-cves.py | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/get-edge-cves.py b/get-edge-cves.py new file mode 100755 index 0000000..0761b4e --- /dev/null +++ b/get-edge-cves.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python + +# SPDX-License-Identifier: GPL-2.0-or-later +# This script extracts the Chromium version mapping for Microsoft Edge based on a given CVE ID. +# It uses the Microsoft Security Response Center (MSRC) API to get the Common Vulnerability Reporting Framework (CVRF) +# for a given month and extracts the Chromium version mapping for Microsoft Edge (Chromium-based) from the CVRF. + +# API Docs https://api.msrc.microsoft.com/cvrf/v3.0/swagger/v3/swagger.json + +# We can use the CVRF API to get the Common Vulnerability Reporting Framework (CVRF) for a given month. +# We can query the API via CVE ID to get the CVRF for a specific CVE, but that just leads us back to querying +# the month. Stretch goal to ingest directly from bgo ticket aliases and confirm the month & version? +# https://api.msrc.microsoft.com/cvrf/v3.0/updates/CVE-2024-7969 + +# https://api.msrc.microsoft.com/cvrf/v3.0/cvrf/2024-Aug +# is the URL for the CVRF for August 2024 + +# The XML looks like this: +# +# Chromium: CVE-2024-7969 Type Confusion in V8 +# . . . +# +# +# 11655 +# . . . +# +# . . . +# CVE-2024-7969 +# . . . +# +# +# Release Notes +# +# 11655 +# +# No +# Security Update +# 128.0.2739.42 +# . . . +# +# . . . +# + +# Process: Pick a month, get the CVRF for that month, then iterate over vulnerabilities to find the ones +# that are for Microsoft Edge (Chromium-based) `11655`. +# Extract the CVE-2024-7969 to extract a CVE ID and +# map to Chromium versions using the 128.0.2739.42 tag + +# It would be possible to parse the tag which contains a table with the chromium and edge versions +# but each row looks like this: <td>128.0.6613.84/.85</td> which is not very useful, and we already +# know which version of Chromium a CVE got fixed in. + +import datetime +import requests +from portage import versions as portage_versions +import sys +import xml.etree.ElementTree as ET +from bs4 import BeautifulSoup + + +class EdgeCVE: + def __init__(self, cve, title, fixedbuild): + self.cve: str = cve + self.title: str = title + self.fixedbuild: str | None = fixedbuild + + def __str__(self): + return f"{self.cve}: {self.title}: Fixed {self.fixedbuild if not None else 'unknown'}" + + +def get_edge_cves(year, month): + msrcapi = f"https://api.msrc.microsoft.com/cvrf/v3.0/cvrf/{year}-{month}" + + # Get the CVRF for the specified month + response = requests.get(msrcapi) + + if response.status_code != 200: + print(f"Website returned {response.status_code}") + print(f"Failed to get CVRF for {year}-{month}") + sys.exit(1) + + # Parse the XML + root = ET.fromstring(response.text) + + # Find all the vulnerabilities + vulnerabilities = root.findall(".//{http://www.icasi.org/CVRF/schema/vuln/1.1}Vulnerability") + + edge_cves = [] # Store the edge cves here + for vulnerability in vulnerabilities: + productstatuses = vulnerability.findall(".//{http://www.icasi.org/CVRF/schema/vuln/1.1}ProductStatuses") + for productstatus in productstatuses: + productid = productstatus.find(".//{http://www.icasi.org/CVRF/schema/vuln/1.1}ProductID") + if productid.text == "11655": + # This is a Microsoft Edge (Chromium-based) vulnerability + cve_id = vulnerability.find(".//{http://www.icasi.org/CVRF/schema/vuln/1.1}CVE").text + cve_title = vulnerability.find(".//{http://www.icasi.org/CVRF/schema/vuln/1.1}Title").text + remediations = vulnerability.findall(".//{http://www.icasi.org/CVRF/schema/vuln/1.1}Remediations") + for remediation in remediations: + fixedbuild = remediation.find(".//{http://www.icasi.org/CVRF/schema/vuln/1.1}FixedBuild") + if fixedbuild is not None: + edge_cves.append( + EdgeCVE(cve_id, + cve_title, + fixedbuild.text) + ) + else: + # Fall back to parsing that horrible, horrible table in the notes + notes = vulnerability.find(".//{http://www.icasi.org/CVRF/schema/vuln/1.1}Notes") + # There appear to be multiple notes, but only one has content that we want: + # <p><strong>What is the version information for this release?</strong></p> + found = False + for note in notes: + if note.attrib['Title'] == "FAQ" and note.attrib['Type'] == "FAQ": + + # The note contains a table with the chromium and edge versions, written in "HTML" + # <td>8/22/2024</td> + content = note.text + + soup = BeautifulSoup(content, 'html.parser') + + # Now you can work with the parsed HTML + + # Find all the table rows + rows = soup.find_all('tr') + # We want the second row, second cell + if len(rows) > 1: + cells = rows[1].find_all('td') + if len(cells) > 1: + # We want the second cell (The first is the channel, the third the chromium version it's based on) + edge_version = cells[1].text + if portage_versions.ververify(edge_version): + found = True + edge_cves.append( + EdgeCVE(cve_id, + cve_title, + edge_version) + ) + + if not found: + edge_cves.append( + EdgeCVE(cve_id, + cve_title, + None) + ) + + return edge_cves + + +now = datetime.datetime.now() +year = now.year +month = now.strftime("%B")[0:3] + +# Call the function with current year and month +edge_cves = get_edge_cves(year, month) +for cve in edge_cves: + print(cve)