diff --git a/Dockerfile b/Dockerfile index 3a0488a..9e9cb5b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM cccs/assemblyline-v4-service-base:stable # Python path to the service class from your service directory # The following example refers to the class "Sample" from the "sample.py" file -ENV SERVICE_PATH filescan_sandbox.FilescanSandbox +ENV SERVICE_PATH metadefender_sandbox.MetaDefenderSandbox # Install any service dependencies here # For example: RUN apt-get update && apt-get install -y libyaml-dev @@ -16,7 +16,7 @@ USER assemblyline WORKDIR /opt/al_service COPY . . -ARG version=4.4.1.dev1 +ARG version=4.4.1.dev2 USER root RUN sed -i -e "s/\$SERVICE_TAG/$version/g" service_manifest.yml diff --git a/README.md b/README.md index 0c016db..bb4cc0a 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,28 @@ -# assemblyline-service-opswat-filescan-sandbox +# assemblyline-service-metadefender-sandbox -This repository is self-developed Assemblyline service which submits a file or a URL from Assemblyline4 to OPSWAT Filescan Sandbox, and after a successful scan its fetches and parses the result. +This repository is self-developed Assemblyline service which submits a file or a URL from Assemblyline4 to MetaDefender Sandbox (previously known as OPSWAT Filescan Sandbox), and after a successful scan its fetches and parses the result. ## Prerequirements -Using this integration it is necessary to have an OPSWAT Filescan Sandbox API-key. You can use the Activation Key that you received from your OPSWAT Sales Representative, and follow the instructions on the [License Activation page](https://docs.opswat.com/filescan/installation/license-activation) or you can create an API key on the [Community site](https://www.filescan.io/auth/signin) under API Key tab. +Using this integration it is necessary to have a MetaDefender Sandbox API-key. You can use the Activation Key that you received from your OPSWAT Sales Representative, and follow the instructions on the [License Activation page](https://docs.opswat.com/filescan/installation/license-activation) or you can create an API key on the [Community site](https://www.filescan.io/auth/signin) under API Key tab. ## Heuristics The result contains two types of heuristic: -- __Filescan Sandbox verdict is _VERDICT___ : This is the final verdict of Filescan Sandbox and added as a ResultSection +- __MetaDefender Sandbox verdict is _VERDICT___ : This is the final verdict of MetaDefender Sandbox and added as a ResultSection - ___VERDICT_ threat indicators__: Comes from signal groups and added as a subsection Heuristic score is the following: -| score | Filescan Sandbox verdict | -|------:|--------------------------| -| -1000 | BENIGN | -| 150 | NO THREAT | -| 299 | UNKNOWN | -| 500 | SUSPICIOUS | -| 850 | LIKELY MALICIOUS | -| 1000 | MALICIOUS | +| score | MetaDefender Sandbox verdict | +|------:|------------------------------| +| -1000 | BENIGN | +| 150 | NO THREAT | +| 299 | UNKNOWN | +| 500 | SUSPICIOUS | +| 850 | LIKELY MALICIOUS | +| 1000 | MALICIOUS | ## Official documentation diff --git a/filescan_sandbox.py b/metadefender_sandbox.py similarity index 89% rename from filescan_sandbox.py rename to metadefender_sandbox.py index c5d02ea..5825a54 100644 --- a/filescan_sandbox.py +++ b/metadefender_sandbox.py @@ -4,7 +4,7 @@ import json import base64 -import filescan_sandbox_result +import metadefender_sandbox_result import time import requests @@ -42,9 +42,9 @@ def requests_retry_session( return session -class FilescanSandbox(ServiceBase): +class MetaDefenderSandbox(ServiceBase): def __init__(self, config=None): - super(FilescanSandbox, self).__init__(config) + super(MetaDefenderSandbox, self).__init__(config) self.api_key = self.config.get("api_key") self.host = self.config.get("host") self.headers = {} @@ -57,7 +57,7 @@ def start(self): # Your service might have to do some warming up on startup to make things faster self.log.info(f"start() from {self.service_attributes.name} service called") - self.log.debug("OPSWAT Filescan Sandbox service started") + self.log.debug("MetaDefender Sandbox service started") def post_sample(self, request: ServiceRequest, url=None, file_path=None): @@ -178,7 +178,7 @@ def execute(self, request: ServiceRequest) -> None: assert self.poll_interval > 0 and self.timeout > 0, "Poll interval or timeout is not appropriate" except Exception as e: self.log.error( - "No API key or Host found for OPSWAT Filescan Sandbox. Error: {e!r}" + "No API key or Host found for MetaDefender Sandbox. Error: {e!r}" ) raise e @@ -188,10 +188,10 @@ def execute(self, request: ServiceRequest) -> None: response = {} try: if submitted_url: - self.log.info("OPSWAT Filescan Sandbox start to scan a file") + self.log.info("MetaDefender Sandbox start to scan a file") response = self.post_sample(request, url=submitted_url) elif submitted_file: - self.log.info("OPSWAT Filescan Sandbox start to scan an URL") + self.log.info("MetaDefender Sandbox start to scan an URL") response = self.post_sample(request, file_path=submitted_file) except Exception as e: self.log.error(f"Error occurred when scan a file/URL: {e!r}") @@ -204,23 +204,23 @@ def execute(self, request: ServiceRequest) -> None: rejected = response.get("rejected_files", None) if rejected: for rejection in rejected: - rejection_result = ResultSection('OPSWAT Filescan Sandbox rejection', + rejection_result = ResultSection('MetaDefender Sandbox rejection', body_format=BODY_FORMAT.KEY_VALUE, body=json.dumps(rejection)) result.add_section(rejection_result) if response.get("reports", {}): - result = filescan_sandbox_result.result_parser(result, response) + result = metadefender_sandbox_result.result_parser(result, response) else: - self.log.warning(f"There is no OPSWAT Filescan Sandbox reports.") + self.log.warning(f"There is no MetaDefender Sandbox reports.") report_link = f"{self.host}/uploads/{response.get('flowId')}" - report_link_rs = ResultSection('OPSWAT Filescan Sandbox full report is available here:', + report_link_rs = ResultSection('MetaDefender Sandbox full report is available here:', body_format=BODY_FORMAT.URL, - body=json.dumps({"name": "Filescan Sandbox report", "url": report_link})) + body=json.dumps({"name": "MetaDefender Sandbox report", "url": report_link})) result.add_section(report_link_rs) else: - self.log.warning(f"There is no OPSWAT Filescan Sandbox response.") + self.log.warning(f"There is no MetaDefender Sandbox response.") request.result = result diff --git a/filescan_sandbox_result.py b/metadefender_sandbox_result.py similarity index 99% rename from filescan_sandbox_result.py rename to metadefender_sandbox_result.py index 4b18c1e..a304a35 100644 --- a/filescan_sandbox_result.py +++ b/metadefender_sandbox_result.py @@ -274,7 +274,7 @@ def process_resources(result_section, resources): def parse_report(report, report_id, flow_id): compact_result = parse_compact_result(report, report_id, flow_id) verdict_rs = ResultSection( - "OPSWAT Filescan Sandbox result", + "MetaDefender Sandbox result", body_format=BODY_FORMAT.KEY_VALUE, body=json.dumps(compact_result), ) diff --git a/service_manifest.yml b/service_manifest.yml index a9cd444..c6c8e2d 100644 --- a/service_manifest.yml +++ b/service_manifest.yml @@ -1,9 +1,9 @@ # Name of the service -name: OPSWAT_Filescan_Sandbox +name: MetaDefender_Sandbox # Version of the service version: $SERVICE_TAG -description: This Assemblyline service interfaces with the OPSWAT Filescan Sandbox, detonating files and URLs. This integration was developed by OPSWAT. (C) OPSWAT, Inc. +description: This Assemblyline service interfaces with the MetaDefender Sandbox -previously known as OPSWAT Filescan Sandbox-, detonating files and URLs. This integration was developed by OPSWAT. (C) OPSWAT, Inc. accepts: .* rejects: empty @@ -26,62 +26,62 @@ uses_metadata: true # >= 1000: malicious heuristics: - - description: OPSWAT Filescan Sandbox determined that the file is benign. + - description: MetaDefender Sandbox determined that the file is benign. filetype: "*" heur_id: 1 - name: Filescan Sandbox verdict is benign. + name: MetaDefender Sandbox verdict is benign. score: -1000 - - description: OPSWAT Filescan Sandbox signal group is benign. + - description: MetaDefender Sandbox signal group is benign. filetype: "*" heur_id: 2 name: Benign threat indicators score: -1000 - - description: OPSWAT Filescan Sandbox determined that the file is informational/no threat. + - description: MetaDefender Sandbox determined that the file is informational/no threat. filetype: "*" heur_id: 3 - name: Filescan Sandbox verdict is no threat. + name: MetaDefender Sandbox verdict is no threat. score: 150 - - description: OPSWAT Filescan Sandbox signal group is informational/no threat. + - description: MetaDefender Sandbox signal group is informational/no threat. filetype: "*" heur_id: 4 name: Informational threat indicators score: 150 - - description: OPSWAT Filescan Sandbox determined that the file is unknown. + - description: MetaDefender Sandbox determined that the file is unknown. filetype: "*" heur_id: 5 - name: Filescan Sandbox verdict is unknown + name: MetaDefender Sandbox verdict is unknown score: 299 - - description: OPSWAT Filescan Sandbox signal group is unknown. + - description: MetaDefender Sandbox signal group is unknown. filetype: "*" heur_id: 6 name: Unknown threat indicators score: 299 - - description: OPSWAT Filescan Sandbox determined that the file is suspicious. + - description: MetaDefender Sandbox determined that the file is suspicious. filetype: "*" heur_id: 7 - name: Filescan Sandbox verdict is suspicious + name: MetaDefender Sandbox verdict is suspicious score: 500 - - description: OPSWAT Filescan Sandbox signal group is suspicious. + - description: MetaDefender Sandbox signal group is suspicious. filetype: "*" heur_id: 8 name: Suspicious threat indicators score: 500 - - description: OPSWAT Filescan Sandbox determined that the file is likely malicious. + - description: MetaDefender Sandbox determined that the file is likely malicious. filetype: "*" heur_id: 9 - name: Filescan Sandbox verdict is likely malicious + name: MetaDefender Sandbox verdict is likely malicious score: 850 - - description: OPSWAT Filescan Sandbox signal group is likely malicious. + - description: MetaDefender Sandbox signal group is likely malicious. filetype: "*" heur_id: 10 name: Likely malicious threat indicators score: 850 - - description: OPSWAT Filescan Sandbox determined that the file is malicious. + - description: MetaDefender Sandbox determined that the file is malicious. filetype: "*" heur_id: 11 - name: Filescan Sandbox verdict is malicious + name: MetaDefender Sandbox verdict is malicious score: 1000 - - description: OPSWAT Filescan Sandbox signal group is malicious. + - description: MetaDefender Sandbox signal group is malicious. filetype: "*" heur_id: 12 name: Malicious threat indicators @@ -91,7 +91,7 @@ heuristics: # - the name of the docker container that will be created # - CPU and ram allocation by the container docker_config: - image: ${REGISTRY}opswat/assemblyline-service-opswat-filescan-sandbox:$SERVICE_TAG + image: ${REGISTRY}opswat/assemblyline-service-metadefender-sandbox:$SERVICE_TAG cpu_cores: 1.0 ram_mb: 1024 allow_internet_access: true diff --git a/tests/filescan_sandbox_test.py b/tests/metadefender_sandbox_test.py similarity index 92% rename from tests/filescan_sandbox_test.py rename to tests/metadefender_sandbox_test.py index 697e975..d9f7e3d 100644 --- a/tests/filescan_sandbox_test.py +++ b/tests/metadefender_sandbox_test.py @@ -8,7 +8,7 @@ sys.path.append("..") -import filescan_sandbox_result +import metadefender_sandbox_result from assemblyline_v4_service.common.result import ( Result, ResultSection, @@ -22,7 +22,7 @@ def util_load_json(path: str) -> Any: return json.loads(f.read()) -class TestFilescanSandboxResult: +class TestMetaDefenderSandboxResult: @classmethod def setup_class(cls): # copy yml @@ -51,7 +51,7 @@ def test_parse_compact_result_bad(): .get("reports", {}) .get("93a90ffb-1aac-43f6-abdd-c579d6ae14df", {}) ) - compact_result = filescan_sandbox_result.parse_compact_result( + compact_result = metadefender_sandbox_result.parse_compact_result( raw_response, "93a90ffb-1aac-43f6-abdd-c579d6ae14df", "64d1fb9c2a1db2a88ac17017", @@ -76,7 +76,7 @@ def test_parse_compact_result_informational(): .get("reports", {}) .get("21815d5f-3653-466e-a421-187423ca7b93", {}) ) - compact_result = filescan_sandbox_result.parse_compact_result( + compact_result = metadefender_sandbox_result.parse_compact_result( raw_response, "21815d5f-3653-466e-a421-187423ca7b93", "64de1abb9489ac1ead366732", @@ -101,7 +101,7 @@ def test_parse_compact_result_badfile2(): .get("reports", {}) .get("d389e943-dc72-4070-aade-1d11f0457ea3", {}) ) - compact_result = filescan_sandbox_result.parse_compact_result( + compact_result = metadefender_sandbox_result.parse_compact_result( raw_response, "d389e943-dc72-4070-aade-1d11f0457ea3", "64de19f4a29d57e20384dac6", @@ -146,7 +146,7 @@ def test_parse_compact_result_badfile2(): @staticmethod def test_parse_compact_result_empty(): raw_response = {} - compact_result = filescan_sandbox_result.parse_compact_result( + compact_result = metadefender_sandbox_result.parse_compact_result( raw_response, "93a90ffb-1aac-43f6-abdd-c579d6ae14df", "64d1fb9c2a1db2a88ac17017", @@ -175,7 +175,7 @@ def test_process_allSignalGroups(): rs = ResultSection("Test", body_format=BODY_FORMAT.TEXT, body="test") - compact_result = filescan_sandbox_result.process_allSignalGroups( + compact_result = metadefender_sandbox_result.process_allSignalGroups( rs, raw_response ) @@ -193,7 +193,7 @@ def test_process_iocs(): rs = ResultSection("Test", body_format=BODY_FORMAT.TEXT, body="test") - compact_result = filescan_sandbox_result.process_iocs(rs, raw_response) + compact_result = metadefender_sandbox_result.process_iocs(rs, raw_response) tags = { "network.email.address": ["ActivationDepartment@FedRetireSoftware.com"], "network.static.uri": [ @@ -218,7 +218,7 @@ def test_process_allOsintTags(): rs = ResultSection("Test", body_format=BODY_FORMAT.TEXT, body="test") - compact_result = filescan_sandbox_result.process_allOsintTags(rs, raw_response) + compact_result = metadefender_sandbox_result.process_allOsintTags(rs, raw_response) tags = {"av.virus_name": ["emotet", "geodo"]} assert rs.tags == tags @@ -233,7 +233,7 @@ def test_process_resources(): rs = ResultSection("Test", body_format=BODY_FORMAT.TEXT, body="test") - compact_result = filescan_sandbox_result.process_resources(rs, raw_response) + compact_result = metadefender_sandbox_result.process_resources(rs, raw_response) tags = { "av.virus_name": ["Trojan/Riskware!my0NYEEN"], "attribution.family": ["riskware"],