diff --git a/plugins/rapid7_insightvm/komand_rapid7_insightvm/triggers/scan_completion/schema.py b/plugins/rapid7_insightvm/komand_rapid7_insightvm/triggers/scan_completion/schema.py index c09f8230f1..ca2d3f33f3 100644 --- a/plugins/rapid7_insightvm/komand_rapid7_insightvm/triggers/scan_completion/schema.py +++ b/plugins/rapid7_insightvm/komand_rapid7_insightvm/triggers/scan_completion/schema.py @@ -22,8 +22,6 @@ class Output: ASSET_ID = "asset_id" HOSTNAME = "hostname" IP = "ip" - NEXPOSE_ID = "nexpose_id" - SOFTWARE_UPDATE_ID = "software_update_id" SOLUTION_ID = "solution_id" SOLUTION_SUMMARY = "solution_summary" VULNERABILITY_ID = "vulnerability_id" @@ -103,7 +101,7 @@ class ScanCompletionOutput(insightconnect_plugin_runtime.Output): "title": "Variables", "properties": { "asset_id": { - "type": "string", + "type": "integer", "title": "Asset ID", "description": "Asset ID", "order": 1 @@ -120,29 +118,17 @@ class ScanCompletionOutput(insightconnect_plugin_runtime.Output): "description": "IP", "order": 3 }, - "nexpose_id": { - "type": "string", - "title": "Nexpose ID", - "description": "Nexpose ID", - "order": 5 - }, - "software_update_id": { - "type": "string", - "title": "Software Update ID", - "description": "Software update ID", - "order": 8 - }, "solution_id": { "type": "string", "title": "Solution ID", "description": "Solution ID", - "order": 6 + "order": 5 }, "solution_summary": { "type": "string", "title": "Solution Summary", "description": "Solution Summary", - "order": 7 + "order": 6 }, "vulnerability_id": { "type": "string", diff --git a/plugins/rapid7_insightvm/komand_rapid7_insightvm/triggers/scan_completion/trigger.py b/plugins/rapid7_insightvm/komand_rapid7_insightvm/triggers/scan_completion/trigger.py index b814e65a01..524a2a1f54 100644 --- a/plugins/rapid7_insightvm/komand_rapid7_insightvm/triggers/scan_completion/trigger.py +++ b/plugins/rapid7_insightvm/komand_rapid7_insightvm/triggers/scan_completion/trigger.py @@ -29,22 +29,28 @@ def run(self, params={}): # Build API call resource_helper = ResourceRequests(self.connection.session, self.logger) - endpoint = Scan.scans(self.connection.console_url) + scans_endpoint = Scan.scans(self.connection.console_url) # Get ALL scans and handle pagination - find last/latest completed scan ID - response = resource_helper.paged_resource_request(endpoint=endpoint, method="get", params={"sort": "id,desc"}) + response = resource_helper.resource_request(endpoint=scans_endpoint, method="get", params={"sort": "id,desc"}) last_id = 0 - for resp in response: - if resp["id"] > last_id: - last_id = resp["id"] + # print(response) + if response.get("resources")[0].get("id") > last_id: + last_id = response.get("resources")[0].get("id") while True: + response = resource_helper.resource_request(endpoint=scans_endpoint, method="get", + params={"sort": "id,desc"}) - if site_id and site_id in response[0]['siteId']: + if response.get("resources")[0].get("id") >= last_id: continue while True: - endpoint = Asset.assets(self.connection.console_url, last_id + 1) + + if site_id and site_id in response[0]["siteId"]: + continue + + endpoint = Asset.assets(self.connection.console_url, last_id) try: asset_response = resource_helper.resource_request(endpoint=endpoint, method="get") @@ -53,21 +59,27 @@ def run(self, params={}): # Placeholders for now - Basically check for input and # if it is in response - if ip_address and ip_address in asset_response.get('ip'): + if ip_address and ip_address in asset_response.get("ip"): continue - if risk_score and risk_score in asset_response.get('riskScore'): - continue + # if risk_score and risk_score in asset_response.get('riskScore'): + # continue - if hostname and hostname in asset_response.get('hostName'): + # Hostname is not always present so we need to handle it. + if not asset_response.get("hostName"): + asset_response["hostName"] = "" + if not asset_response.get("hostNames"): + asset_response["hostNames"] = "" + + if hostname and hostname in asset_response.get("hostName"): continue - if source and source in asset_response.get('hostNames')[0].get('source'): + if source and source in asset_response.get("hostNames")[0].get("source"): continue # Cannot find asset_group, cve or site_id from Get Asset By ID. # Next, run GET Asset Vulnerabilities to retrieve vulnerability IDs - endpoint = VulnerabilityResult.vulnerabilities_for_asset(self.connection.console_url, last_id + 1) + endpoint = VulnerabilityResult.vulnerabilities_for_asset(self.connection.console_url, last_id) try: asset_vuln_response = resource_helper.paged_resource_request(endpoint=endpoint, method="get") except Exception: @@ -75,33 +87,55 @@ def run(self, params={}): # Add all the vulnerability IDs related to the asset into a list vulnerability_ids = [] + # print(f"\n{asset_vuln_response}\n") for vulns in asset_vuln_response: - for i in vulns: - for j in i: - vulnerability_ids.append(j.get('id')) + vulnerability_ids.append(vulns.get("id")) + print(f"\n{vulnerability_ids}\n") # Next, Get Asset Vulnerability Solution by vulnerability ID for vulnerability_id in vulnerability_ids: - endpoint = Asset.asset_vulnerability_solution(self.connection.console_url, last_id + 1, vulnerability_id) + print(f"\n\n{last_id} + {vulnerability_id}") + + endpoint = Asset.asset_vulnerability_solution( + self.connection.console_url, last_id, vulnerability_id + ) try: solution_response = resource_helper.resource_request(endpoint=endpoint, method="get") except Exception: break - solution_data = solution_response.get('resources')[0] + try: + solution_data = solution_response.get("resources")[0] + except IndexError: + break self.send( { Output.ASSET_ID: asset_response.get("id"), Output.HOSTNAME: asset_response.get("hostName"), Output.IP: asset_response.get("ip"), - Output.NEXPOSE_ID: "", - Output.SOFTWARE_UPDATE_ID: "", - Output.SOLUTION_ID: solution_data.get('id'), - Output.SOLUTION_SUMMARY: solution_data.get('summary').get('text'), + Output.SOLUTION_ID: self.strip_msft_id(solution_data.get("id")), + Output.SOLUTION_SUMMARY: solution_data.get("summary").get("text"), Output.VULNERABILITY_ID: vulnerability_id, } ) last_id += 1 - time.sleep(params.get(Input.INTERVAL) * 60) + time.sleep(params.get(Input.INTERVAL) * 10) + + @staticmethod + def strip_msft_id(solution_id: str) -> str: + """ + Helper method to strip solution IDs specific to microsoft IDs + to return a useful solution ID for sccm + + :param solution_id: Solution ID + :return: Regular solution ID or stripped solution ID + """ + + list_x = solution_id.split("-") + + if list_x[0] == "msft": + return "-".join(list_x[2:]) + else: + return solution_id diff --git a/plugins/rapid7_insightvm/plugin.spec.yaml b/plugins/rapid7_insightvm/plugin.spec.yaml index e4c9dd2475..e991566bc5 100644 --- a/plugins/rapid7_insightvm/plugin.spec.yaml +++ b/plugins/rapid7_insightvm/plugin.spec.yaml @@ -4412,7 +4412,7 @@ triggers: asset_id: title: Asset ID description: Asset ID - type: string + type: integer required: false hostname: title: Hostname @@ -4429,11 +4429,6 @@ triggers: description: Vulnerability ID type: string required: false - nexpose_id: - title: Nexpose ID - description: Nexpose ID - type: string - required: false solution_id: title: Solution ID description: Solution ID @@ -4444,8 +4439,3 @@ triggers: description: Solution Summary type: string required: false - software_update_id: - title: Software Update ID - description: Software update ID - type: string - required: false \ No newline at end of file