From 142c3dd78b49475889e1819e2c25befad0f54e7f Mon Sep 17 00:00:00 2001 From: Dante Acosta Date: Fri, 5 Apr 2024 11:55:58 -0300 Subject: [PATCH 01/24] first attempt fixing missing policy_id parameter. must be tested with client --- CHANGELOG/current/214.md | 1 + .../static/executors/official/tenableio.py | 22 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) create mode 100644 CHANGELOG/current/214.md diff --git a/CHANGELOG/current/214.md b/CHANGELOG/current/214.md new file mode 100644 index 00000000..2d7fccd6 --- /dev/null +++ b/CHANGELOG/current/214.md @@ -0,0 +1 @@ +[FIX] Fixed missing policy_id error when loading user-defined report templates. #214 diff --git a/faraday_agent_dispatcher/static/executors/official/tenableio.py b/faraday_agent_dispatcher/static/executors/official/tenableio.py index 609c0a60..3c462b44 100644 --- a/faraday_agent_dispatcher/static/executors/official/tenableio.py +++ b/faraday_agent_dispatcher/static/executors/official/tenableio.py @@ -48,6 +48,7 @@ def main(): TENABLE_SCAN_NAME = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_NAME", "faraday-scan") TENABLE_SCANNER_NAME = os.getenv("EXECUTOR_CONFIG_TENABLE_SCANNER_NAME") + TENABLE_POLICY_ID = os.getenv("EXECUTOR_CONFIG_TENABLE_POLICY_ID") TENABLE_SCAN_ID = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_ID") TENABLE_RELAUNCH_SCAN = os.getenv("EXECUTOR_CONFIG_RELAUNCH_SCAN", "False").lower() == "true" TENABLE_SCAN_TARGET = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_TARGET") @@ -84,19 +85,16 @@ def main(): target = TENABLE_SCAN_TARGET target_ip = resolve_hostname(target) log(f"The target ip is {target_ip}") + scan_kwargs = { + "name": TENABLE_SCAN_NAME, + "targets": [target_ip], + "template": TENABLE_SCAN_TEMPLATE, + } + if TENABLE_POLICY_ID: + scan_kwargs["policy_id"] = TENABLE_POLICY_ID if TENABLE_SCANNER_NAME: - scan = tio.scans.create( - name=TENABLE_SCAN_NAME, - targets=[target_ip], - template=TENABLE_SCAN_TEMPLATE, - scanner=TENABLE_SCANNER_NAME, - ) - else: - scan = tio.scans.create( - name=TENABLE_SCAN_NAME, - targets=[target_ip], - template=TENABLE_SCAN_TEMPLATE, - ) + scan_kwargs["scanner"] = TENABLE_SCANNER_NAME + scan = tio.scans.create(**scan_kwargs) tio.scans.launch(scan["id"]) status = "pending" while status[-2:] != "ed": From 701be92ddd5260e29cb1a05fa14ecaef993e552a Mon Sep 17 00:00:00 2001 From: Dante Acosta Date: Wed, 10 Apr 2024 11:27:37 -0300 Subject: [PATCH 02/24] Add Tenable SC agent --- .../static/executors/official/tenablesc.py | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 faraday_agent_dispatcher/static/executors/official/tenablesc.py diff --git a/faraday_agent_dispatcher/static/executors/official/tenablesc.py b/faraday_agent_dispatcher/static/executors/official/tenablesc.py new file mode 100644 index 00000000..befa4e4a --- /dev/null +++ b/faraday_agent_dispatcher/static/executors/official/tenablesc.py @@ -0,0 +1,108 @@ +import os +import sys +import time +from urllib.parse import urlparse +from tenable.sc import TenableSC +from faraday_plugins.plugins.repo.nessus_sc.plugin import NessusScPlugin + +from faraday_agent_dispatcher.utils.url_utils import resolve_hostname + + +def log(msg): + print(msg, file=sys.stderr) + + +def main(): + ignore_info = os.getenv("AGENT_CONFIG_IGNORE_INFO", "False").lower() == "true" + hostname_resolution = os.getenv("AGENT_CONFIG_RESOLVE_HOSTNAME", "True").lower() == "true" + vuln_tag = os.getenv("AGENT_CONFIG_VULN_TAG", None) + if vuln_tag: + vuln_tag = vuln_tag.split(",") + service_tag = os.getenv("AGENT_CONFIG_SERVICE_TAG", None) + if service_tag: + service_tag = service_tag.split(",") + host_tag = os.getenv("AGENT_CONFIG_HOSTNAME_TAG", None) + if host_tag: + host_tag = host_tag.split(",") + + TENABLE_SCAN_NAME = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_NAME", "faraday-scan") + TENABLE_SCANNER_NAME = os.getenv("EXECUTOR_CONFIG_TENABLE_SCANNER_NAME") + TENABLE_SCAN_ID = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_ID") + TENABLE_SCAN_TARGETS = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_TARGETS") + TENABLE_SCAN_REPO = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_REPO") + TENABLE_SCAN_TEMPLATE = os.getenv( + "EXECUTOR_CONFIG_TENABLE_SCAN_TEMPLATE", + "basic", + ) + TENABLE_PULL_INTERVAL = os.getenv("TENABLE_PULL_INTERVAL", 30) + TENABLE_ACCESS_KEY = os.getenv("TENABLE_ACCESS_KEY") + TENABLE_SECRET_KEY = os.getenv("TENABLE_SECRET_KEY") + TENABLE_URL = os.getenv("TENABLE_URL") + if not (TENABLE_ACCESS_KEY and TENABLE_SECRET_KEY): + log("TenableIo access_key and secret_key were not provided") + exit(1) + + if not TENABLE_SCAN_TARGETS: + log("Scan Target were not provided") + exit(1) + if not TENABLE_URL: + log("Tenable Url not provided") + exit(1) + targets = [] + for target in TENABLE_SCAN_TARGETS.split(","): + parse_target = urlparse(target) + if parse_target.netloc: + targets.append(resolve_hostname(parse_target.netloc)) + else: + targets.append(resolve_hostname(target)) + log(f"Targets ip {targets}") + tsc = TenableSC(host=TENABLE_URL, access_key=TENABLE_ACCESS_KEY, secret_key=TENABLE_SECRET_KEY) + if TENABLE_SCAN_ID: + scans = tsc.scans.list() + scans_id = "" + for scan in scans: + scans_id += f"{scan['id']} {scan['name']}" + if scan["id"] == TENABLE_SCAN_ID: + log( + f"Scan found: {scan['name']}", + ) + break + else: + log( + f"Scan id {TENABLE_SCAN_ID} not found, the current scans available are: {scans_id}", + ) + exit(1) + elif TENABLE_SCANNER_NAME: + scan = tsc.scans.create( + name=TENABLE_SCAN_NAME, + repo=TENABLE_SCAN_REPO, + targets=targets, + template=TENABLE_SCAN_TEMPLATE, + scanner=TENABLE_SCANNER_NAME, + ) + else: + scan = tsc.scans.create( + name=TENABLE_SCAN_NAME, repo=TENABLE_SCAN_REPO, targets=targets, template=TENABLE_SCAN_TEMPLATE + ) + tsc.scans.launch(scan["id"]) + status = "pending" + while status[-2:] != "ed": + time.sleep(int(TENABLE_PULL_INTERVAL)) + status = tsc.scans.status(scan["id"]) + if status != "completed": + log(f"Scanner ended with status {status}") + exit(1) + report = tsc.scans.export(scan["id"]) + plugin = NessusScPlugin( + ignore_info=ignore_info, + hostname_resolution=hostname_resolution, + host_tag=host_tag, + service_tag=service_tag, + vuln_tag=vuln_tag, + ) + plugin.parseOutputString(report.read()) + print(plugin.get_json()) + + +if __name__ == "__main__": + main() From e778fc16b43b60c4708ff29f13779e8b2476bfc9 Mon Sep 17 00:00:00 2001 From: Dante Acosta Date: Wed, 10 Apr 2024 13:10:40 -0300 Subject: [PATCH 03/24] Modify code logic in tenablesc --- .../static/executors/official/tenablesc.py | 64 ++++++++++++------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/faraday_agent_dispatcher/static/executors/official/tenablesc.py b/faraday_agent_dispatcher/static/executors/official/tenablesc.py index befa4e4a..05c1fb08 100644 --- a/faraday_agent_dispatcher/static/executors/official/tenablesc.py +++ b/faraday_agent_dispatcher/static/executors/official/tenablesc.py @@ -1,6 +1,7 @@ import os import sys import time +import zipfile as zp from urllib.parse import urlparse from tenable.sc import TenableSC from faraday_plugins.plugins.repo.nessus_sc.plugin import NessusScPlugin @@ -12,6 +13,24 @@ def log(msg): print(msg, file=sys.stderr) +def search_scan_id(tio, TENABLE_SCAN_ID): + scans = tio.scan_instances.list() + scans_id = "" + for scan in scans["usable"]: + scans_id += f"{scan['id']} {scan['name']}\n" + if str(scan["id"]) == str(TENABLE_SCAN_ID): + log( + f"Scan found: {scan['name']}", + ) + break + else: + log( + f"Scan id {TENABLE_SCAN_ID} not found, the current scans available are: {scans_id}", + ) + exit(1) + return scan + + def main(): ignore_info = os.getenv("AGENT_CONFIG_IGNORE_INFO", "False").lower() == "true" hostname_resolution = os.getenv("AGENT_CONFIG_RESOLVE_HOSTNAME", "True").lower() == "true" @@ -42,36 +61,37 @@ def main(): log("TenableIo access_key and secret_key were not provided") exit(1) - if not TENABLE_SCAN_TARGETS: - log("Scan Target were not provided") - exit(1) + # if not TENABLE_SCAN_TARGETS: + # log("Scan Target were not provided") + # exit(1) if not TENABLE_URL: log("Tenable Url not provided") exit(1) targets = [] - for target in TENABLE_SCAN_TARGETS.split(","): - parse_target = urlparse(target) - if parse_target.netloc: - targets.append(resolve_hostname(parse_target.netloc)) - else: - targets.append(resolve_hostname(target)) + if TENABLE_SCAN_TARGETS: + for target in TENABLE_SCAN_TARGETS.split(","): + parse_target = urlparse(target) + if parse_target.netloc: + targets.append(resolve_hostname(parse_target.netloc)) + else: + targets.append(resolve_hostname(target)) log(f"Targets ip {targets}") tsc = TenableSC(host=TENABLE_URL, access_key=TENABLE_ACCESS_KEY, secret_key=TENABLE_SECRET_KEY) if TENABLE_SCAN_ID: - scans = tsc.scans.list() - scans_id = "" - for scan in scans: - scans_id += f"{scan['id']} {scan['name']}" - if scan["id"] == TENABLE_SCAN_ID: - log( - f"Scan found: {scan['name']}", + scan = search_scan_id(tsc, TENABLE_SCAN_ID) + report = tsc.scan_instances.export_scan(scan["id"]) + with zp.ZipFile(report.read(), "r") as zip_ref: + file_name = zip_ref.namelist()[0] + with zip_ref.open(file_name): + plugin = NessusScPlugin( + ignore_info=ignore_info, + hostname_resolution=hostname_resolution, + host_tag=host_tag, + service_tag=service_tag, + vuln_tag=vuln_tag, ) - break - else: - log( - f"Scan id {TENABLE_SCAN_ID} not found, the current scans available are: {scans_id}", - ) - exit(1) + plugin.parseOutputString(file_name) + return elif TENABLE_SCANNER_NAME: scan = tsc.scans.create( name=TENABLE_SCAN_NAME, From 5172905548dc985445c96846fd52646182769cc5 Mon Sep 17 00:00:00 2001 From: Esteban Rodriguez Date: Wed, 10 Apr 2024 13:15:28 -0300 Subject: [PATCH 04/24] modify tenablesc for reading file and send to plugin parse --- .../static/executors/official/tenablesc.py | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/faraday_agent_dispatcher/static/executors/official/tenablesc.py b/faraday_agent_dispatcher/static/executors/official/tenablesc.py index 05c1fb08..f717ce95 100644 --- a/faraday_agent_dispatcher/static/executors/official/tenablesc.py +++ b/faraday_agent_dispatcher/static/executors/official/tenablesc.py @@ -5,7 +5,6 @@ from urllib.parse import urlparse from tenable.sc import TenableSC from faraday_plugins.plugins.repo.nessus_sc.plugin import NessusScPlugin - from faraday_agent_dispatcher.utils.url_utils import resolve_hostname @@ -19,16 +18,10 @@ def search_scan_id(tio, TENABLE_SCAN_ID): for scan in scans["usable"]: scans_id += f"{scan['id']} {scan['name']}\n" if str(scan["id"]) == str(TENABLE_SCAN_ID): - log( - f"Scan found: {scan['name']}", - ) - break - else: - log( - f"Scan id {TENABLE_SCAN_ID} not found, the current scans available are: {scans_id}", - ) - exit(1) - return scan + log(f"Scan found: {scan['name']}") + return scan + log(f"Scan id {TENABLE_SCAN_ID} not found, the current scans available are: {scans_id}") + exit(1) def main(): @@ -49,10 +42,7 @@ def main(): TENABLE_SCAN_ID = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_ID") TENABLE_SCAN_TARGETS = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_TARGETS") TENABLE_SCAN_REPO = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_REPO") - TENABLE_SCAN_TEMPLATE = os.getenv( - "EXECUTOR_CONFIG_TENABLE_SCAN_TEMPLATE", - "basic", - ) + TENABLE_SCAN_TEMPLATE = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_TEMPLATE", "basic") TENABLE_PULL_INTERVAL = os.getenv("TENABLE_PULL_INTERVAL", 30) TENABLE_ACCESS_KEY = os.getenv("TENABLE_ACCESS_KEY") TENABLE_SECRET_KEY = os.getenv("TENABLE_SECRET_KEY") @@ -61,12 +51,10 @@ def main(): log("TenableIo access_key and secret_key were not provided") exit(1) - # if not TENABLE_SCAN_TARGETS: - # log("Scan Target were not provided") - # exit(1) if not TENABLE_URL: log("Tenable Url not provided") exit(1) + targets = [] if TENABLE_SCAN_TARGETS: for target in TENABLE_SCAN_TARGETS.split(","): @@ -76,13 +64,15 @@ def main(): else: targets.append(resolve_hostname(target)) log(f"Targets ip {targets}") + tsc = TenableSC(host=TENABLE_URL, access_key=TENABLE_ACCESS_KEY, secret_key=TENABLE_SECRET_KEY) + if TENABLE_SCAN_ID: scan = search_scan_id(tsc, TENABLE_SCAN_ID) report = tsc.scan_instances.export_scan(scan["id"]) - with zp.ZipFile(report.read(), "r") as zip_ref: + with zp.ZipFile(io.BytesIO(report.read()), "r") as zip_ref: file_name = zip_ref.namelist()[0] - with zip_ref.open(file_name): + with zip_ref.open(file_name) as file: plugin = NessusScPlugin( ignore_info=ignore_info, hostname_resolution=hostname_resolution, @@ -90,7 +80,7 @@ def main(): service_tag=service_tag, vuln_tag=vuln_tag, ) - plugin.parseOutputString(file_name) + plugin.parseOutputString(file.read()) return elif TENABLE_SCANNER_NAME: scan = tsc.scans.create( @@ -102,16 +92,22 @@ def main(): ) else: scan = tsc.scans.create( - name=TENABLE_SCAN_NAME, repo=TENABLE_SCAN_REPO, targets=targets, template=TENABLE_SCAN_TEMPLATE + name=TENABLE_SCAN_NAME, + repo=TENABLE_SCAN_REPO, + targets=targets, + template=TENABLE_SCAN_TEMPLATE ) + tsc.scans.launch(scan["id"]) status = "pending" - while status[-2:] != "ed": + while not status.endswith("ed"): time.sleep(int(TENABLE_PULL_INTERVAL)) status = tsc.scans.status(scan["id"]) + if status != "completed": log(f"Scanner ended with status {status}") exit(1) + report = tsc.scans.export(scan["id"]) plugin = NessusScPlugin( ignore_info=ignore_info, From c2db552179807cf52a9b181cddaede0399289c91 Mon Sep 17 00:00:00 2001 From: Diego Nadares Date: Thu, 11 Apr 2024 11:38:13 -0300 Subject: [PATCH 05/24] Fix zip file usage First succesful data import. Also remove unused code. --- .../static/executors/official/tenablesc.py | 52 ++----------------- 1 file changed, 5 insertions(+), 47 deletions(-) diff --git a/faraday_agent_dispatcher/static/executors/official/tenablesc.py b/faraday_agent_dispatcher/static/executors/official/tenablesc.py index f717ce95..b979541d 100644 --- a/faraday_agent_dispatcher/static/executors/official/tenablesc.py +++ b/faraday_agent_dispatcher/static/executors/official/tenablesc.py @@ -1,10 +1,10 @@ import os +import io import sys -import time import zipfile as zp from urllib.parse import urlparse from tenable.sc import TenableSC -from faraday_plugins.plugins.repo.nessus_sc.plugin import NessusScPlugin +from faraday_plugins.plugins.repo.nessus.plugin import NessusPlugin from faraday_agent_dispatcher.utils.url_utils import resolve_hostname @@ -37,13 +37,8 @@ def main(): if host_tag: host_tag = host_tag.split(",") - TENABLE_SCAN_NAME = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_NAME", "faraday-scan") - TENABLE_SCANNER_NAME = os.getenv("EXECUTOR_CONFIG_TENABLE_SCANNER_NAME") TENABLE_SCAN_ID = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_ID") TENABLE_SCAN_TARGETS = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_TARGETS") - TENABLE_SCAN_REPO = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_REPO") - TENABLE_SCAN_TEMPLATE = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_TEMPLATE", "basic") - TENABLE_PULL_INTERVAL = os.getenv("TENABLE_PULL_INTERVAL", 30) TENABLE_ACCESS_KEY = os.getenv("TENABLE_ACCESS_KEY") TENABLE_SECRET_KEY = os.getenv("TENABLE_SECRET_KEY") TENABLE_URL = os.getenv("TENABLE_URL") @@ -71,9 +66,8 @@ def main(): scan = search_scan_id(tsc, TENABLE_SCAN_ID) report = tsc.scan_instances.export_scan(scan["id"]) with zp.ZipFile(io.BytesIO(report.read()), "r") as zip_ref: - file_name = zip_ref.namelist()[0] - with zip_ref.open(file_name) as file: - plugin = NessusScPlugin( + with zip_ref.open(zip_ref.namelist()[0]) as file: + plugin = NessusPlugin( ignore_info=ignore_info, hostname_resolution=hostname_resolution, host_tag=host_tag, @@ -81,43 +75,7 @@ def main(): vuln_tag=vuln_tag, ) plugin.parseOutputString(file.read()) - return - elif TENABLE_SCANNER_NAME: - scan = tsc.scans.create( - name=TENABLE_SCAN_NAME, - repo=TENABLE_SCAN_REPO, - targets=targets, - template=TENABLE_SCAN_TEMPLATE, - scanner=TENABLE_SCANNER_NAME, - ) - else: - scan = tsc.scans.create( - name=TENABLE_SCAN_NAME, - repo=TENABLE_SCAN_REPO, - targets=targets, - template=TENABLE_SCAN_TEMPLATE - ) - - tsc.scans.launch(scan["id"]) - status = "pending" - while not status.endswith("ed"): - time.sleep(int(TENABLE_PULL_INTERVAL)) - status = tsc.scans.status(scan["id"]) - - if status != "completed": - log(f"Scanner ended with status {status}") - exit(1) - - report = tsc.scans.export(scan["id"]) - plugin = NessusScPlugin( - ignore_info=ignore_info, - hostname_resolution=hostname_resolution, - host_tag=host_tag, - service_tag=service_tag, - vuln_tag=vuln_tag, - ) - plugin.parseOutputString(report.read()) - print(plugin.get_json()) + print(plugin.get_json()) if __name__ == "__main__": From b5a02789c77ca006d97c39a22e2c52f639973142 Mon Sep 17 00:00:00 2001 From: Dante Acosta Date: Wed, 17 Apr 2024 11:19:23 -0300 Subject: [PATCH 06/24] Fix agent websocket token not updating on yaml --- CHANGELOG/current/200.md | 1 + faraday_agent_dispatcher/dispatcher_io.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG/current/200.md diff --git a/CHANGELOG/current/200.md b/CHANGELOG/current/200.md new file mode 100644 index 00000000..0cf65535 --- /dev/null +++ b/CHANGELOG/current/200.md @@ -0,0 +1 @@ +[FIX] Fix agent websocket token not changing on registration token update #200 diff --git a/faraday_agent_dispatcher/dispatcher_io.py b/faraday_agent_dispatcher/dispatcher_io.py index 67ae0a11..b389ed75 100644 --- a/faraday_agent_dispatcher/dispatcher_io.py +++ b/faraday_agent_dispatcher/dispatcher_io.py @@ -156,7 +156,7 @@ async def register(self, registration_token=None): if not await self.check_connection(): exit(1) - if self.agent_token is None: + if self.agent_token is None or registration_token is not None: try: control_registration_token("token", registration_token) except ValueError as ex: From 881d3a903a4f86da2ba6c47d12b80afd81a8e92b Mon Sep 17 00:00:00 2001 From: Dante Acosta Date: Mon, 22 Apr 2024 11:24:00 -0300 Subject: [PATCH 07/24] Created base files for Cyber Vision agent --- CHANGELOG/current/217.md | 1 + .../executors/official/cisco_cybervision.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 CHANGELOG/current/217.md create mode 100644 faraday_agent_dispatcher/static/executors/official/cisco_cybervision.py diff --git a/CHANGELOG/current/217.md b/CHANGELOG/current/217.md new file mode 100644 index 00000000..21e2d48f --- /dev/null +++ b/CHANGELOG/current/217.md @@ -0,0 +1 @@ +[ADD] Added new agent for Cisco Cyber Vision. #217 diff --git a/faraday_agent_dispatcher/static/executors/official/cisco_cybervision.py b/faraday_agent_dispatcher/static/executors/official/cisco_cybervision.py new file mode 100644 index 00000000..c75de28a --- /dev/null +++ b/faraday_agent_dispatcher/static/executors/official/cisco_cybervision.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +import os + + +def make_report(): + print("REPORT HERE") + + +def main(): + params_cybervision_token = os.getenv("CYBERVISION_TOKEN") + print(f"Using token {params_cybervision_token}") + + +if __name__ == "__main__": + main() From fc58ca9096ebd71fd2f70dad9f32e744e65eec82 Mon Sep 17 00:00:00 2001 From: Dante Acosta Date: Fri, 26 Apr 2024 10:12:52 -0300 Subject: [PATCH 08/24] Updated tenablesc agent to match agent_parameter_types variables also reformated to remove unnused code --- .../static/executors/official/tenablesc.py | 53 ++++++++----------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/faraday_agent_dispatcher/static/executors/official/tenablesc.py b/faraday_agent_dispatcher/static/executors/official/tenablesc.py index b979541d..38206e83 100644 --- a/faraday_agent_dispatcher/static/executors/official/tenablesc.py +++ b/faraday_agent_dispatcher/static/executors/official/tenablesc.py @@ -2,10 +2,8 @@ import io import sys import zipfile as zp -from urllib.parse import urlparse from tenable.sc import TenableSC from faraday_plugins.plugins.repo.nessus.plugin import NessusPlugin -from faraday_agent_dispatcher.utils.url_utils import resolve_hostname def log(msg): @@ -38,44 +36,37 @@ def main(): host_tag = host_tag.split(",") TENABLE_SCAN_ID = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_ID") - TENABLE_SCAN_TARGETS = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_TARGETS") TENABLE_ACCESS_KEY = os.getenv("TENABLE_ACCESS_KEY") TENABLE_SECRET_KEY = os.getenv("TENABLE_SECRET_KEY") - TENABLE_URL = os.getenv("TENABLE_URL") + TENABLE_HOST = os.getenv("TENABLE_HOST") + if not (TENABLE_ACCESS_KEY and TENABLE_SECRET_KEY): - log("TenableIo access_key and secret_key were not provided") + log("TenableSC access_key and secret_key were not provided") exit(1) - if not TENABLE_URL: - log("Tenable Url not provided") + if not TENABLE_HOST: + log("TenableSC Host not provided") exit(1) - targets = [] - if TENABLE_SCAN_TARGETS: - for target in TENABLE_SCAN_TARGETS.split(","): - parse_target = urlparse(target) - if parse_target.netloc: - targets.append(resolve_hostname(parse_target.netloc)) - else: - targets.append(resolve_hostname(target)) - log(f"Targets ip {targets}") + if not TENABLE_SCAN_ID: + log("TenableSC Scan ID not provided") + exit(1) - tsc = TenableSC(host=TENABLE_URL, access_key=TENABLE_ACCESS_KEY, secret_key=TENABLE_SECRET_KEY) + tsc = TenableSC(host=TENABLE_HOST, access_key=TENABLE_ACCESS_KEY, secret_key=TENABLE_SECRET_KEY) - if TENABLE_SCAN_ID: - scan = search_scan_id(tsc, TENABLE_SCAN_ID) - report = tsc.scan_instances.export_scan(scan["id"]) - with zp.ZipFile(io.BytesIO(report.read()), "r") as zip_ref: - with zip_ref.open(zip_ref.namelist()[0]) as file: - plugin = NessusPlugin( - ignore_info=ignore_info, - hostname_resolution=hostname_resolution, - host_tag=host_tag, - service_tag=service_tag, - vuln_tag=vuln_tag, - ) - plugin.parseOutputString(file.read()) - print(plugin.get_json()) + scan = search_scan_id(tsc, TENABLE_SCAN_ID) + report = tsc.scan_instances.export_scan(scan["id"]) + with zp.ZipFile(io.BytesIO(report.read()), "r") as zip_ref: + with zip_ref.open(zip_ref.namelist()[0]) as file: + plugin = NessusPlugin( + ignore_info=ignore_info, + hostname_resolution=hostname_resolution, + host_tag=host_tag, + service_tag=service_tag, + vuln_tag=vuln_tag, + ) + plugin.parseOutputString(file.read()) + print(plugin.get_json()) if __name__ == "__main__": From 3dcdbd7831a580bb1ea625706b4d202eea225981 Mon Sep 17 00:00:00 2001 From: Diego Nadares Date: Mon, 6 May 2024 14:50:47 -0300 Subject: [PATCH 09/24] Add option to send a list of scan ids --- .../static/executors/official/tenablesc.py | 89 +++++++++++++------ 1 file changed, 63 insertions(+), 26 deletions(-) diff --git a/faraday_agent_dispatcher/static/executors/official/tenablesc.py b/faraday_agent_dispatcher/static/executors/official/tenablesc.py index 38206e83..a5e38cf2 100644 --- a/faraday_agent_dispatcher/static/executors/official/tenablesc.py +++ b/faraday_agent_dispatcher/static/executors/official/tenablesc.py @@ -1,3 +1,4 @@ +import json import os import io import sys @@ -10,16 +11,34 @@ def log(msg): print(msg, file=sys.stderr) -def search_scan_id(tio, TENABLE_SCAN_ID): - scans = tio.scan_instances.list() - scans_id = "" - for scan in scans["usable"]: - scans_id += f"{scan['id']} {scan['name']}\n" - if str(scan["id"]) == str(TENABLE_SCAN_ID): - log(f"Scan found: {scan['name']}") - return scan - log(f"Scan id {TENABLE_SCAN_ID} not found, the current scans available are: {scans_id}") - exit(1) +def get_only_usable_ids(tio, scan_ids): + tenable_scans = tio.scan_instances.list() + usable_tenable_scans = [int(scan["id"]) for scan in tenable_scans["usable"]] + log(usable_tenable_scans) + return [id for id in scan_ids if id in usable_tenable_scans] + + +def process_scan( + tsc, scan_id, ignore_info=False, hostname_resolution=False, host_tag=False, service_tag=False, vuln_tag=False +): + log(f"Processing scan id {scan_id}") + try: + report = tsc.scan_instances.export_scan(scan_id) + except Exception as e: + log(e) + return {} + with zp.ZipFile(io.BytesIO(report.read()), "r") as zip_ref: + with zip_ref.open(zip_ref.namelist()[0]) as file: + plugin = NessusPlugin( + ignore_info=ignore_info, + hostname_resolution=hostname_resolution, + host_tag=host_tag, + service_tag=service_tag, + vuln_tag=vuln_tag, + ) + plugin.parseOutputString(file.read()) + return plugin.get_json() + return {} def main(): @@ -35,7 +54,7 @@ def main(): if host_tag: host_tag = host_tag.split(",") - TENABLE_SCAN_ID = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_ID") + tenable_scan_ids = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_ID") TENABLE_ACCESS_KEY = os.getenv("TENABLE_ACCESS_KEY") TENABLE_SECRET_KEY = os.getenv("TENABLE_SECRET_KEY") TENABLE_HOST = os.getenv("TENABLE_HOST") @@ -48,26 +67,44 @@ def main(): log("TenableSC Host not provided") exit(1) - if not TENABLE_SCAN_ID: + if not tenable_scan_ids: log("TenableSC Scan ID not provided") exit(1) + # it should be a list but the it is save as a str in the environment + try: + tenable_scan_ids_list = json.loads(tenable_scan_ids) + except Exception as e: + log(f"TenableSC Scan IDs could not be parsed {e}") + exit(1) + tsc = TenableSC(host=TENABLE_HOST, access_key=TENABLE_ACCESS_KEY, secret_key=TENABLE_SECRET_KEY) + usable_scan_ids = get_only_usable_ids(tsc, tenable_scan_ids_list) + log(usable_scan_ids) - scan = search_scan_id(tsc, TENABLE_SCAN_ID) - report = tsc.scan_instances.export_scan(scan["id"]) - with zp.ZipFile(io.BytesIO(report.read()), "r") as zip_ref: - with zip_ref.open(zip_ref.namelist()[0]) as file: - plugin = NessusPlugin( - ignore_info=ignore_info, - hostname_resolution=hostname_resolution, - host_tag=host_tag, - service_tag=service_tag, - vuln_tag=vuln_tag, - ) - plugin.parseOutputString(file.read()) - print(plugin.get_json()) + responses = [] + for scan_id in usable_scan_ids: + processed_scan = process_scan( + tsc, + scan_id, + ignore_info=ignore_info, + hostname_resolution=hostname_resolution, + host_tag=host_tag, + service_tag=service_tag, + vuln_tag=vuln_tag, + ) + if processed_scan: + responses.append(processed_scan) + if responses: + final_response = json.loads(responses.pop(0)) + for response in responses: + json_response = json.loads(response) + final_response["hosts"] += [host for host in json_response["hosts"]] + print(json.dumps(final_response), flush=True) if __name__ == "__main__": - main() + try: + main() + except Exception as e: + log(f"Agent execution failed. {e}") From 376efb5680209c32d3420b15fed57344784694ab Mon Sep 17 00:00:00 2001 From: Diego Nadares Date: Mon, 6 May 2024 16:30:17 -0300 Subject: [PATCH 10/24] Add gitignore files --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 616aa923..6471dfcb 100644 --- a/.gitignore +++ b/.gitignore @@ -163,3 +163,6 @@ fabric.properties logs/* */logs/* *.log.* + +# MacOS ds files +.DS_Store From 1acc83a689d243ac9f9e69e40d6165668adc35d6 Mon Sep 17 00:00:00 2001 From: Diego Nadares Date: Tue, 7 May 2024 10:39:22 -0300 Subject: [PATCH 11/24] Remove logs --- .../static/executors/official/tenablesc.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/faraday_agent_dispatcher/static/executors/official/tenablesc.py b/faraday_agent_dispatcher/static/executors/official/tenablesc.py index a5e38cf2..5b59d4c5 100644 --- a/faraday_agent_dispatcher/static/executors/official/tenablesc.py +++ b/faraday_agent_dispatcher/static/executors/official/tenablesc.py @@ -11,11 +11,11 @@ def log(msg): print(msg, file=sys.stderr) -def get_only_usable_ids(tio, scan_ids): - tenable_scans = tio.scan_instances.list() +def get_only_usable_ids(tsc, scan_ids): + tenable_scans = tsc.scan_instances.list() usable_tenable_scans = [int(scan["id"]) for scan in tenable_scans["usable"]] log(usable_tenable_scans) - return [id for id in scan_ids if id in usable_tenable_scans] + return [_id for _id in scan_ids if _id in usable_tenable_scans] def process_scan( @@ -80,7 +80,6 @@ def main(): tsc = TenableSC(host=TENABLE_HOST, access_key=TENABLE_ACCESS_KEY, secret_key=TENABLE_SECRET_KEY) usable_scan_ids = get_only_usable_ids(tsc, tenable_scan_ids_list) - log(usable_scan_ids) responses = [] for scan_id in usable_scan_ids: @@ -99,8 +98,9 @@ def main(): final_response = json.loads(responses.pop(0)) for response in responses: json_response = json.loads(response) - final_response["hosts"] += [host for host in json_response["hosts"]] - print(json.dumps(final_response), flush=True) + for host in json_response["hosts"]: + final_response["hosts"].append(host) + print(json.dumps(final_response)) if __name__ == "__main__": From d9a73b96e876e3a727873b0b934fcf870b1c719c Mon Sep 17 00:00:00 2001 From: Diego Nadares Date: Wed, 8 May 2024 10:40:25 -0300 Subject: [PATCH 12/24] Remove log. Also fix a typo. --- .../static/executors/official/tenablesc.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/faraday_agent_dispatcher/static/executors/official/tenablesc.py b/faraday_agent_dispatcher/static/executors/official/tenablesc.py index 5b59d4c5..b32f6d31 100644 --- a/faraday_agent_dispatcher/static/executors/official/tenablesc.py +++ b/faraday_agent_dispatcher/static/executors/official/tenablesc.py @@ -14,7 +14,6 @@ def log(msg): def get_only_usable_ids(tsc, scan_ids): tenable_scans = tsc.scan_instances.list() usable_tenable_scans = [int(scan["id"]) for scan in tenable_scans["usable"]] - log(usable_tenable_scans) return [_id for _id in scan_ids if _id in usable_tenable_scans] @@ -71,7 +70,7 @@ def main(): log("TenableSC Scan ID not provided") exit(1) - # it should be a list but the it is save as a str in the environment + # it should be a list but it is save as a str in the environment try: tenable_scan_ids_list = json.loads(tenable_scan_ids) except Exception as e: From 47249b3d7f9ca4802ff17affc76e38a320d25174 Mon Sep 17 00:00:00 2001 From: Diego Nadares Date: Wed, 8 May 2024 10:50:02 -0300 Subject: [PATCH 13/24] Add changelog --- CHANGELOG/current/216.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 CHANGELOG/current/216.md diff --git a/CHANGELOG/current/216.md b/CHANGELOG/current/216.md new file mode 100644 index 00000000..4952c8b7 --- /dev/null +++ b/CHANGELOG/current/216.md @@ -0,0 +1 @@ +[ADD] Introducing the new Tenable SC agent, now available for integration. This initial version focuses on supporting scan imports. #216 From 335712632174d4fb8c323a82b6020298cd51b6d5 Mon Sep 17 00:00:00 2001 From: Dante Acosta Date: Tue, 14 May 2024 12:25:58 -0300 Subject: [PATCH 14/24] Add Cisco Cybervision agent Also added calc severity utility --- CHANGELOG/current/217.md | 2 +- .../executors/official/cisco_cybervision.py | 111 +++++++++++++++++- .../utils/severity_utils.py | 26 ++++ 3 files changed, 135 insertions(+), 4 deletions(-) create mode 100644 faraday_agent_dispatcher/utils/severity_utils.py diff --git a/CHANGELOG/current/217.md b/CHANGELOG/current/217.md index 21e2d48f..c1de6d1f 100644 --- a/CHANGELOG/current/217.md +++ b/CHANGELOG/current/217.md @@ -1 +1 @@ -[ADD] Added new agent for Cisco Cyber Vision. #217 +[ADD] Added new agent for Cisco Cyber Vision. Also added severity calc utility. #217 diff --git a/faraday_agent_dispatcher/static/executors/official/cisco_cybervision.py b/faraday_agent_dispatcher/static/executors/official/cisco_cybervision.py index c75de28a..8227ed1e 100644 --- a/faraday_agent_dispatcher/static/executors/official/cisco_cybervision.py +++ b/faraday_agent_dispatcher/static/executors/official/cisco_cybervision.py @@ -1,14 +1,119 @@ #!/usr/bin/env python import os +import re +import sys +import json +import datetime +import requests +from urllib3.exceptions import InsecureRequestWarning +from faraday_agent_dispatcher.utils.severity_utils import severity_from_score +API_BASE = "/api/3.0/" -def make_report(): - print("REPORT HERE") + +def log(msg, end="\n"): + print(msg, file=sys.stderr, flush=True, end=end) + + +def cybervision_report_composer(url, token, preset_list): + req_headers = {"accept": "application/json", "x-token-id": token} + requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) + presets_queue = [] + presets_id = {} + + # STAGE 1 - get preset list + req_url = f"{url}{API_BASE}presets" + try: + resp = requests.get(req_url, headers=req_headers, timeout=20, verify=False).json() + except TimeoutError: + log("Can't reach Cyber Vision: connection timed out") + sys.exit(1) + if "error" in resp: + log(f"API Error: {resp['error']}") + sys.exit(1) + for req_preset in preset_list: + for preset in resp: + if preset["label"] == req_preset: + presets_id[preset["label"]] = preset["id"] + presets_queue.append(preset["id"]) + + # STAGE 2 - get all vulns per preset + presets_vuln_collection = {} + step_c = 1 + step_s = 100 + for _id in presets_queue: + step_c = 1 + presets_vuln_collection[_id] = [] + while True: + req_url = f"{url}{API_BASE}presets/{_id}/visualisations/" f"vulnerability-list?page={step_c}&size={step_s}" + try: + resp = requests.get(req_url, headers=req_headers, timeout=20, verify=False) + if resp.content.decode("UTF-8") == "Service unavailable: data is not available yet": + raise ValueError(resp.content.decode("UTF-8")) + resp = resp.json() + except TimeoutError: + log("Can't reach Cyber Vision: connection timed out") + sys.exit(1) + except ValueError as ve: + log(f"{str(ve)} at preset {_id}") + break + if "error" in resp: + log(f"API Error: {resp['error']}") + break + if len(resp) < 1: + break + presets_vuln_collection[_id].append(resp) + step_c += 1 + + # STAGE 3 - processing vulns + hosts = {} + for pres_data in presets_id.items(): + for vuln_pack in presets_vuln_collection[pres_data[1]]: + for vuln in vuln_pack: + if not vuln["device"]["label"] in hosts: + hosts[vuln["device"]["label"]] = { + "ip": vuln["device"]["label"], + "description": f"Device ID {vuln['device']['id']}", + "mac": "" if not vuln["device"]["mac"] else vuln["device"]["mac"], + "vulnerabilities": [], + "tags": [pres_data[0]], + } + if not vuln["title"] in [x["name"] for x in hosts[vuln["device"]["label"]]["vulnerabilities"]]: + try: + vuln["cvss"] = float(vuln["cvss"]) + except ValueError: + vuln["cvss"] = -1.0 + hosts[vuln["device"]["label"]]["vulnerabilities"].append( + { + "name": vuln["title"], + "desc": vuln["summary"], + "severity": severity_from_score(vuln["cvss"], 10.0), + "refs": [{"name": ref["link"], "type": "other"} for ref in vuln["links"]], + "external_id": vuln["id"], + "type": "Vulnerability", + "resolution": vuln["solution"], + "data": vuln["fullDescription"], + "status": "open", + "cve": [x["cve"] for i, x in enumerate(vuln_pack) if x["title"] == vuln["title"]], + "run_date": datetime.datetime.strptime( + vuln["publishTime"], "%Y-%m-%dT%H:%M:%SZ" + ).timestamp(), + } + ) + data = {"hosts": [x[1] for x in hosts.items()]} + print(json.dumps(data)) def main(): params_cybervision_token = os.getenv("CYBERVISION_TOKEN") - print(f"Using token {params_cybervision_token}") + params_cybervision_url = os.getenv("CYBERVISION_HTTPS_URL") + params_cybervision_presets = re.findall("'([^']*)'", os.getenv("EXECUTOR_CONFIG_CYBERVISION_PRESETS")) + + if not params_cybervision_url.startswith("https://"): + log("Cyber Vision URL must be HTTPS") + sys.exit(1) + + cybervision_report_composer(params_cybervision_url, params_cybervision_token, params_cybervision_presets) if __name__ == "__main__": diff --git a/faraday_agent_dispatcher/utils/severity_utils.py b/faraday_agent_dispatcher/utils/severity_utils.py new file mode 100644 index 00000000..b6494ffd --- /dev/null +++ b/faraday_agent_dispatcher/utils/severity_utils.py @@ -0,0 +1,26 @@ +"""Severity Utils""" + + +def severity_from_score(score: float, max_score: float): + """ + Returns severity string from score range. + + >> [score] - input score value + + >> [max_score] - could be 10 or 100 (or whatever, calc is proportional) + + << [severity] - severity as string "info", "low", "medium", "high" or "critical" + + Author: Dante Acosta + """ + if 0 <= score < max_score * 0.1: + return "info" + if max_score * 0.1 <= score < max_score * 0.4: + return "low" + if max_score * 0.4 <= score < max_score * 0.7: + return "medium" + if max_score * 0.7 <= score < max_score * 0.9: + return "high" + if max_score * 0.9 <= score < max_score: + return "critical" + return "" From 1f6378a84dd4a277963e04b6cd967edb89ce0dab Mon Sep 17 00:00:00 2001 From: Dante Acosta Date: Tue, 14 May 2024 12:49:37 -0300 Subject: [PATCH 15/24] Add asset tags and vuln tags --- .../executors/official/cisco_cybervision.py | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/faraday_agent_dispatcher/static/executors/official/cisco_cybervision.py b/faraday_agent_dispatcher/static/executors/official/cisco_cybervision.py index 8227ed1e..2ddfb825 100644 --- a/faraday_agent_dispatcher/static/executors/official/cisco_cybervision.py +++ b/faraday_agent_dispatcher/static/executors/official/cisco_cybervision.py @@ -15,7 +15,7 @@ def log(msg, end="\n"): print(msg, file=sys.stderr, flush=True, end=end) -def cybervision_report_composer(url, token, preset_list): +def cybervision_report_composer(url, token, preset_list, asset_tags, vuln_tags): req_headers = {"accept": "application/json", "x-token-id": token} requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) presets_queue = [] @@ -76,7 +76,7 @@ def cybervision_report_composer(url, token, preset_list): "description": f"Device ID {vuln['device']['id']}", "mac": "" if not vuln["device"]["mac"] else vuln["device"]["mac"], "vulnerabilities": [], - "tags": [pres_data[0]], + "tags": [pres_data[0]] + asset_tags, } if not vuln["title"] in [x["name"] for x in hosts[vuln["device"]["label"]]["vulnerabilities"]]: try: @@ -98,6 +98,7 @@ def cybervision_report_composer(url, token, preset_list): "run_date": datetime.datetime.strptime( vuln["publishTime"], "%Y-%m-%dT%H:%M:%SZ" ).timestamp(), + "tags": vuln_tags, } ) data = {"hosts": [x[1] for x in hosts.items()]} @@ -113,7 +114,20 @@ def main(): log("Cyber Vision URL must be HTTPS") sys.exit(1) - cybervision_report_composer(params_cybervision_url, params_cybervision_token, params_cybervision_presets) + params_vulnerability_tags = os.getenv("AGENT_CONFIG_VULN_TAG") or [] + if params_vulnerability_tags: + params_vulnerability_tags = params_vulnerability_tags.split(",") + params_asset_tags = os.getenv("AGENT_CONFIG_HOSTNAME_TAG") or [] + if params_asset_tags: + params_asset_tags = params_asset_tags.split(",") + + cybervision_report_composer( + params_cybervision_url, + params_cybervision_token, + params_cybervision_presets, + params_asset_tags, + params_vulnerability_tags, + ) if __name__ == "__main__": From cd54acaeaecff1df9238b02b01ba9d6d362f2089 Mon Sep 17 00:00:00 2001 From: Diego Nadares Date: Mon, 20 May 2024 12:25:34 -0300 Subject: [PATCH 16/24] Fix list copy to environment. Also add log. --- faraday_agent_dispatcher/dispatcher_io.py | 6 +++++- .../static/executors/official/tenablesc.py | 7 +++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/faraday_agent_dispatcher/dispatcher_io.py b/faraday_agent_dispatcher/dispatcher_io.py index 67ae0a11..964f574b 100644 --- a/faraday_agent_dispatcher/dispatcher_io.py +++ b/faraday_agent_dispatcher/dispatcher_io.py @@ -515,7 +515,11 @@ async def create_process(executor: Executor, args: dict, plugin_args: dict): # Executor Variables if isinstance(args, dict): for k in args: - env[f"EXECUTOR_CONFIG_{k.upper()}"] = str(args[k]) + # This should allow to correctly get lists from environment with json.loads + if isinstance(args[k], list): + env[f"EXECUTOR_CONFIG_{k.upper()}"] = json.dumps(args[k]) + else: + env[f"EXECUTOR_CONFIG_{k.upper()}"] = str(args[k]) else: logger.error("Args from data received has a not supported type") raise ValueError("Args from data received has a not supported type") diff --git a/faraday_agent_dispatcher/static/executors/official/tenablesc.py b/faraday_agent_dispatcher/static/executors/official/tenablesc.py index b32f6d31..01cb0fc7 100644 --- a/faraday_agent_dispatcher/static/executors/official/tenablesc.py +++ b/faraday_agent_dispatcher/static/executors/official/tenablesc.py @@ -13,8 +13,9 @@ def log(msg): def get_only_usable_ids(tsc, scan_ids): tenable_scans = tsc.scan_instances.list() - usable_tenable_scans = [int(scan["id"]) for scan in tenable_scans["usable"]] - return [_id for _id in scan_ids if _id in usable_tenable_scans] + usable_tenable_scans = [str(scan["id"]) for scan in tenable_scans["usable"]] + log(usable_tenable_scans) + return [_id for _id in scan_ids if str(_id) in usable_tenable_scans] def process_scan( @@ -80,6 +81,8 @@ def main(): tsc = TenableSC(host=TENABLE_HOST, access_key=TENABLE_ACCESS_KEY, secret_key=TENABLE_SECRET_KEY) usable_scan_ids = get_only_usable_ids(tsc, tenable_scan_ids_list) + log(usable_scan_ids) + responses = [] for scan_id in usable_scan_ids: processed_scan = process_scan( From 8d709161b3549c024e75e9bcce5578f50aacfa04 Mon Sep 17 00:00:00 2001 From: Diego Nadares Date: Mon, 20 May 2024 12:52:36 -0300 Subject: [PATCH 17/24] Add fetch to update parameter_type repo --- .gitlab/ci/testing/.testing-gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab/ci/testing/.testing-gitlab-ci.yml b/.gitlab/ci/testing/.testing-gitlab-ci.yml index 9c5dc294..61922195 100644 --- a/.gitlab/ci/testing/.testing-gitlab-ci.yml +++ b/.gitlab/ci/testing/.testing-gitlab-ci.yml @@ -12,6 +12,7 @@ - cd typing - if [ -z "$TYPING_BRANCH" ]; then export TYPING_BRANCH="master"; fi - echo $TYPING_BRANCH + - git fetch - git checkout $TYPING_BRANCH - pip install . - cd .. From 06a5e2019183991906093eef963c504c068622d8 Mon Sep 17 00:00:00 2001 From: Diego Nadares Date: Mon, 20 May 2024 13:15:07 -0300 Subject: [PATCH 18/24] Modify default typing branch variable --- .gitlab-ci.yml | 1 + .gitlab/ci/testing/.testing-gitlab-ci.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f7ecdb74..07e253b2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,6 +13,7 @@ variables: VAULT_ROLE: 'python-sast-readonly' VAULT_ADDR: 'https://tluav-lb.faradaysec.com' VAULT_SECRET_PATH: 'gitlab/SAST' + TYPING_BRANCH: 'dev' workflow: rules: diff --git a/.gitlab/ci/testing/.testing-gitlab-ci.yml b/.gitlab/ci/testing/.testing-gitlab-ci.yml index 61922195..7d44db4e 100644 --- a/.gitlab/ci/testing/.testing-gitlab-ci.yml +++ b/.gitlab/ci/testing/.testing-gitlab-ci.yml @@ -11,7 +11,7 @@ - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/faradaysec/cloud/faraday_agent_parameters_types.git typing - cd typing - if [ -z "$TYPING_BRANCH" ]; then export TYPING_BRANCH="master"; fi - - echo $TYPING_BRANCH + - echo "Using faraday_agent_parameters_type branch -> $TYPING_BRANCH" - git fetch - git checkout $TYPING_BRANCH - pip install . From 2102f10e33905f5a0097f16d6d010dbe1e6d7d95 Mon Sep 17 00:00:00 2001 From: Adriano Canavero Date: Tue, 21 May 2024 17:08:21 -0300 Subject: [PATCH 19/24] Add tenable io changes --- .../static/executors/official/tenableio.py | 136 ++++++++++++++---- 1 file changed, 108 insertions(+), 28 deletions(-) diff --git a/faraday_agent_dispatcher/static/executors/official/tenableio.py b/faraday_agent_dispatcher/static/executors/official/tenableio.py index 3c462b44..6910b539 100644 --- a/faraday_agent_dispatcher/static/executors/official/tenableio.py +++ b/faraday_agent_dispatcher/static/executors/official/tenableio.py @@ -2,19 +2,79 @@ import sys import time import re +import json from tenable.io import TenableIO from faraday_plugins.plugins.repo.nessus.plugin import NessusPlugin -from faraday_agent_dispatcher.utils.url_utils import resolve_hostname +# from faraday_agent_dispatcher.utils.url_utils import resolve_hostname HTTP_REGEX = re.compile("^(http|https)://") +TEMPLATE_NAMES = [ + "asv", + "discovery", + "wannacry", + "intelamt", + "basic", + "patch_audit", + "webapp", + "malware", + "mobile", + "mdm", + "compliance", + "pci", + "offline", + "cloud_audit", + "scap", + "custom", + "ghost", + "spectre_meltdown", + "advanced", + "agent_advanced", + "agent_basic", + "agent_compliance", + "agent_scap", + "agent_malware", + "agent_custom", + "ripple-treck", + "zerologon", + "solorigate", + "hafnium", + "printnightmare", + "active_directory", + "log4shell", + "log4shell_dc", + "agent_log4shell", + "log4shell_vulnerable_ecosystem", + "eoy22", + "agent_inventory_collection", + "cisa_alert_aa22011a", + "contileaks", + "ransomware_ecosystem_2022", + "active_directory_identity", +] def log(msg): print(msg, file=sys.stderr) +def search_policy_id_by_template_name(tio, template_name): + policies = tio.policies.list() + for policy in policies: + if policy["name"] == template_name: + return policy["id"] + return None + + +def get_agent_group_uuid_by_agent_group_name(tio, agent_group_name): + agent_groups = tio.agent_groups.list() + for agent_group in agent_groups: + if agent_group["name"] == agent_group_name: + return agent_group["uuid"] + return None + + def search_scan_id(tio, TENABLE_SCAN_ID): scans = tio.scans.list() scans_id = "" @@ -33,6 +93,20 @@ def search_scan_id(tio, TENABLE_SCAN_ID): return scan +def parse_targets(tenable_scan_targets): + """ + Given a string of ips separated by ',' it takes out the http or https + and retrieves only the domain name or ip address""" + parsed_targets = [] + for ip in tenable_scan_targets: + if HTTP_REGEX.match(ip): + target = re.sub(HTTP_REGEX, "", ip).strip() + else: + target = ip.strip() + parsed_targets.append(target) + return parsed_targets + + def main(): ignore_info = os.getenv("AGENT_CONFIG_IGNORE_INFO", "False").lower() == "true" hostname_resolution = os.getenv("AGENT_CONFIG_RESOLVE_HOSTNAME", "True").lower() == "true" @@ -45,20 +119,17 @@ def main(): host_tag = os.getenv("AGENT_CONFIG_HOSTNAME_TAG", None) if host_tag: host_tag = host_tag.split(",") - - TENABLE_SCAN_NAME = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_NAME", "faraday-scan") - TENABLE_SCANNER_NAME = os.getenv("EXECUTOR_CONFIG_TENABLE_SCANNER_NAME") - TENABLE_POLICY_ID = os.getenv("EXECUTOR_CONFIG_TENABLE_POLICY_ID") - TENABLE_SCAN_ID = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_ID") + TENABLE_SCAN_NAME = os.getenv("EXECUTOR_CONFIG_SCAN_NAME", "faraday-scan") + TENABLE_SCAN_ID = os.getenv("EXECUTOR_CONFIG_SCAN_ID") TENABLE_RELAUNCH_SCAN = os.getenv("EXECUTOR_CONFIG_RELAUNCH_SCAN", "False").lower() == "true" - TENABLE_SCAN_TARGET = os.getenv("EXECUTOR_CONFIG_TENABLE_SCAN_TARGET") - TENABLE_SCAN_TEMPLATE = os.getenv( - "EXECUTOR_CONFIG_TENABLE_SCAN_TEMPLATE", - "basic", - ) + TENABLE_SCAN_TARGETS = os.getenv("EXECUTOR_CONFIG_SCAN_TARGETS") # solo para user-defined template + TENABLE_TEMPLATE_NAME = os.getenv("EXECUTOR_CONFIG_TEMPLATE_NAME", "agent_basic") TENABLE_PULL_INTERVAL = os.getenv("TENABLE_PULL_INTERVAL", 30) TENABLE_ACCESS_KEY = os.getenv("TENABLE_ACCESS_KEY") TENABLE_SECRET_KEY = os.getenv("TENABLE_SECRET_KEY") + TENABLE_IS_USER_DEFINED = os.getenv("EXECUTOR_CONFIG_USE_USER_DEFINED_TEMPLATE", "False").lower() == "true" + TENABLE_AGENT_GROUP_NAME = os.getenv("EXECUTOR_CONFIG_AGENT_GROUP_NAME") + if not (TENABLE_ACCESS_KEY and TENABLE_SECRET_KEY): log("TenableIo access_key and secret_key were not provided") exit(1) @@ -78,23 +149,30 @@ def main(): return if TENABLE_SCAN_ID: scan = search_scan_id(tio, TENABLE_SCAN_ID) + elif TENABLE_IS_USER_DEFINED and TENABLE_SCAN_NAME and TENABLE_SCAN_TARGETS and TENABLE_TEMPLATE_NAME: + policy_id = search_policy_id_by_template_name( + tio, TENABLE_TEMPLATE_NAME + ) # User defined template policy id is searched by template_name + if not policy_id: + log("The provided template name does not exist.") # policy_id refers to a user_defined_template + exit(1) + targets = json.loads(TENABLE_SCAN_TARGETS) + parsed_targets = parse_targets(targets) + log(f"The targets are {parsed_targets}") + scan = tio.scans.create(name=TENABLE_SCAN_NAME, targets=parsed_targets, policy_id=policy_id) else: - if HTTP_REGEX.match(TENABLE_SCAN_TARGET): - target = re.sub(HTTP_REGEX, "", TENABLE_SCAN_TARGET) - else: - target = TENABLE_SCAN_TARGET - target_ip = resolve_hostname(target) - log(f"The target ip is {target_ip}") - scan_kwargs = { - "name": TENABLE_SCAN_NAME, - "targets": [target_ip], - "template": TENABLE_SCAN_TEMPLATE, - } - if TENABLE_POLICY_ID: - scan_kwargs["policy_id"] = TENABLE_POLICY_ID - if TENABLE_SCANNER_NAME: - scan_kwargs["scanner"] = TENABLE_SCANNER_NAME - scan = tio.scans.create(**scan_kwargs) + if TENABLE_TEMPLATE_NAME not in TEMPLATE_NAMES: + log("The provided template name does not exist.") + exit(1) + agent_group_uuid = get_agent_group_uuid_by_agent_group_name(tio, TENABLE_AGENT_GROUP_NAME) + if not agent_group_uuid: + log("The provided agent group does not exist.") + exit(1) + scan = tio.scans.create( + name=TENABLE_SCAN_NAME, + template=TENABLE_TEMPLATE_NAME, + agent_group_id=[agent_group_uuid], # Must be a list, otherwise returns 500 + ) tio.scans.launch(scan["id"]) status = "pending" while status[-2:] != "ed": @@ -103,7 +181,9 @@ def main(): if status != "completed": log(f"Scanner ended with status {status}") exit(1) - report = tio.scans.export(scan["id"]) + report = tio.scans.export( + scan["id"] + ) # Valid report is assumed. If report isn't valid, executor will crash but dispatcher won't. plugin = NessusPlugin( ignore_info=ignore_info, hostname_resolution=hostname_resolution, From 4e52f5d80096b97e07ef2acaead63e433539ae88 Mon Sep 17 00:00:00 2001 From: Diego Nadares Date: Wed, 22 May 2024 13:58:54 -0300 Subject: [PATCH 20/24] Modify params_cybervision_presets parse --- .../static/executors/official/cisco_cybervision.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/faraday_agent_dispatcher/static/executors/official/cisco_cybervision.py b/faraday_agent_dispatcher/static/executors/official/cisco_cybervision.py index 2ddfb825..96efb237 100644 --- a/faraday_agent_dispatcher/static/executors/official/cisco_cybervision.py +++ b/faraday_agent_dispatcher/static/executors/official/cisco_cybervision.py @@ -1,6 +1,5 @@ #!/usr/bin/env python import os -import re import sys import json import datetime @@ -108,7 +107,11 @@ def cybervision_report_composer(url, token, preset_list, asset_tags, vuln_tags): def main(): params_cybervision_token = os.getenv("CYBERVISION_TOKEN") params_cybervision_url = os.getenv("CYBERVISION_HTTPS_URL") - params_cybervision_presets = re.findall("'([^']*)'", os.getenv("EXECUTOR_CONFIG_CYBERVISION_PRESETS")) + params_cybervision_presets_env = os.getenv("EXECUTOR_CONFIG_CYBERVISION_PRESETS") + + params_cybervision_presets = [] + if params_cybervision_presets_env: + params_cybervision_presets = json.loads(params_cybervision_presets_env) if not params_cybervision_url.startswith("https://"): log("Cyber Vision URL must be HTTPS") From a45c5461c221c5a4d15dfd5454c8581648370278 Mon Sep 17 00:00:00 2001 From: Diego Nadares Date: Wed, 22 May 2024 17:01:01 +0000 Subject: [PATCH 21/24] Update severity_utils.py --- faraday_agent_dispatcher/utils/severity_utils.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/faraday_agent_dispatcher/utils/severity_utils.py b/faraday_agent_dispatcher/utils/severity_utils.py index b6494ffd..b14a6d6e 100644 --- a/faraday_agent_dispatcher/utils/severity_utils.py +++ b/faraday_agent_dispatcher/utils/severity_utils.py @@ -1,6 +1,3 @@ -"""Severity Utils""" - - def severity_from_score(score: float, max_score: float): """ Returns severity string from score range. @@ -10,8 +7,6 @@ def severity_from_score(score: float, max_score: float): >> [max_score] - could be 10 or 100 (or whatever, calc is proportional) << [severity] - severity as string "info", "low", "medium", "high" or "critical" - - Author: Dante Acosta """ if 0 <= score < max_score * 0.1: return "info" From a96747416a442fdbc7a5257ea125cd8ce666411a Mon Sep 17 00:00:00 2001 From: Adriano Canavero Date: Wed, 22 May 2024 17:47:15 +0000 Subject: [PATCH 22/24] Update 214.md --- CHANGELOG/current/214.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG/current/214.md b/CHANGELOG/current/214.md index 2d7fccd6..644242d0 100644 --- a/CHANGELOG/current/214.md +++ b/CHANGELOG/current/214.md @@ -1 +1 @@ -[FIX] Fixed missing policy_id error when loading user-defined report templates. #214 +[FIX] Resolved the issue where users were unable to execute user-defined templates and pre-defined TenableIO templates. Additionally, fixed the functionality to retrieve completed scan results and relaunch previously created scans. #214 From 41f44e65b52a91eb8b33226f63334d54ebd9a71a Mon Sep 17 00:00:00 2001 From: Diego Nadares Date: Wed, 22 May 2024 17:51:30 +0000 Subject: [PATCH 23/24] Update tenableio.py --- faraday_agent_dispatcher/static/executors/official/tenableio.py | 1 - 1 file changed, 1 deletion(-) diff --git a/faraday_agent_dispatcher/static/executors/official/tenableio.py b/faraday_agent_dispatcher/static/executors/official/tenableio.py index 6910b539..698627f2 100644 --- a/faraday_agent_dispatcher/static/executors/official/tenableio.py +++ b/faraday_agent_dispatcher/static/executors/official/tenableio.py @@ -7,7 +7,6 @@ from tenable.io import TenableIO from faraday_plugins.plugins.repo.nessus.plugin import NessusPlugin -# from faraday_agent_dispatcher.utils.url_utils import resolve_hostname HTTP_REGEX = re.compile("^(http|https)://") TEMPLATE_NAMES = [ From 1e7eaf03597b5b5104bb9f1c329a7c076a920d9d Mon Sep 17 00:00:00 2001 From: Diego Nadares Date: Wed, 22 May 2024 17:49:31 -0300 Subject: [PATCH 24/24] Ready for release 3.4.0 --- CHANGELOG/{current => 3.4.0}/200.md | 0 CHANGELOG/{current => 3.4.0}/214.md | 0 CHANGELOG/{current => 3.4.0}/216.md | 0 CHANGELOG/{current => 3.4.0}/217.md | 0 CHANGELOG/3.4.0/date.md | 1 + RELEASE.md | 7 +++++++ faraday_agent_dispatcher/__init__.py | 2 +- 7 files changed, 9 insertions(+), 1 deletion(-) rename CHANGELOG/{current => 3.4.0}/200.md (100%) rename CHANGELOG/{current => 3.4.0}/214.md (100%) rename CHANGELOG/{current => 3.4.0}/216.md (100%) rename CHANGELOG/{current => 3.4.0}/217.md (100%) create mode 100644 CHANGELOG/3.4.0/date.md diff --git a/CHANGELOG/current/200.md b/CHANGELOG/3.4.0/200.md similarity index 100% rename from CHANGELOG/current/200.md rename to CHANGELOG/3.4.0/200.md diff --git a/CHANGELOG/current/214.md b/CHANGELOG/3.4.0/214.md similarity index 100% rename from CHANGELOG/current/214.md rename to CHANGELOG/3.4.0/214.md diff --git a/CHANGELOG/current/216.md b/CHANGELOG/3.4.0/216.md similarity index 100% rename from CHANGELOG/current/216.md rename to CHANGELOG/3.4.0/216.md diff --git a/CHANGELOG/current/217.md b/CHANGELOG/3.4.0/217.md similarity index 100% rename from CHANGELOG/current/217.md rename to CHANGELOG/3.4.0/217.md diff --git a/CHANGELOG/3.4.0/date.md b/CHANGELOG/3.4.0/date.md new file mode 100644 index 00000000..d7f736d5 --- /dev/null +++ b/CHANGELOG/3.4.0/date.md @@ -0,0 +1 @@ +May 22th, 2024 diff --git a/RELEASE.md b/RELEASE.md index 430b5a45..d5a45f9c 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,3 +1,10 @@ +3.4.0 [May 22th, 2024]: +--- + * [ADD] Introducing the new Tenable SC agent, now available for integration. This initial version focuses on supporting scan imports. #216 + * [ADD] Added new agent for Cisco Cyber Vision. Also added severity calc utility. #217 + * [FIX] Fix agent websocket token not changing on registration token update #200 + * [FIX] Resolved the issue where users were unable to execute user-defined templates and pre-defined TenableIO templates. Additionally, fixed the functionality to retrieve completed scan results and relaunch previously created scans. #214 + 3.3.0 [Mar 12th, 2024]: --- * [ADD] Add hotspots option to SonarQube. #197 diff --git a/faraday_agent_dispatcher/__init__.py b/faraday_agent_dispatcher/__init__.py index c7a1437b..fcd8d1ee 100644 --- a/faraday_agent_dispatcher/__init__.py +++ b/faraday_agent_dispatcher/__init__.py @@ -20,4 +20,4 @@ __author__ = """Faraday Development Team""" __email__ = "devel@infobytesec.com" -__version__ = "3.3.0" +__version__ = "3.4.0"