FireEye Detection on Demand
FireEye Detection On Demand is a threat detection service delivered as an API for integration into the SOC workflow, SIEM analytics, data repositories, or web applications, etc. It delivers flexible file and content analysis to identify malicious behavior wherever the enterprise needs it.
Forensics & Malware Analysis · FireEye Detection on Demand
Details
| ID | FireEye Detection on Demand |
|---|---|
| Provider | Trellix |
| Category | Forensics & Malware Analysis |
| From Version | 6.0.0 |
| Docker Image | demisto/python3:3.12.8.3296088 |
| Supported Modules | Agentix XSIAM |
README
FireEye Detection On Demand is a threat detection service delivered as an API for integration into the SOC workflow, SIEM analytics, data repositories, or web applications, etc. It delivers flexible file and content analysis to identify malicious behavior wherever the enterprise needs it.
This integration was integrated and tested with version 1.4.1 of FireEye Detection on Demand
Configure FireEye Detection on Demand in Cortex
| Parameter | Description | Required |
|---|---|---|
| url | DoD hostname | True |
| apikey | API Key | True |
| insecure | Trust any certificate (not secure) | False |
| proxy | Use system proxy settings | False |
Commands
You can execute these commands from the 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.
fireeye-dod-get-hashes
Queries FireEye Detection on Demand reports for the provided md5 hashes
Base Command
fireeye-dod-get-hashes
Input
| Argument Name | Description | Required |
|---|---|---|
| md5_hashes | One or more comma separated MD5 hashes to get the reputation of. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| DBotScore.Indicator | string | The indicator that was tested. |
| DBotScore.Score | number | The actual score. |
| DBotScore.Type | unknown | The indicator type. |
| DBotScore.Vendor | unknown | The vendor used to calculate the score. |
| File.Malicious.Vendor | unknown | N/A |
| File.MD5 | unknown | The MD5 hash of the file |
| FireEyeDoD.engine_results.cache_lookup.sha256 | String | The sha256 value of the file |
| FireEyeDoD.engine_results.cache_lookup.signature_name | String | The name of the virus signature |
| FireEyeDoD.engine_results.cache_lookup.is_malicious | Number | True/False if the file is malicious |
| FireEyeDoD.engine_results.cache_lookup.verdict | String | The overall verdict of all analysis engines |
| FireEyeDoD.engine_results.cache_lookup.file_extension | String | The extension of the file |
| FireEyeDoD.engine_results.cache_lookup.weight | Number | How important this engine result is to determining malicious activity |
| FireEyeDoD.engine_results.dynamic_analysis.verdict | String | This particular engine’s verdict on whether or not the file is malicious |
| FireEyeDoD.engine_results.av_lookup.verdict | String | This particular engine’s verdict on whether or not the file is malicious |
| FireEyeDoD.engine_results.avs_lookup.verdict | String | This particular engine’s verdict on whether or not the file is malicious |
| FireEyeDoD.engine_results.dti_lookup.verdict | String | This particular engine’s verdict on whether or not the file is malicious |
| FireEyeDoD.md5 | String | The MD5 hash of the file |
| FireEyeDoD.is_malicious | Number | True/False if the file is malicious |
Command Example
!fireeye-dod-get-hashes md5_hashes=47f9fdc617f8c98a6732be534d8dbe9c
Context Example
{
"DBotScore": {
"Indicator": "47f9fdc617f8c98a6732be534d8dbe9c",
"Score": 0,
"Type": "file",
"Vendor": "FireEye DoD"
},
"File": {
"FireEyeDoD": {
"engine_results": {
"av_lookup": {
"verdict": "not_found"
},
"avs_lookup": {
"verdict": "not_found"
},
"cache_lookup": {
"verdict": "not_found"
},
"dti_lookup": {
"verdict": "not_found"
},
"dynamic_analysis": {
"verdict": "not_found"
}
},
"is_malicious": false
},
"MD5": "47f9fdc617f8c98a6732be534d8dbe9c"
}
}
Human Readable Output
FireEye DoD Results
MD5 SHA256 Malicious 47f9fdc617f8c98a6732be534d8dbe9c
fireeye-dod-submit-file
Submits file to FireEye Detection on Demand for analysis
Base Command
fireeye-dod-submit-file
Input
| Argument Name | Description | Required |
|---|---|---|
| entryID | The file entry ID to submit. | Required |
| password | Password to be used by the detection engine to decrypt a password protected file. | Optional |
| param | Command line parameter(s) to be used by detection engine when running the file. Mainly applicable to .exe files. For example, setting param to “start -h localhost -p 5555” will make the detection engine run a file named “malicious.exe” as “malicious.exe start -h localhost -p 5555”. | Optional |
| screenshot | Extract screenshot of screen activity during dynamic analysis if true, which later can be downloaded with artifacts api | Optional |
| video | Extract video activity during dynamic analysis if true, which later can be downloaded with artifacts api | Optional |
| fileExtraction | Extract dropped files from vm during dynamic analysis if true, which later can be downloaded with artifacts api | Optional |
| memoryDump | Extract memory dump files from vm during dynamic analysis if true, which later can be downloaded with artifacts api | Optional |
| pcap | Extract pcap files from vm during dynamic analysis if true, which later can be downloaded with artifacts api | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| FireEyeDoD.Scan.report_id | unknown | The report ID can be used to query the status and results of the file submission |
| FireEyeDoD.Scan.status | unknown | The current status of the file submission |
| FireEyeDoD.Scan.filename | unknown | The name of the file that was submitted |
Command Example
!fireeye-dod-submit-file entryID=37@760083ae-625e-4a6c-8e93-87ece7964dd0
Context Example
{
"FireEyeDoD": {
"Scan": {
"filename": "test-infection.exe",
"md5": "47f9fdc617f8c98a6732be534d8dbe9a",
"overall_status": "RUNNING",
"report_id": "c1d32790-5b08-45ab-a3be-3e61f8826e8b"
}
}
}
Human Readable Output
Started analysis of test-infection.exe with FireEye Detection on Demand. Results will be published to report id: c1d32790-5b08-45ab-a3be-3e61f8826e8b
fireeye-dod-submit-urls
Submits URLs to FireEye Detection on Demand for analysis
Notice: Submitting indicators using this command might make the indicator data publicly available. See the vendor’s documentation for more details.
Base Command
fireeye-dod-submit-urls
Input
| Argument Name | Description | Required |
|---|---|---|
| urls | A comma separated list of URLs to scan. Maximum of 10 per request. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| FireEyeDoD.Scan.report_id | unknown | The ID of the report |
| FireEyeDoD.Scan.status | unknown | The status of the file submission. Will be “DONE” when all engines are finished. |
Command Example
!fireeye-dod-submit-urls urls="https://www.google.com"
Context Example
{
"FireEyeDoD": {
"Scan": {
"md5": "NA",
"overall_status": "RUNNING",
"report_id": "55223a00-6741-41c4-80a9-28d3c133a5db"
}
}
}
Human Readable Output
Started analysis of [‘https://www.google.com’] with FireEye Detection on Demand. Results will be published to report id: 55223a00-6741-41c4-80a9-28d3c133a5db
fireeye-dod-get-reports
Retrieves one or more reports of file scans
Base Command
fireeye-dod-get-reports
Input
| Argument Name | Description | Required |
|---|---|---|
| report_ids | A comma separated list of one or more report IDs to fetch. | Required |
| extended_report | If True, additional information will be returned | Optional |
| get_screenshot | Whether or not to get screenshot artifacts from the report | Optional |
| get_artifact | Which report artifacts to retrieve (if any) | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| FireEyeDoD.Scan.report_id | String | The ID of the report |
| FireEyeDoD.Scan.overall_status | String | The overall status of all of the engines |
| FireEyeDoD.Scan.is_malicious | Number | True/False if the file is malicious |
| FireEyeDoD.Scan.started_at | Date | The UTC time the scan was started |
| FireEyeDoD.Scan.completed_at | Date | The UTC time the scan was completed |
| FireEyeDoD.Scan.duration | Number | How long, in seconds, the scan took to complete. |
| FireEyeDoD.Scan.file_name | String | The name of the submitted file |
| FireEyeDoD.Scan.file_size | Number | The size of the file in bytes |
| FireEyeDoD.Scan.file_extension | String | The extension of the submitted file. If a URL was submitted, this will be empty. |
| FireEyeDoD.Scan.md5 | String | The MD5 hash of the submitted file |
| FireEyeDoD.Scan.sha256 | String | The sha256 hash of the submitted file |
| FireEyeDoD.Scan.signature_name | String | List of signatures extracted by all engines |
Command Example
!fireeye-dod-get-reports report_ids=82e71bec-04c7-4f04-945b-4d344a758abe
Context Example
{
"FireEyeDoD": {
"Scan": {
"completed_at": "2020-11-10 14:28:18",
"duration": 0,
"file_extension": "urlscan",
"file_name": "test-infection.exe",
"file_size": 28672,
"is_malicious": true,
"magic": null,
"md5": "NA",
"name": "test-infection.exe",
"overall_status": "DONE",
"report_id": "82e71bec-04c7-4f04-945b-4d344a758abe",
"sha1": "NA",
"sha256": "NA",
"signature_name": [
"Phish.LIVE.DTI.URL",
"Malicious.LIVE.DTI.URL",
"fe_ml_heuristic",
"FireEye.Malware.exe",
"FETestEvent"
],
"size": 28672,
"started_at": "2020-11-10 14:28:18",
"type": "urlscan",
"urls": [
"http://fedeploycheck.fireeye.com/appliance-test/block.html",
"http://165.227.14.8/?NDU2MDgz&yOyeu&YPocHQsbD=disagree&lAjd=callous&mvUq=disagree&eSCpt=disagree&mnnYBwlX=abettor&MZMJ=everyone&ipEMqw=professional&xRefGF=callous&tzsdfga4=dJORROwbnhRaGKA1hlIhYVV0W8a2ojkbXzhCf1JaG9RGIZ1hD-sGcELgL6G2xyPNRcw&cvggd54=wnfQMvXcJBXQFYbIKuXDSKxDKU7WFEaVw4-RhMG3YpjNfynz1-zURnL6tASVVFuRrbM&hMdqbI=electrical&qgZufk=disagree&egHdAM=abettor&BUfBH=professional&RGVeFwBNTM2MzY2",
"http://br430.teste.website/~idbrok92/idb/UI/Login/",
"http://www.dulys.co.zw/",
"http://fedeploycheck.fireeye.com/appliance-test/test-infection.exe",
"http://fedeploycheck.fireeye.com/appliance-test/test-infection.pdf",
"http://fedeploycheck.fireeye.com/appliance-test/alert.html",
"https://tinyurl.com/y2qezvol",
"https://fedeploycheck.fireeye.com/appliance-test/alert.html"
],
"verdict": "MALICIOUS"
}
}
}
Human Readable Output
Scan status
completed_at duration file_extension file_name file_size is_malicious magic md5 name overall_status report_id sha1 sha256 signature_name size started_at type urls verdict 2020-11-10 14:28:18 0 urlscan test-infection.exe 28672 true NA test-infection.exe DONE 82e71bec-04c7-4f04-945b-4d344a758abe NA NA Phish.LIVE.DTI.URL,
Malicious.LIVE.DTI.URL,
fe_ml_heuristic,
FireEye.Malware.exe,
FETestEvent28672 2020-11-10 14:28:18 urlscan http://fedeploycheck.fireeye.com/appliance-test/block.html,
http://165.227.14.8/?NDU2MDgz&yOyeu&YPocHQsbD=disagree&lAjd=callous&mvUq=disagree&eSCpt=disagree&mnnYBwlX=abettor&MZMJ=everyone&ipEMqw=professional&xRefGF=callous&tzsdfga4=dJORROwbnhRaGKA1hlIhYVV0W8a2ojkbXzhCf1JaG9RGIZ1hD-sGcELgL6G2xyPNRcw&cvggd54=wnfQMvXcJBXQFYbIKuXDSKxDKU7WFEaVw4-RhMG3YpjNfynz1-zURnL6tASVVFuRrbM&hMdqbI=electrical&qgZufk=disagree&egHdAM=abettor&BUfBH=professional&RGVeFwBNTM2MzY2,
http://br430.teste.website/~idbrok92/idb/UI/Login/,
http://www.dulys.co.zw/,
http://fedeploycheck.fireeye.com/appliance-test/test-infection.exe,
http://fedeploycheck.fireeye.com/appliance-test/test-infection.pdf,
http://fedeploycheck.fireeye.com/appliance-test/alert.html,
https://tinyurl.com/y2qezvol,
https://fedeploycheck.fireeye.com/appliance-test/alert.htmlMALICIOUS
fireeye-dod-get-report-url
Generates a pre-signed URL for a report
Base Command
fireeye-dod-get-report-url
Input
| Argument Name | Description | Required |
|---|---|---|
| report_id | The ID of the report to fetch | Required |
| expiration | Expiration (in hours) for browser viewable report pre-signed URL link. Default value is 72 hours. Minimum is 1 hour, and maximum is 8760 hours (365 days). | Optional |
Context Output
There is no context output for this command.
Command Example
!fireeye-dod-get-report-url report_id=82e71bec-04c7-4f04-945b-4d344a758abe
Context Example
{}
Human Readable Output
Report 82e71bec-04c7-4f04-945b-4d344a758abe is available here
Configuration parameters
url— DoD hostname (required)apikey— API Key (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (5)
-
fireeye-dod-get-hashesQueries FireEye Detection on Demand reports for the provided md5 hashes.
-
fireeye-dod-get-report-urlGenerates a pre-signed URL for a report.
-
fireeye-dod-get-reportsRetrieves one or more reports of file scans.
-
fireeye-dod-submit-fileSubmits file to FireEye Detection on Demand for analysis.
-
fireeye-dod-submit-urlsSubmits URLs to FireEye Detection on Demand for analysis.
from typing import Any import dateparser import demistomock as demisto # noqa: F401 import urllib3 from CommonServerPython import * # noqa: F401 # Disable insecure warnings urllib3.disable_warnings() """ CONSTANTS """ DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ" """ CLIENT CLASS """ class Client(BaseClient): """Client class to interact with the service API This Client implements API calls, and does not contain any Demisto logic. Should only do requests and return data. It inherits from BaseClient defined in CommonServer Python. Most calls use _http_request() that handles proxy, SSL verification, etc. For this HelloWorld implementation, no special attributes defined """ def get_file_reputation(self, file: str) -> dict[str, Any]: return self._http_request(method="GET", url_suffix=f"/hashes/{file}") def get_health(self) -> dict[str, Any]: return self._http_request(method="GET", url_suffix="/health") def submit_file(self, files: dict[str, Any], data: dict[str, Any]) -> dict[str, Any]: return self._http_request(method="POST", url_suffix="/files", files=files, data=data) def submit_urls(self, data: dict[str, Any]) -> dict[str, Any]: return self._http_request(method="POST", url_suffix="/urls", files=data, data=None) def get_report_url(self, report_id: str, expiration: int) -> dict[str, Any]: return self._http_request(method="GET", url_suffix=f"/presigned-url/{report_id}", params={"expiry": expiration}) def report_status(self, report_id: str, extended: str) -> dict[str, Any]: return self._http_request(method="GET", url_suffix=f"/reports/{report_id}", params={"extended": extended}) def report_artifact(self, report_id: str, artifact_type: str) -> dict[str, Any]: return self._http_request( method="GET", url_suffix=f"/artifacts/{report_id}", params={ "type": artifact_type, }, resp_type="content", ) """ HELPER FUNCTIONS """ def convert_to_demisto_severity(severity: str) -> int: # In this case the mapping is straightforward, but more complex mappings # might be required in your integration, so a dedicated function is # recommended. This mapping should also be documented. return { "Low": 1, # low severity "Medium": 2, # medium severity "High": 3, # high severity "Critical": 4, # critical severity }[severity] def arg_to_int(arg: Any, arg_name: str, required: bool = False) -> int | None: if arg is None: if required is True: raise ValueError(f'Missing "{arg_name}"') return None if isinstance(arg, str): if arg.isdigit(): return int(arg) raise ValueError(f'Invalid number: "{arg_name}"="{arg}"') if isinstance(arg, int): return arg raise ValueError(f'Invalid number: "{arg_name}"') def arg_to_timestamp(arg: Any, arg_name: str, required: bool = False) -> int | None: if arg is None: if required is True: raise ValueError(f'Missing "{arg_name}"') return None if isinstance(arg, str) and arg.isdigit(): # timestamp is a str containing digits - we just convert it to int return int(arg) if isinstance(arg, str): # we use dateparser to handle strings either in ISO8601 format, or # relative time stamps. # For example: format 2019-10-23T00:00:00 or "3 days", etc date = dateparser.parse(arg, settings={"TIMEZONE": "UTC"}) if date is None: # if d is None it means dateparser failed to parse it raise ValueError(f"Invalid date: {arg_name}") return int(date.timestamp()) if isinstance(arg, int | float): # Convert to int if the input is a float return int(arg) raise ValueError(f'Invalid date: "{arg_name}"') """ COMMAND FUNCTIONS """ def test_module(client: Client) -> str: # INTEGRATION DEVELOPER TIP # Client class should raise the exceptions, but if the test fails # the exception text is printed to the Cortex XSOAR UI. # If you have some specific errors you want to capture (i.e. auth failure) # you should catch the exception here and return a string with a more # readable output (for example return 'Authentication Error, API Key # invalid'). # Cortex XSOAR will print everything you return different than 'ok' as # an error try: # client.get_health() except DemistoException as e: if "Forbidden" in str(e): return "Authorization Error: make sure API Key is correctly set" else: raise e return "ok" def get_hashes_command(client: Client, args: dict[str, Any]) -> tuple[str, dict, Any]: hashes = argToList(args.get("md5_hashes")) if len(hashes) == 0: raise ValueError("hash(es) not specified") for hash in hashes: if md5Regex.match(hash): continue raise Exception("Invalid hash. Only MD5 is supported.") dbot_score_list: list[dict[str, Any]] = [] file_standard_list: list[dict[str, Any]] = [] file_data_list: list[dict[str, Any]] = [] for hash in hashes: file_data = client.get_file_reputation(hash) file_data["MD5"] = file_data["md5"] del file_data["md5"] # demisto.results(file_data) engines = file_data.get("engine_results", {}) for key in engines: if engines[key].get("sha256"): file_data["SHA256"] = engines[key].get("sha256") del engines[key]["sha256"] # If the outer `is_malicious` is set to True, assume the score should be bad # Otherwise, default to unknown unless at least one engine has returned a verdict besides `not_found` if file_data["is_malicious"]: score = 3 # bad else: score = 0 # unknown for key in engines: verdict = engines[key].get("verdict", "not_found") if verdict != "not_found" and verdict != "malicious": score = 1 # good break dbot_score = {"Indicator": hash, "Vendor": "FireEye DoD", "Type": "file", "Score": score} file_standard_context = { "MD5": hash, } if score == 3: # if score is bad must add DBotScore Vendor and Description file_standard_context["Malicious"] = {"Vendor": "FireEye DoD"} filedata = {} filedata["FireEyeDoD"] = file_data filedata["MD5"] = file_data["MD5"] del filedata["FireEyeDoD"]["MD5"] if file_data.get("SHA256"): dbot_score_sha256 = {"Indicator": file_data.get("SHA256"), "Vendor": "FireEye DoD", "Type": "file", "Score": score} dbot_score_list.append(dbot_score_sha256) filedata["SHA256"] = file_data["SHA256"] file_standard_context["SHA256"] = file_data["SHA256"] del filedata["FireEyeDoD"]["SHA256"] file_standard_list.append(file_standard_context) dbot_score_list.append(dbot_score) file_data_list.append(filedata) outputs = { "DBotScore(val.Vendor == obj.Vendor && val.Indicator == obj.Indicator)": dbot_score_list, outputPaths["file"]: file_standard_list, "File(val.MD5 == obj.MD5 || val.SHA256 == obj.SHA256)": file_data_list, } readable_output = tableToMarkdown("FireEye DoD Results", file_standard_list, headers=["MD5", "SHA256", "Malicious"]) return (readable_output, outputs, file_data_list) def generate_report_url(client: Client, args: dict[str, Any]) -> tuple[str, dict, dict]: report_id = str(args.get("report_id")) expiration = arg_to_int(arg=args.get("expiration"), arg_name="expiration", required=True) if expiration: if expiration < 1 or expiration > 8760: raise ValueError("Expiration must be between 1 and 8760 hours.") else: raise ValueError("Expiration not specified or not a number.") report = client.get_report_url(report_id=report_id, expiration=expiration) presigned_report_url = report.get("presigned_report_url") readable_output = f"Report {report_id} is available [here]({presigned_report_url})" return (readable_output, {}, report) def submit_file_command(client: Client, args: dict[str, Any]) -> tuple[str, dict, dict]: entry_id = demisto.args().get("entryID") file_entry = demisto.getFilePath(entry_id) # .get('path') file_name = file_entry["name"] file_path = file_entry["path"] files = {"file": (file_name, open(file_path, "rb"))} # Optional parameters to send along with the file optional_params = ["password", "param", "screenshot", "video", "fileExtraction", "memoryDump", "pcap"] data = {} for param in optional_params: value = demisto.args().get(param) if value: data[param] = value scan = client.submit_file(files=files, data=data) scan["filename"] = file_name del scan["status"] scan["overall_status"] = "RUNNING" report_id = scan.get("report_id") readable_output = ( f"Started analysis of {file_name} with FireEye Detection on Demand." f"Results will be published to report id: {report_id}" ) outputs = {"FireEyeDoD.Scan(val.report_id == obj.report_id)": scan} return (readable_output, outputs, scan) def submit_urls_command(client: Client, args: dict[str, Any]) -> tuple[str, dict, dict]: urls = argToList(args.get("urls")) if len(urls) == 0: raise ValueError("hash(es) not specified") # Format the URLs into a string list, which the API understands formatted_urls = "[" + ",".join([url.replace(url, f'"{url}"') for url in urls]) + "]" data = {"urls": formatted_urls} scan = client.submit_urls(data=data) del scan["status"] scan["overall_status"] = "RUNNING" report_id = scan.get("report_id") readable_output = ( f"Started analysis of {urls} with FireEye Detection on Demand.Results will be published to report id: {report_id}" ) outputs = {"FireEyeDoD.Scan(val.report_id == obj.report_id)": scan} return (readable_output, outputs, scan) def get_reports_command(client: Client, args: dict[str, Any]) -> tuple[str, dict, Any]: report_id_list = argToList(args.get("report_ids", [])) extended = args.get("extended_report", "False") screenshot = args.get("get_screenshot", "false") artifact = args.get("get_artifact", "") if len(report_id_list) == 0: raise ValueError("report_id(s) not specified") report_list: list[dict[str, Any]] = [] for report_id in report_id_list: report = client.report_status(report_id=report_id, extended=extended) if screenshot.lower() == "true": screenshot = client.report_artifact(report_id=report_id, artifact_type="screenshot") stored_img = fileResult("screenshot.gif", screenshot) demisto.results( { "Type": entryTypes["image"], "ContentsFormat": formats["text"], "File": stored_img["File"], "FileID": stored_img["FileID"], "Contents": "", } ) if artifact != "": artifacts = client.report_artifact(report_id=report_id, artifact_type=artifact) stored_artifacts = fileResult("artifacts.zip", artifacts) demisto.results( { "Type": entryTypes["file"], "ContentsFormat": formats["text"], "File": stored_artifacts["File"], "FileID": stored_artifacts["FileID"], "Contents": "", } ) report_list.append(report) readable_output = tableToMarkdown("Scan status", report_list) outputs = {"FireEyeDoD.Scan(val.report_id == obj.report_id)": report_list} return (readable_output, outputs, report_list) """ MAIN FUNCTION """ def main() -> None: """main function, parses params and runs command functions :return: :rtype: """ api_key = demisto.params().get("apikey") # get the service API url base_url = demisto.params()["url"] # if your Client class inherits from BaseClient, SSL verification is # handled out of the box by it, just pass ``verify_certificate`` to # the Client constructor verify_certificate = not demisto.params().get("insecure", False) # if your Client class inherits from BaseClient, system proxy is handled # out of the box by it, just pass ``proxy`` to the Client constructor proxy = demisto.params().get("proxy", False) # INTEGRATION DEVELOPER TIP # You can use functions such as ``demisto.debug()``, ``demisto.info()``, # etc. to print information in the XSOAR server log. You can set the log # level on the server configuration # See: https://xsoar.pan.dev/docs/integrations/code-conventions#logging demisto.debug(f"Command being called is {demisto.command()}") try: headers = {"feye-auth-key": f"{api_key}"} client = Client(base_url=base_url, verify=verify_certificate, headers=headers, proxy=proxy) if demisto.command() == "test-module": # This is the call made when pressing the integration Test button. result = test_module(client) demisto.results(result) elif demisto.command() == "fireeye-dod-get-hashes": return_outputs(*get_hashes_command(client, demisto.args())) elif demisto.command() == "fireeye-dod-get-reports": return_outputs(*get_reports_command(client, demisto.args())) elif demisto.command() == "fireeye-dod-submit-file": return_outputs(*submit_file_command(client, demisto.args())) elif demisto.command() == "fireeye-dod-submit-urls": return_outputs(*submit_urls_command(client, demisto.args())) elif demisto.command() == "fireeye-dod-get-report-url": return_outputs(*generate_report_url(client, demisto.args())) # Log exceptions and return errors except Exception as e: raise e # demisto.error(traceback.format_exc()) # print the traceback # return_error(f'Failed to execute {demisto.command()} command.\nError:\n{str(e)}') """ ENTRY POINT """ if __name__ in ("__main__", "__builtin__", "builtins"): main()