MetaDefender Aether
Next-generation unified Zero-Day detection solution, combining Threat Reputation, Dynamic Analysis, Threat Scoring, and Threat Hunting into a single adaptive detection pipeline (previously known as MetaDefender Sandbox).
Forensics & Malware Analysis · MetaDefender Aether
Details
| ID | MetaDefender Aether |
|---|---|
| Category | Forensics & Malware Analysis |
| From Version | 6.10.0 |
| Docker Image | demisto/fastapi:0.125.0.10158186 |
README
Next-generation unified Zero-Day detection solution, combining the proven capabilities of MetaDefender Sandbox with built-in Threat Intelligence, Threat Scoring and Threat Hunting - all delivered as a single adaptive detection pipeline. (previously known as MetaDefender Sandbox)
Configure MetaDefender Aether on Cortex XSOAR
- Navigate to Settings > Integrations > Servers & Services.
- Search for MetaDefender Aether.
-
Click Add instance to create and configure a new integration instance.
Parameter Required Server URL (e.g. https://www.filescan.io/api) True API Key True Trust any certificate (not secure) False Use system proxy settings False - Click Test to validate the URLs, the API Key and connection.
Commands
You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
metadefender-aether-scan-url
Scan URL with MetaDefender Aether
Note: MetaDefender Aether handles URL scanning as a file scan.
Notice: Submitting indicators using this command might make the indicator data publicly available. See the vendor’s documentation for more details.
Base Command
metadefender-aether-scan-url
Input
| Argument Name | Description | Required |
|---|---|---|
| url | The URL to submit | Required |
| timeout | The timeout for the polling in seconds | Optional |
| hide_polling_output | Hide polling output | Optional |
| description | Uploaded file/url description | Optional |
| tags | Tags array to propagate | Optional |
| password | Custom password, in case uploaded archive is protected | Optional |
| is_private | If file should not be available for download by other users | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| DBotScore.Indicator | String | The indicator that was tested. |
| DBotScore.Type | String | The indicator type. |
| DBotScore.Vendor | String | The vendor used to calculate the score. |
| DBotScore.Score | Number | The actual score. |
| File.Name | String | The full file name. |
| File.SHA256 | String | The SHA256 hash of the file. |
| File.Malicious.Vendor | String | The vendor that reported the file as malicious. |
| MetaDefender.Aether.Analysis.finalVerdict.verdict | String | The final verdict. |
| MetaDefender.Aether.Analysis.allTags | Unknown | All tags. |
| MetaDefender.Aether.Analysis.overallState | String | Overall state of the scan. |
| MetaDefender.Aether.Analysis.taskReference.name | String | Name of the main scan task. |
| MetaDefender.Aether.Analysis.taskReference.additionalInfo | Unknown | Additional information about the main scan task. |
| MetaDefender.Aether.Analysis.taskReference.ID | String | ID of the main scan task. |
| MetaDefender.Aether.Analysis.taskReference.state | String | State of the main scan task. |
| MetaDefender.Aether.Analysis.taskReference.resourceReference | Unknown | Resource reference of the main scan task. |
| MetaDefender.Aether.Analysis.taskReference.opcount | Number | Counter. |
| MetaDefender.Aether.Analysis.taskReference.processTime | Number | processTime. |
| MetaDefender.Aether.Analysis.subtaskReferences | Unknown | Status of scan subtasks. |
| MetaDefender.Aether.Analysis.allSignalGroups | Unknown | All signal groups. |
| MetaDefender.Aether.Analysis.resources | Unknown | Resources. |
| MetaDefender.Aether.Analysis.file.name | String | The name of the file. |
| MetaDefender.Aether.Analysis.file.hash | String | The SHA256 of the file. |
| MetaDefender.Aether.Analysis.file.type | String | The type of the submission. |
Command example
!metadefender-aether-scan-url url=https://www.test.com
Context Example
{
"DBotScore":
[
{
"Indicator": "1111111111111111111111111111111111111111111111111111111111111111",
"Score": 1,
"Type": "file",
"Vendor": "MetaDefender Aether"
}
],
"File":
[
{
"Name": "https://www.test.com",
"SHA256": "1111111111111111111111111111111111111111111111111111111111111111"
}
],
"MetaDefender":
{
"Aether":
{
"Analysis":
[
{
"finalVerdict":
{
"verdict": "BENIGN"
},
"allTags":
[
{
"source": "MEDIA_TYPE",
"sourceIdentifier": "12345678",
"isRootTag": true,
"tag":
{
"name": "html",
"synonyms":
[],
"descriptions":
[],
"verdict":
{
"verdict": "INFORMATIONAL",
"threatLevel": 0.1,
"confidence": 1
}
}
}
],
"overallState": "success_partial",
"taskReference":
{
"name": "transform-file",
"additionalInfo":
{
"submitName": "https://www.test.com",
"submitTime": 1679014774270,
"digests":
{
"SHA-256": "1111111111111111111111111111111111111111111111111111111111111111"
}
},
"ID": "abcd-1234",
"state": "SUCCESS",
"resourceReference":
{
"type": "TRANSFORM_FILE",
"name": "file",
"ID": "abcd-5678"
},
"opcount": 1,
"processTime": 20350
},
"subtaskReferences":
[
{
"name": "domain-resolve",
"additionalInfo": 72,
"ID": "12345678",
"state": "SUCCESS",
"resourceReference":
{
"type": "DOMAIN_RESOLVE",
"name": "domain-resolve",
"ID": "123456789"
},
"opcount": 20,
"processTime": 11309
}
],
"allSignalGroups":
[
{
"identifier": "I000",
"description": "OSINT source detected malicious resource",
"averageSignalStrength": 0.75,
"peakSignalStrength": 0.75,
"finalSignalStrength": 0.75,
"verdict":
{
"verdict": "LIKELY_MALICIOUS",
"threatLevel": 0.75,
"confidence": 1
},
"allTags":
[],
"signals":
[
{
"strength": 0.75,
"isStrictlyBasedOnInputData": false,
"signalReadable": "OSINT provider TEST provider (2/93)",
"additionalInfo": "https://www.google.com",
"originPath": "osint.results.verdict",
"originType": "INPUT_FILE",
"originIdentifier": "1234"
}
]
}
],
"resources":
{
"00f1e4d6-27fb-45e8-8a02-dc53818044ec":
{
"resourceReference":
{
"name": "osint"
},
"results":
[]
}
},
"file":
{
"name": "https://www.test.com",
"hash": "1111111111111111111111111111111111111111111111111111111111111111",
"type": "other"
}
}
]
}
}
}
Human Readable Output
Scan Result (digest)
FileHash FileName FileType FinalVerdict SubtaskReferences Tags 1111111111111111111111111111111111111111111111111111111111111111 https://www.test.com other BENIGN osint, url-render, domain-resolve html, png
metadefender-aether-scan-file
Scan File with MetaDefender Aether
Base Command
metadefender-aether-scan-file
Input
| Argument Name | Description | Required |
|---|---|---|
| entry_id | The War Room entry ID of the file to submit | Required |
| timeout | The timeout for the polling in seconds | Optional |
| hide_polling_output | Hide polling output | Optional |
| description | Uploaded file/url description | Optional |
| tags | Tags array to propagate | Optional |
| password | Custom password, in case uploaded archive is protected | Optional |
| is_private | If file should not be available for download by other users | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| DBotScore.Indicator | String | The indicator that was tested. |
| DBotScore.Type | String | The indicator type. |
| DBotScore.Vendor | String | The vendor used to calculate the score. |
| DBotScore.Score | Number | The actual score. |
| File.Name | String | The full file name. |
| File.SHA256 | String | The SHA256 hash of the file. |
| File.Malicious.Vendor | String | The vendor that reported the file as malicious. |
| MetaDefender.Aether.Analysis.finalVerdict.verdict | String | The final verdict. |
| MetaDefender.Aether.Analysis.allTags | Unknown | All tags. |
| MetaDefender.Aether.Analysis.overallState | String | Overall state of the scan. |
| MetaDefender.Aether.Analysis.taskReference.name | String | Name of the main scan task. |
| MetaDefender.Aether.Analysis.taskReference.additionalInfo | Unknown | Additional information about the main scan task. |
| MetaDefender.Aether.Analysis.taskReference.ID | String | ID of the main scan task. |
| MetaDefender.Aether.Analysis.taskReference.state | String | State of the main scan task. |
| MetaDefender.Aether.Analysis.taskReference.resourceReference | Unknown | Resource reference of the main scan task. |
| MetaDefender.Aether.Analysis.taskReference.opcount | Number | Counter. |
| MetaDefender.Aether.Analysis.taskReference.processTime | Number | processTime. |
| MetaDefender.Aether.Analysis.subtaskReferences | Unknown | Status of scan subtasks. |
| MetaDefender.Aether.Analysis.allSignalGroups | Unknown | All signal groups. |
| MetaDefender.Aether.Analysis.resources | Unknown | Resources. |
| MetaDefender.Aether.Analysis.file.name | String | The name of the file. |
| MetaDefender.Aether.Analysis.file.hash | String | The SHA256 of the file. |
| MetaDefender.Aether.Analysis.file.type | String | The type of the submission. |
Command example
!metadefender-aether-scan-file entry_id=1234@abcd-efgh-ijkl-mnop-xyz
Context Example
{
"DBotScore":
[
{
"Indicator": "1111111111111111111111111111111111111111111111111111111111111111",
"Score": 1,
"Type": "file",
"Vendor": "MetaDefender Aether"
}
],
"File":
[
{
"Name": "1234@abcd-efgh-ijkl-mnop-xyz",
"SHA256": "1111111111111111111111111111111111111111111111111111111111111111"
}
],
"MetaDefender":
{
"Aether":
{
"Analysis":
[
{
"finalVerdict":
{
"verdict": "MALICIOUS"
},
"allTags":
[
{
"source": "SIGNAL",
"sourceIdentifier": "1234",
"isRootTag": false,
"tag":
{
"name": "packed",
"synonyms": [],
"descriptions": [],
"verdict": {
"verdict": "SUSPICIOUS",
"threatLevel": 0.5,
"confidence": 1
}
}
}
],
"overallState": "success_partial",
"taskReference":
{
"name": "transform-file",
"additionalInfo": {
"submitName": "bad_file.exe",
"submitTime": 1679011634945,
"digests": {
"SHA-256": "1111111111111111111111111111111111111111111111111111111111111111"
}
},
"ID": "1234",
"state": "SUCCESS",
"resourceReference": {
"type": "TRANSFORM_FILE",
"name": "file",
"ID": "0101010101"
},
"opcount": 1,
"processTime": 7180
},
"subtaskReferences":
[
{
"name": "domain-resolve",
"additionalInfo": 72,
"ID": "12345678",
"state": "SUCCESS",
"resourceReference":
{
"type": "DOMAIN_RESOLVE",
"name": "domain-resolve",
"ID": "123456789"
},
"opcount": 20,
"processTime": 11309
}
],
"allSignalGroups":
[
{
"identifier": "Y002",
"description": "Matched a malicious YARA rule",
"averageSignalStrength": 1,
"peakSignalStrength": 1,
"finalSignalStrength": 1,
"verdict": {
"verdict": "MALICIOUS",
"threatLevel": 1,
"confidence": 1
},
"allTags": [],
"signals": [
{
"strength": 1,
"isStrictlyBasedOnInputData": true,
"signalReadable": "Matched YARA with strength \"0.75\"",
"additionalInfo": "PUP_InstallRex_AntiFWb",
"originPath": "file.yaraMatches",
"originType": "INPUT_FILE",
"originIdentifier": "111111111111111111111111111"
}
]
}
],
"resources":
{
"00f1e4d6-27fb-45e8-8a02-dc53818044ec":
{
"resourceReference":
{
"name": "osint"
},
"results":
[]
}
},
"file":
{
"name": "1234@abcd-efgh-ijkl-mnop-xyz",
"hash": "1111111111111111111111111111111111111111111111111111111111111111",
"type": "other"
}
}
]
}
}
}
Human Readable Output
Scan Result (digest)
FileHash FileName FileType FinalVerdict SubtaskReferences Tags 1111111111111111111111111111111111111111111111111111111111111111 1234@abcd-efgh-ijkl-mnop-xyz pe MALICIOUS visualization, osint, domain-resolve html, peexe
metadefender-aether-search-query
Search for reports. Finds reports and uploaded files by various tokens.
Base Command
metadefender-aether-search-query
Input
| Argument Name | Description | Required |
|---|---|---|
| query | The query string | Required |
| limit | Number of total results. Maximum 50 | Optional |
| page | Page number, starting from 1 | Optional |
| page_size | The page size. Can be 5, 10 or 20 | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| MetaDefender.Aether.Analysis.id | String | The analysis id. |
| MetaDefender.Aether.Analysis.file.name | String | The name of the file. |
| MetaDefender.Aether.Analysis.file.sha256 | String | The SHA256 of the file. |
| MetaDefender.Aether.Analysis.verdict | String | The final verdict. |
| MetaDefender.Aether.Analysis.state | String | Overall state of the scan. |
| MetaDefender.Aether.Analysis.date | Date | The scan date. |
| MetaDefender.Aether.Analysis.file.mime_type | String | The file MimeType. |
| MetaDefender.Aether.Analysis.file.short_type | String | The type of the submission. |
| MetaDefender.Aether.Analysis.tags | Unknown | All tags. |
Command example
!metadefender-aether-search-query query="834d1dbfab8330ea5f1844f6e905ed0ac19d1033ee9a9f1122ad2051c56783dc"
Context Example
{
"MetaDefender":
{
"Aether":
{
"Analysis":
[
{
"id": "b4f92c03-0fc2-4a40-9d34-8f2b05dd240c",
"file": {
"name": "bad_file.exe",
"mime_type": "application/x-msdownload",
"short_type": "peexe",
"sha256": "834d1dbfab8330ea5f1844f6e905ed0ac19d1033ee9a9f1122ad2051c56783dc"
},
"state": "success",
"verdict": "malicious",
"tags": [
{
"source": "MEDIA_TYPE",
"sourceIdentifier": "834d1dbfab8330ea5f1844f6e905ed0ac19d1033ee9a9f1122ad2051c56783dc",
"isRootTag": true,
"tag": {
"name": "peexe",
"synonyms": [],
"descriptions": [],
"verdict": {
"verdict": "INFORMATIONAL",
"threatLevel": 0.1,
"confidence": 1
}
}
}
],
"date": "03/20/2023, 14:28:09"
}
]
}
}
}
Human Readable Output
Analysis Result
Id SampleName SHA256 Verdict State Date 8c38be8c-7cfd-4d64-be41-c98a795c9ce0 bad_file.exe 834d1dbfab8330ea5f1844f6e905ed0ac19d1033ee9a9f1122ad2051c56783dc MALICIOUS success_partial 03/14/2023, 15:07:07 e334d27f-e2b1-46c9-9936-7d3155eb3706 bad_file.exe 834d1dbfab8330ea5f1844f6e905ed0ac19d1033ee9a9f1122ad2051c56783dc UNKNOWN success 03/14/2020, 15:03:48
Configuration parameters
url— Server URL (e.g. https://www.filescan.io/api) (required)api_key— (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (3)
-
metadefender-aether-scan-fileScan file resource.
-
metadefender-aether-scan-urlScan URL resource.
-
metadefender-aether-search-querySearch for reports. Finds reports and uploaded files by various tokens.
from CommonServerPython import * from CommonServerUserPython import * from ContentClientApiModule import * """ IMPORTS """ import traceback from typing import Any import urllib3 # Disable insecure warnings urllib3.disable_warnings() """GLOBALS/PARAMS """ INTEGRATION_NAME = "MetaDefender Aether Integration" INTEGRATION_CONTEXT_NAME = "MetaDefender.Aether" TIMEOUT = 600 class Client(ContentClient): def __init__(self, api_key: str, base_url: str, proxy: bool, verify: bool): super().__init__(base_url=base_url, proxy=proxy, verify=verify) self.api_key = api_key if self.api_key: self._headers = {"X-Api-Key": self.api_key} def test_module(self) -> dict: """ Return information about the user. (Need API key) """ request_result = self._http_request( method="GET", ok_codes=(200,), url_suffix="/users/me", ) return request_result def post_sample(self, args: dict[str, Any]) -> dict[str, Any]: data = {} if description := args.get("description"): data["description"] = description if tags := args.get("tags"): data["tags"] = tags if password := args.get("password"): data["password"] = password if is_private := args.get("is_private"): data["is_private"] = is_private if url := args.get("url"): data["url"] = url return self._http_request(method="POST", url_suffix="/scan/url", ok_codes=(200,), data=data) elif entry_id := args.get("entry_id"): try: file_entry = demisto.getFilePath(entry_id) except Exception as e: demisto.debug(f"Failed to find file entry with id: {entry_id}. Traceback: {traceback.format_exc()}") raise DemistoException(f'Failed to find file entry with id:"{entry_id}". got error: {e}') with open(file_entry["path"], "rb") as file: return self._http_request( method="POST", url_suffix="/scan/file", ok_codes=(200,), data=data, files={"file": (file_entry["name"], file)}, ) else: raise DemistoException("No file or URL was provided.") def get_scan_result(self, flow_id: str) -> dict[str, Any]: filters = [ "filter=general", "filter=finalVerdict", "filter=allTags", "filter=overallState", "filter=taskReference", "filter=subtaskReferences", "filter=allSignalGroups", ] postfix = "&".join(filters) url_suffix = f"/scan/{flow_id}/report?{postfix}" response = self._http_request( method="GET", ok_codes=(200,), url_suffix=url_suffix, ) return response def get_search_query(self, query_string: str, page: int, page_size: int) -> dict[str, Any]: return self._http_request( method="GET", ok_codes=(200,), params={"query": query_string, "page_size": page_size, "page": page}, url_suffix="/reports/search", ) """ HELPER FUNCTIONS """ def build_one_reputation_result(report: dict[str, Any]): score = Common.DBotScore.NONE final_verdict = report.get("finalVerdict", {}) threat_level = final_verdict.get("threatLevel", 0) # Threatlevel based on https://www.opswat.com/docs/filescan/datasheet/verdict if threat_level == 0 or not isinstance(threat_level, int | float): score = Common.DBotScore.NONE elif threat_level <= 0.25: score = Common.DBotScore.GOOD elif 0.25 < threat_level < 0.75: score = Common.DBotScore.SUSPICIOUS elif threat_level >= 0.75: score = Common.DBotScore.BAD report_file = report.get("file", {}) report_hash = report_file.get("hash", None) dbot_score = Common.DBotScore( indicator=report_hash, indicator_type=DBotScoreType.FILE, integration_name="MetaDefender Aether", score=score, ) file = Common.File(name=report_file.get("name"), sha256=report_hash, dbot_score=dbot_score) tags = [tag.get("tag", {}).get("name") for tag in report.get("allTags", [])] subtasks = [subtask.get("name") for subtask in report.get("subtaskReferences", [])] human_readable = { "FileName": report_file.get("name"), "FileHash": report_hash, "FileType": report_file.get("type"), "FinalVerdict": report.get("finalVerdict", {}).get("verdict"), "Tags": tags, "SubtaskReferences": subtasks, } readable_output = tableToMarkdown("Scan Result (digest):", human_readable) results = CommandResults( outputs_prefix=f"{INTEGRATION_CONTEXT_NAME}.Analysis", outputs_key_field="sha256", outputs=report, raw_response=report, readable_output=readable_output, indicator=file, ) return results def build_search_query_result(analyses: list[dict]) -> list[CommandResults]: command_results = [] for analysis in analyses: file_result = analysis.get("file", {}) hr_analysis = { "Id": analysis.get("id"), "SampleName": file_result.get("name"), "SHA256": file_result.get("sha256"), "Verdict": analysis.get("verdict"), "State": analysis.get("state"), "Date": analysis.get("date"), "MIMEType": file_result.get("mime_type"), "Type": file_result.get("short_type"), "Tags": analysis.get("tags"), } score = Common.DBotScore.NONE verdict = analysis.get("verdict", "UNKNOWN") verdict_upper = verdict.upper() if verdict_upper in ("BENIGN", "INFORMATIONAL", "TRUSTED", "NO_THREAT_DETECTED", "NO_THREAT"): score = Common.DBotScore.GOOD elif verdict_upper in ("MALICIOUS", "LIKELY_MALICIOUS", "HIGH_RISK", "CONFIRMED_THREAT"): score = Common.DBotScore.BAD elif verdict_upper in ("SUSPICIOUS", "LOW_RISK"): score = Common.DBotScore.SUSPICIOUS dbot_score = Common.DBotScore( indicator=file_result.get("sha256"), indicator_type=DBotScoreType.FILE, integration_name="MetaDefender Aether", score=score, ) file_indicator = Common.File( name=file_result.get("name"), sha256=file_result.get("sha256"), dbot_score=dbot_score, ) command_result = CommandResults( outputs=analysis, readable_output=tableToMarkdown("Analysis Result:", hr_analysis), outputs_prefix=f"{INTEGRATION_CONTEXT_NAME}.Analysis", outputs_key_field="id", indicator=file_indicator, ) command_results.append(command_result) return command_results def sample_submission(client: Client, args: dict[str, Any]) -> PollResult: res = client.post_sample(args) partial_res = CommandResults(readable_output=f'Waiting for submission "{res.get("flow_id")}" to finish...') return PollResult( response=CommandResults( outputs=res, outputs_prefix=f"{INTEGRATION_CONTEXT_NAME}.Submission", outputs_key_field="flow_id", ), args_for_next_run={"flow_id": res.get("flow_id"), **args}, continue_to_poll=True, partial_result=partial_res, ) def build_reputation_result(api_reponse: dict[str, Any]): reports = api_reponse.get("reports", {}) command_res_ls = [] for report in reports.values(): command_res_ls.append(build_one_reputation_result(report)) return command_res_ls def is_valid_pass(api_response: dict[str, Any]): if "rejected_files" not in api_response: return True return all(reject.get("rejected_reason") != "INVALID_PASSWORD" for reject in api_response["rejected_files"]) @polling_function( name=demisto.command(), timeout=arg_to_number(demisto.args().get("timeout")) or TIMEOUT, interval=5, poll_message="Polling result", requires_polling_arg=False, ) def polling_submit_command(args: dict[str, Any], client: Client): if flow_id := args.get("flow_id"): api_response = client.get_scan_result(flow_id) successful_response = False if api_response.get("allFinished", False): successful_response = True if successful_response: if not is_valid_pass(api_response): raise DemistoException("Invalid password!") return PollResult(response=build_reputation_result(api_response), continue_to_poll=False) return PollResult( response=[ CommandResults( outputs=api_response, outputs_prefix=f"{INTEGRATION_CONTEXT_NAME}.Submission", outputs_key_field="flow_id", readable_output=f'Waiting for submission "{api_response.get("flow_id")}" to finish...', ), ], continue_to_poll=True, args_for_next_run={"flow_id": args.get("flow_id"), **args}, ) else: return sample_submission(client, args) """ COMMANDS """ def test_module_command(client: Client, *_) -> str: """Performs a basic GET request to check if the API is reachable and authentication is successful.""" results = client.test_module() if "accountId" in results: return "ok" raise DemistoException(f"\nTest module failed, {results}") def scan_command(client: Client, args: dict[str, Any]): return polling_submit_command(args=args, client=client) def search_query_command(client: Client, args: dict[str, Any]): def validate_args(): if page_size and page_size not in [5, 10, 20]: raise DemistoException("Page size value must be 5, 10 or 20") if page and page <= 0: raise DemistoException("Page must be an integer and greater than 0") if limit and (limit <= 0 or limit > 50): raise DemistoException("Limit must be an integer and between 1 and 50") items = [] query_string = args.get("query", "") page_size = arg_to_number(args.get("page_size")) page = arg_to_number(args.get("page")) limit = arg_to_number(args.get("limit")) or 10 validate_args() if page_size and not page: page = 1 elif not page_size and page: page_size = 10 if page_size and page: items = client.get_search_query(query_string, page, page_size).get("items", []) else: page_size = 20 page = 1 continue_query = True while continue_query: response = client.get_search_query(query_string, page, page_size) actual_items = response.get("items", []) items += actual_items # Stop if no items returned or we've reached the limit if not actual_items or len(items) >= limit: continue_query = False else: page += 1 items = items[0:limit] if items: return build_search_query_result(items) return CommandResults(readable_output="No Results were found.") """ COMMANDS MANAGER / SWITCH PANEL """ def main(): params = demisto.params() base_url = params.get("url", "") api_key = params.get("api_key", {}).get("password") verify = not params.get("insecure", False) proxy = params.get("proxy", False) command = demisto.command() demisto.info(f"Command being called is {command}") args = demisto.args() try: client = Client(api_key=api_key, base_url=base_url, verify=verify, proxy=proxy) handle_proxy() if command == "test-module": return_results(test_module_command(client)) elif command == "metadefender-aether-scan-url": return_results(scan_command(client, args)) elif command == "metadefender-aether-scan-file": return_results(scan_command(client, args)) elif command == "metadefender-aether-search-query": return_results(search_query_command(client, args)) else: raise NotImplementedError(f"{command} command is not implemented.") except Exception as e: err_msg = f"Exception in {INTEGRATION_NAME} : Failed to execute {command} command: [{e!r}]\n{traceback.format_exc()}" return_error(err_msg, error=e) """ ENTRY POINT """ if __name__ in ("__main__", "__builtin__", "builtins"): main()