Skip to content

Instantly share code, notes, and snippets.

@haginara
Last active May 14, 2024 17:13
Show Gist options
  • Save haginara/89e2c89d3f4f7bdc449516f5915e6106 to your computer and use it in GitHub Desktop.
Save haginara/89e2c89d3f4f7bdc449516f5915e6106 to your computer and use it in GitHub Desktop.
Getting Microsoft Security Update from api.msrc.microsoft.com via Python
# coding: utf-8
from dataclasses import dataclass, asdict, field
from typing import Dict, List, Optional
import pprint
import json
try:
import requests
except ImportError:
raise SystemExit("Please install 'requests' first")
@dataclass
class Note:
Title: str
Type: int
Ordinal: str
Value: str
@dataclass
class Vulnerability:
Title: Dict
Notes: List[Note]
DiscoveryDateSpecified: bool
ReleaseDateSpecified: bool
Ordinal: str
RevisionHistory: List[Dict]
CVE: str
ProductStatuses: List[Dict]
Threats: List[Dict]
CVSSScoreSets: List
Remediations: List
Acknowledgments: List
@dataclass(init=False)
class CVRF:
DocumentTitle: str
DocumentType: str
DocumentPublisher : Dict[str, Dict]
DocumentTracking: Dict[str, Dict]
DocumentNotes: List[Dict]
ProductTree: Dict
Vulnerabilities: List[Vulnerability]
@classmethod
def init(cls, raw):
obj = cls()
obj.DocumentTitle = raw.get("DocumentTitle").get("Value")
obj.DocumentType = raw.get("DocumentType").get("Value")
obj.DocumentPublisher = raw.get("DcoumentPublisher")
obj.DocumentTracking = raw.get("DcoumentTracking")
obj.DocumentNotes = raw.get("DcoumentNotes")
obj.ProductTree = raw.get("ProductTree")
obj.Vulnerabilities = []
for vuln in raw.get("Vulnerability", []):
pprint.pprint(vuln)
obj.Vulnerabilities.append(Vulnerability(**vuln))
return obj
def is_security(self) -> bool:
if self.DocuemntType['Value'] == 'Security Update':
return True
return False
def Affected(self) -> List[str]:
values = set()
for item in self.ProductTree['Branch']['Items']:
for product in item['Items']:
values.add(product['Value'])
return list(values)
@dataclass
class SecurityUpdate:
ID: str
Alias: str = field(repr=False)
DocumentTitle: str
Severity: str
InitialReleaseDate: str = field(repr=False)
CurrentReleaseDate: str
CvrfUrl: str = field(repr=False)
Cvrf: CVRF = field(repr=False, default=None)
def summary(self):
return f"{self.DocumentTitle}({self.ID}): {len(self.Cvrf.Vulnerability)}"
def dump(self, filename: str=None):
if filename is None:
filename = f"{self.ID}_Security_Update.json"
data = {
'ID': self.ID,
'title': self.DocumentTitle,
'ReleaseDate': self.CurrentReleaseDate,
}
if self.Cvrf:
data['cvrf'] = asdict(self.Cvrf)
with open(filename, 'w') as f:
f.write(json.dumps(data, indent=2))
url = 'https://api.msrc.microsoft.com'
key = 'MSRC_API_KEY'
headers = {
'Accept': 'application/json',
'api-key': key,
}
params = {'api-version': 2020}
updates_query = f"{url}/updates"
r = requests.get(updates_query, headers=headers, params=params)
if r.status_code != 200:
raise SystemExit("Failed to get updates")
updates = [SecurityUpdate(**update) for update in r.json().get('value')]
for update in updates:
r = requests.get(update.CvrfUrl, headers=headers, params=params)
if r.status_code != 200:
print(f"Failed to get update: {ID}")
continue
try:
data = r.json()
print(f"Init {update.ID}")
cvrf = CVRF.init(data)
update.Cvrf = cvrf
#print(f"{update.summary()}")
print(f"{update}")
update.dump()
except Exception as e:
print(f"Failed to get CVRF: {update.ID} Error: {e}")
raise(e)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment