from CommonServerPython import * from collections import defaultdict from datetime import date def header_transform(key: str) -> str: """ Function returns header key in human readable :param key: header key :return: translated headers """ header_dict = { "Cve": "CVE ID", "CVSS": "CVSS Score", "VRR": "VRR Score", "ThreatCount": "Threat Count", "VulnLastTrendingOn": "Last Trending On Date", "Trending": "Trending", } return header_dict.get(key, "") def get_ransomware_trending_cves(ransomware_cves) -> list: """ Filter last 7 days trending reansomware cves from ransomware cves. :param ransomware_cves: list of ransomware cves. :return: list of trending ransomware. """ ransomware_trending = [] today_date = date.today() week_ago_date = today_date - timedelta(days=7) demisto.setContext("Date.CurrentDate", str(today_date)) demisto.setContext("Date.WeekAgoDate", str(week_ago_date)) for cve in ransomware_cves: if cve.get("VulnLastTrendingOn") and cve.get("VulnLastTrendingOn") != "Not Found": vuln_last_trending_on_date = datetime.strptime(cve.get("VulnLastTrendingOn", "2000-01-01"), "%Y-%m-%d").date() if (today_date - vuln_last_trending_on_date).days <= 7: ransomware_trending.append(cve) return ransomware_trending def get_ransomware_cves(host_findings): """ Retrieves ransomware cves from host findings details. :param host_findings: list of host findings details :return: list of ransomware cves """ all_cves: dict = defaultdict(dict) for findings in host_findings: risk_rating = findings.get("RiskRating", 0) threat_list = defaultdict(list) threats = findings.get("Threat") if findings.get("Threat", []) else [] vulns = findings.get("Vulnerability") if findings.get("Vulnerability", []) else [] # if dict response receive from context data then convert it to list threats = [threats] if isinstance(threats, dict) else threats vulns = [vulns] if isinstance(vulns, dict) else vulns for threat in threats: for cve in threat.get("Cve", []): threat_list[cve].append( { "Title": threat.get("Title", ""), "Category": threat.get("Category", ""), "Severity": threat.get("Severity", ""), "Description": threat.get("Description", ""), "Cve": threat.get("Cve", ""), "Source": threat.get("Source", ""), "Published": threat.get("Published", ""), "Updated": threat.get("Updated", ""), "ThreatLastTrendingOn": threat.get("ThreatLastTrendingOn", ""), "Trending": threat.get("Trending", ""), } ) for vulnerability in vulns: last_trending = vulnerability.get("VulnLastTrendingOn", "") all_cves[vulnerability.get("Cve", "No ID Found")] = { "Cve": vulnerability.get("Cve", ""), "CVSS": vulnerability.get("BaseScore", ""), "VRR": risk_rating, "ThreatCount": len(threat_list.get(vulnerability.get("Cve", ""), [])), "Trending": vulnerability.get("Trending", ""), "VulnLastTrendingOn": last_trending if last_trending else "Not Found", "Threats": threat_list.get(vulnerability.get("Cve", ""), []), "Description": vulnerability.get("Description", ""), } cve_list = [] for cve in all_cves.values(): if isinstance(cve, list): cve_list.extend(cve) else: cve_list.append(cve) ransomware_cves = [] for cve in cve_list: for threat in cve.get("Threats", []): if threat.get("Category", "").lower() == "ransomware": ransomware_cves.append(cve) break return ransomware_cves def display_ransomware_cve_results(ransomware_cves): """ Set context data and human readable for ransomware cves. will raise an error message if no ransomware cves found. :param ransomware_cves: list of ransomware cves :return: standard output """ ransomware_cves_count = len(ransomware_cves) if ransomware_cves_count <= 0: return_results("No ransomware CVEs found.") demisto.setContext("CVECount", ransomware_cves_count) readable_output = "### Total CVEs found: " + str(len(ransomware_cves)) + "\n" readable_output += tableToMarkdown( "List of CVEs that have ransomware threat", ransomware_cves, ["Cve", "CVSS", "VRR", "ThreatCount", "VulnLastTrendingOn", "Trending"], header_transform, removeNull=True, ) return CommandResults( outputs_prefix="RiskSense.RansomwareCves", outputs_key_field="Cve", outputs=ransomware_cves, readable_output=readable_output, raw_response={}, ) def display_ransomware_trending_cve_results(ransomware_cves): """ Retrieve trending ransomware cves and Set context data and human readable for trending ransomware cves. will raise an error message if no trending ransomware cves found. :param ransomware_cves: list of ransomware cves. :return: standard output. """ ransomware_trending = get_ransomware_trending_cves(ransomware_cves) ransomware_trending_cves_count = len(ransomware_trending) if ransomware_trending_cves_count <= 0: return_results("No CVEs found With trending ransomware.") demisto.setContext("TrendingCVECount", ransomware_trending_cves_count) readable_output = "### Total CVEs found: " + str(len(ransomware_trending)) + "\n" readable_output += tableToMarkdown( "List of CVEs that are ransomware trending", ransomware_trending, ["Cve", "CVSS", "VRR", "ThreatCount", "VulnLastTrendingOn", "Trending"], header_transform, removeNull=True, ) return CommandResults( outputs_prefix="RiskSense.RansomwareTrendingCves", outputs_key_field="Cve", outputs=ransomware_trending, readable_output=readable_output, raw_response={}, ) def main() -> None: LOG("Start RiskSense get ransomeware cves script") # Fetch Parameter trending = demisto.args().get("trending") results = demisto.executeCommand( "risksense-get-host-findings", {"fieldname": "threat_categories", "operator": "EXACT", "value": "Ransomware", "size": 1000, "status": "Open"}, ) host_findings = results[0].get("EntryContext", {}).get("RiskSense.HostFinding(val.ID == obj.ID)") if not host_findings: return_results("Key [RiskSense.HostFinding] was not found in context data.") host_findings = [host_findings] if isinstance(host_findings, dict) else host_findings ransomware_cves = get_ransomware_cves(host_findings) if argToBoolean(trending): result = display_ransomware_trending_cve_results(ransomware_cves) return_results(result) else: result = display_ransomware_cve_results(ransomware_cves) return_results(result) if __name__ == "__builtin__" or __name__ == "builtins": main()