Lastline v2
Use the Lastline v2 integration to provide threat analysts and incident response teams with the advanced malware isolation and inspection environment needed to safely execute advanced malware samples, and understand their behavior.
Data Enrichment & Threat Intelligence · Lastline
Details
| ID | Lastline v2 |
|---|---|
| Provider | Broadcom |
| Category | Data Enrichment & Threat Intelligence |
| From Version | 5.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM EDR Cortex Cloud Cloud Runtime Security |
README
Use the Lastline v2 integration to provide threat analysts and incident response teams with the advanced malware isolation and inspection environment needed to safely execute advanced malware samples, and understand their behavior.
Configure Lastline v2 on Cortex XSOAR
- Navigate to Settings > Integrations > Servers & Services.
- Search for Lastline v2.
- Click Add instance to create and configure a new integration instance.
Note that you can configure your instance using an API Key and API Token OR using an Email Address and Password.- Name: a textual name for the integration instance.
- Server URL (e.g. https://analysis.lastline.com)
- API Key for accessing Lastline APIs
- API Token for accessing Lastline APIs
- Email Address for accessing Lastline APIs using account based authentication
- Password for accessing Lastline APIs using account based authentication
- Use system proxy settings
- Trust any certificate (not secure)
- Threshold
- Click Test to validate the URLs, token, and connection.
Check the reputation of a file
Checks the file reputation of the specified file hashes. Supports MD5, SHA1, and SHA256 hashes.
Base Command
file
Input
| Argument Name | Description | Required |
|---|---|---|
| file | A comma-separated list of file hashes to check. Supports MD5, SHA1, and SHA256 hashes. | Required |
| threshold | The score threshold that determines if the file is malicious. The default value is “70”. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| File.MD5 | string | The MD5 hash of the file. |
| File.SHA1 | string | The SHA1 hash of the file. |
| File.SHA256 | string | The SHA256 hash of the file. |
| File.Type | string | The file type. |
| File.Malicious.Vendor | string | The vendor who determined that the file is malicious. |
| File.Malicious.Description | string | The reason that the vendor determined that the file is malicious. |
| File.Malicious.Score | number | The score that the vendor gave the malicious file. |
| DBotScore.Indicator | string | The indicator that was tested. |
| DBotScore.Type | string | The type of indicator. |
| DBotScore.Vendor | string | The vendor used to calculate the score. |
| DBotScore.Score | number | The actual score. |
| Lastline.Submission.Status | string | The status of the submission. |
| Lastline.Submission.UUID | string | The task UUID. |
| Lastline.Submission.SubmissionTime | string | The timestamp in Lastline. |
| Lastline.Submission.YaraSignatures.name | string | Yara signature’s name. |
| Lastline.Submission.YaraSignatures.score | number | The score according to the Yara signatures (0 to 100). |
| Lastline.Submission.YaraSignatures.internal | boolean | Whether the signature is for internal use only. |
| Lastline.Submission.DNSqueries | string | A list of DNS queries executed by the analysis subject. |
| Lastline.Submission.NetworkConnections | string | A list of network connections executed by the analysis subject. |
| Lastline.Submission.DownloadedFiles | string | A list of files that were downloaded using the Microsoft Windows file-download API functions. Each element is a tuple of file-origin URL and a File element. |
| Lastline.Submission.Process | Unknown | Information on the Windows process. |
| Lastline.Submission.Process.arguments | string | The argument of the process. |
| Lastline.Submission.Process.executable | Unknown | The executable of the process. |
| Lastline.Submission.Process.executable.abs_path | string | The absolute path of the executable of the process. |
| Lastline.Submission.Process.executable.filename | string | The filename of the executable. |
| Lastline.Submission.Process.executable.yara_signature_hits | string | The Yara signature of the executable of the process. |
| Lastline.Submission.Process.executable.ext_info | unknown | The executable information of the process. |
| Lastline.Submission.Process.process_id | string | The process ID. |
Command Example
!file file=03bc132ee4a10f6d656fc21315fc7a65797be69a
Context Example
{
"DBotScore": [
{
"Vendor": "Lastline",
"Indicator": "441666007e579b040967e72c13e5133b",
"Score": 1,
"Type": "File"
}
],
"File": [
{
"Type": "application/zip",
"SHA1": "03bc132ee4a10f6d656fc21315fc7a65797be69a",
"SHA256": "fd977f34a9514ece503fa3ff3976ed3f305a101b3c5ff31a1293a9d0b607dfc1",
"MD5": "441666007e579b040967e72c13e5133b"
}
],
"Lastline": [
{
"Submission": {
"Status": "Completed",
"SubmissionTime": "2020-02-25 06:58:19",
"UUID": "2b9d578d02540010179339d362664f9b"
}
}
]
}
Human Readable Output
Lastline analysis for file: 441666007e579b040967e72c13e5133b
Score: 0
Task UUID: 2b9d578d02540010179339d362664f9b
Submission Time: 2020-02-25 06:58:19
| MD5 | SHA1 | SHA256 | Type |
|---|---|---|---|
| 441666007e579b040967e72c13e5133b | 03bc132ee4a10f6d656fc21315fc7a65797be69a | fd977f34a9514ece503fa3ff3976ed3f305a101b3c5ff31a1293a9d0b607dfc1 | application/zip |
Submit a URL for analysis
Submits a URL 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
lastline-upload-url
Input
| Argument Name | Description | Required |
|---|---|---|
| url | The URL to analyze. For example: https://www.demisto.com. | Required |
| threshold | The score threshold that determines if the file is malicious. The default value is “70”. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| URL.Data | string | A list of malicious URLs identified by the Lastline analysis. |
| URL.Malicious.Vendor | string | The vendor who determined that a URL is malicious. |
| URL.Malicious.Description | string | The reason that the vendor made the decision. |
| URL.Malicious.Score | number | The score that the malicious URL received from the vendor. |
| 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. |
| Lastline.Submission.Status | string | The status of the submission. |
| Lastline.Submission.UUID | string | The task UUID. |
| Lastline.Submission.SubmissionTime | string | The submission timestamp in Lastline. |
| Lastline.Submission.YaraSignatures.name | string | Yara signatures name. |
| Lastline.Submission.YaraSignatures.score | number | The score according to the Yara signatures (0 to 100). |
| Lastline.Submission.YaraSignatures.internal | boolean | Whether the signature is for internal usage only. |
| Lastline.Submission.DNSqueries | string | A list of DNS queries executed by the analysis subject. |
| Lastline.Submission.NetworkConnections | string | A list of network connections executed by the analysis subject. |
| Lastline.Submission.DownloadedFiles | string | A list of files that were downloaded using the Microsoft Windows file-download API functions. Each element is a tuple of file-origin URL and a File element. |
| Lastline.Submission.Process | Unknown | Information on the Windows process. |
| Lastline.Submission.Process.arguments | string | The argument of the process. |
| Lastline.Submission.Process.executable | Unknown | The executable of the process. |
| Lastline.Submission.Process.executable.abs_path | string | The absolute path of the executable of the process. |
| Lastline.Submission.Process.executable.yara_signature_hits | string | The Yara signature of the executable of the process. |
| Lastline.Submission.Process.executable.ext_info | unknown | The executable information of the process. |
| Lastline.Submission.Process.process_id | string | The process ID. |
Command Example
!lastline-upload-url url="https://www.demisto.com" threshold=80
Context Example
{
"URL": {
"Data": "https://www.demisto.com"
},
"DBotScore": {
"Vendor": "Lastline",
"Indicator": "https://www.demisto.com",
"Score": 1,
"Type": "URL"
},
"Lastline": {
"Submission": {
"Status": "Completed",
"SubmissionTime": "2020-02-24 07:05:33",
"UUID": "c62b15a9e3dc00101e9557a0b6a17d3f"
}
}
}
Human Readable Output
Lastline analysis for url: https://www.demisto.com
Score: 0
Task UUID: c62b15a9e3dc00101e9557a0b6a17d3f
Submission Time: 2020-02-24 07:05:33
| Data |
|---|
| https://www.demisto.com |
Upload a file for analysis
Submits a file for analysis.\
Note: Due to a limitation in Lastline’s API, EML files are not supported.
Base Command
lastline-upload-file
Input
| Argument Name | Description | Required |
|---|---|---|
| EntryID | The entry ID of the file to upload. | Required |
| threshold | The score threshold that determines if the file is malicious. The default value is “70”. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| File.MD5 | string | The MD5 hash of the file. |
| File.SHA1 | string | The SHA1 hash of the file. |
| File.SHA256 | string | The SHA256 hash of the file. |
| File.Type | string | The file type. |
| File.Malicious.Vendor | string | The vendor who determined that the file is malicious. |
| File.Malicious.Description | string | The reason that the vendor determined that the file is malicious. |
| File.Malicious.Score | number | The score the malicious file received from the vendor. |
| 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. |
| Lastline.Submission.Status | string | The status of the submission. |
| Lastline.Submission.UUID | string | The task UUID. |
| Lastline.Submission.SubmissionTime | string | The submission timestamp in Lastline. |
| Lastline.Submission.YaraSignatures.name | string | Yara signatures name. |
| Lastline.Submission.YaraSignatures.score | number | The score according to the Yara signatures (0 to 100). |
| Lastline.Submission.YaraSignatures.internal | boolean | Whether the signature is for internal use only. |
| Lastline.Submission.DNSqueries | string | A list of DNS queries executed by the analysis subject. |
| Lastline.Submission.NetworkConnections | string | A list of network connections executed by the analysis subject. |
| Lastline.Submission.DownloadedFiles | string | A list of files that were downloaded using the Microsoft Windows file-download API functions. Each element is a tuple of file-origin URL and a File element. |
| Lastline.Submission.Process | Unknown | Information on the Windows process. |
| Lastline.Submission.Process.arguments | string | The argument of the process. |
| Lastline.Submission.Process.executable | Unknown | The executable of the process. |
| Lastline.Submission.Process.executable.abs_path | string | The absolute path of the executable of the process. |
| Lastline.Submission.Process.executable.filename | string | The filename of the executable. |
| Lastline.Submission.Process.executable.yara_signature_hits | string | The Yara signature of the executable of the process. |
| Lastline.Submission.Process.executable.ext_info | unknown | The executable information of the process. |
| Lastline.Submission.Process.process_id | string | The process ID. |
Command Example
!lastline-upload-file EntryID=152@374 threshold=40
Context Example
{
"DBotScore": {
"Vendor": "Lastline",
"Indicator": "441666007e579b040967e72c13e5133b",
"Score": 1,
"Type": "File"
},
"File": {
"Type": "application/zip",
"SHA1": "03bc132ee4a10f6d656fc21315fc7a65797be69a",
"SHA256": "fd977f34a9514ece503fa3ff3976ed3f305a101b3c5ff31a1293a9d0b607dfc1",
"MD5": "441666007e579b040967e72c13e5133b"
},
"Lastline": {
"Submission": {
"Status": "Completed",
"SubmissionTime": "2020-02-25 06:58:19",
"UUID": "2b9d578d02540010179339d362664f9b"
}
}
}
Human Readable Output
Lastline analysis for file: 441666007e579b040967e72c13e5133b
Score: 0
Task UUID: 2b9d578d02540010179339d362664f9b
Submission Time: 2020-02-25 06:58:19
| MD5 | SHA1 | SHA256 | Type |
|---|---|---|---|
| 441666007e579b040967e72c13e5133b | 03bc132ee4a10f6d656fc21315fc7a65797be69a | fd977f34a9514ece503fa3ff3976ed3f305a101b3c5ff31a1293a9d0b607dfc1 | application/zip |
Get an analysis report
Returns an analysis report.
Base Command
lastline-get-report
Input
| Argument Name | Description | Required |
|---|---|---|
| uuid | The task UUID of the submitted Lastline analysis. | Required |
| threshold | The score threshold that determines if the file is malicious. The default value is “70”. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| URL.Data | string | A list of malicious URLs identified by the Lastline analysis. |
| URL.Malicious.Vendor | string | The vendor that determined a URL is malicious. |
| URL.Malicious.Description | string | The reason that the vendor determined that the URL is malicious. |
| URL.Malicious.Score | number | The score that the malicious URL received from the vendor. |
| File.MD5 | string | The MD5 hash of the file. |
| File.SHA1 | string | The SHA1 hash of the file. |
| File.SHA256 | string | The SHA256 hash of the file. |
| File.Type | string | The file type. |
| File.Malicious.Vendor | string | The vendor that determined a file is malicious. |
| File.Malicious.Description | string | The reason that the vendor determined that the file is malicious. |
| File.Malicious.Score | number | The score that the malicious file received from the vendor. |
| DBotScore.Indicator | string | The indicator that was tested. |
| DBotScore.Type | string | The type of indicator. |
| DBotScore.Vendor | string | The vendor used to calculate the score. |
| DBotScore.Score | number | The actual score. |
| Lastline.Submission.Status | string | Status of the submission. |
| Lastline.Submission.UUID | string | The task UUID. |
| Lastline.Submission.SubmissionTime | string | The timestamp in Lastline. |
| Lastline.Submission.YaraSignatures.name | string | Yara signatures name. |
| Lastline.Submission.YaraSignatures.score | number | The score according to the Yara signatures (0 to 100). |
| Lastline.Submission.YaraSignatures.internal | boolean | Whether the signature is for internal use only. |
| Lastline.Submission.DNSqueries | string | A list of DNS queries executed by the analysis subject. |
| Lastline.Submission.NetworkConnections | string | A list of network connections executed by the analysis subject. |
| Lastline.Submission.DownloadedFiles | string | A list of files that were downloaded using the Microsoft Windows file-download API functions. Each element is a tuple of file-origin URL and a File element. |
| Lastline.Submission.Process | Unknown | Information on the Windows process. |
| Lastline.Submission.Process.arguments | string | The argument of the process. |
| Lastline.Submission.Process.executable | Unknown | The executable of the process. |
| Lastline.Submission.Process.executable.abs_path | string | The absolute path of the executable of the process. |
| Lastline.Submission.Process.executable.filename | string | The filename of the executable. |
| Lastline.Submission.Process.executable.yara_signature_hits | string | The Yara signature of the executable of the process. |
| Lastline.Submission.Process.executable.ext_info | unknown | The executable information of the process. |
| Lastline.Submission.Process.process_id | string | The process ID. |
Command Example
!lastline-get-report uuid=b32ed21999be00100eca07d07cb7bf38 threshold=70
Context Example
{
"URL": {
"Data": "https://google.com"
},
"DBotScore": {
"Vendor": "Lastline",
"Indicator": "https://google.com",
"Score": 1,
"Type": "URL"
},
"Lastline": {
"Submission": {
"Status": "Completed",
"SubmissionTime": "2019-12-31 02:40:44",
"UUID": "b32ed21999be00100eca07d07cb7bf38"
}
}
}
Human Readable Output
Lastline analysis for url: https://google.com
Score: 0
Task UUID: b32ed21999be00100eca07d07cb7bf38
Submission Time: 2019-12-31 02:40:44
| Data |
|---|
| https://google.com |
Get a list of tasks
Returns a list of tasks.
Base Command
lastline-get-task-list
Input
| Argument Name | Description | Required |
|---|---|---|
| before | Return tasks before this date (in UTC format %Y-%m-%dT%H:%M:%S). For example, 2018-07-08T12:00:00. | Optional |
| after | Return tasks after this date (in UTC format %Y-%m-%dT%H:%M:%S). For example, 2018-07-10T12:00:00. | Required |
Context Output
There is no context output for this command.
Command Example
!lastline-get-task-list after=2020-01-01T00:00:00 before=2020-01-02T00:00:00
Human Readable Output
tasks
| UUID | Time | Status |
|---|---|---|
| b32ed21999be00100eca07d07cb7bf38 | 2019-12-31T02:40:44 | Completed |
| 6493c3fa395000101e8ee41181d70b02 | 2020-01-01T15:26:35 | Completed |
Get the status of a submission
Checks the status of a submission.
Base Command
lastline-check-status
Input
| Argument Name | Description | Required |
|---|---|---|
| uuid | The task UUID of the submitted Lastline analysis. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| URL.Data | string | A list of malicious URLs identified by the lastline analysis. |
| URL.Malicious.Vendor | string | The vendor that determined that a URL is malicious. |
| URL.Malicious.Description | string | The reason that the vendor determined that the URL is malicious. |
| URL.Malicious.Score | number | The score that the malicious URL received from the vendor. |
| File.MD5 | string | The MD5 hash of the file. |
| File.SHA1 | string | The SHA1 hash of the file. |
| File.SHA256 | string | The SHA256 hash of the file. |
| File.Type | string | The file type. |
| File.Malicious.Vendor | string | The vendor that determined that the file is malicious. |
| File.Malicious.Description | string | The reason that the vendor determined that the file is malicious. |
| File.Malicious.Score | number | The score that the malicious file received from the vendor. |
| DBotScore.Indicator | string | The indicator that was tested. |
| DBotScore.Type | string | The type of indicator. |
| DBotScore.Vendor | string | The vendor used to calculate the score. |
| DBotScore.Score | number | The actual score. |
| Lastline.Submission.Status | string | The status of the submission. |
| Lastline.Submission.UUID | string | The task UUID. |
| Lastline.Submission.SubmissionTime | string | The timestamp in Lastline. |
| Lastline.Submission.YaraSignatures.name | string | Yara signatures name. |
| Lastline.Submission.YaraSignatures.score | number | The score according to the Yara signatures (0 to 100). |
| Lastline.Submission.YaraSignatures.internal | boolean | Whether the signature is for internal use only. |
| Lastline.Submission.DNSqueries | string | List of DNS queries executed by the analysis subject. |
| Lastline.Submission.NetworkConnections | string | A list of network connections executed by the analysis subject. |
| Lastline.Submission.DownloadedFiles | string | A list of files that were downloaded using the Microsoft Windows file-download API functions. Each element is a tuple of file-origin URL and a File element. |
| Lastline.Submission.Process | Unknown | Information on athe Windows process. |
| Lastline.Submission.Process.arguments | string | The argument of the process. |
| Lastline.Submission.Process.executable | Unknown | The executable of the process. |
| Lastline.Submission.Process.executable.abs_path | string | The absolute path of the executable of the process. |
| Lastline.Submission.Process.executable.filename | string | The filename of the executable. |
| Lastline.Submission.Process.executable.yara_signature_hits | string | The Yara signature of the executable of the process. |
| Lastline.Submission.Process.executable.ext_info | unknown | The executable information of the process. |
| Lastline.Submission.Process.process_id | string | The process ID. |
Command Example
!lastline-check-status uuid=b32ed21999be00100eca07d07cb7bf38
Context Example
{
"URL": {
"Data": "https://google.com"
},
"DBotScore": {
"Vendor": "Lastline",
"Indicator": "https://google.com",
"Score": 1,
"Type": "URL"
},
"Lastline": {
"Submission": {
"Status": "Completed",
"SubmissionTime": "2019-12-31 02:40:44",
"UUID": "b32ed21999be00100eca07d07cb7bf38"
}
}
}
Human Readable Output
Lastline analysis for url: https://google.com
Score: 0
Task UUID: b32ed21999be00100eca07d07cb7bf38
Submission Time: 2019-12-31 02:40:44
| Data |
|---|
| https://google.com |
Configuration parameters
url— Server URL (e.g. https://analysis.lastline.com) (required)creds_key_and_token— API Key for accessing Lastline APIscredentials— Email addressproxy— Use system proxy settingsinsecure— Trust any certificate (not secure)threshold— Thresholdapi_key— API Key for accessing Lastline APIsapi_token— API Token for accessing Lastline APIsintegrationReliability— Source ReliabilityfeedExpirationPolicy—feedExpirationInterval—
Commands (6)
-
fileChecks the file reputation of the specified file hashes. Supports MD5, SHA1, and SHA256 hashes.
-
lastline-check-statusChecks the status of a submission.
-
lastline-get-reportReturns an analysis report.
-
lastline-get-task-listReturns a list of tasks.
-
lastline-upload-fileSubmits a file for analysis.
-
lastline-upload-urlSubmits a URL for analysis.
import hashlib import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 from urllib3 import disable_warnings from CommonServerUserPython import * INTEGRATION_COMMAND_NAME = "lastline" INTEGRATION_NAME = "Lastline v2" SUFFIX_TRANSFORMER = { "/analysis/submit/file": {"url": "papi/analysis/submit_file", "method": "POST"}, "/analysis/get": {"url": "papi/analysis/get_result", "method": "GET"}, "/analysis/get_completed": {"url": "papi/analysis/get_history", "method": "GET"}, "/analysis/submit/url": {"url": "papi/analysis/submit_url", "method": "POST"}, } disable_warnings() class Client(BaseClient): MD5_LEN = 32 SHA1_LEN = 40 SHA256_LEN = 64 DEFAULT_THRESHOLD = 70 def __init__(self, base_url: str, api_params: dict, verify=True, proxy=False, credentials: dict = None, threshold=None): self.command_params = api_params self.threshold = threshold if threshold else Client.DEFAULT_THRESHOLD if credentials: self.credentials = {"username": credentials.get("identifier"), "password": credentials.get("password")} else: self.credentials = {} super().__init__(base_url, verify, proxy) def file(self): human_readable = "" context_entry: dict = {"Lastline": [], "File": [], "DBotScore": []} result = [] hash_arg = argToList(self.command_params.get("file")) for arg in hash_arg: hash_type = hash_type_checker(arg) self.command_params[hash_type] = arg temp_result = self.http_request("/analysis/submit/file") temp_human_readable, temp_context_entry = report_generator(temp_result, self.threshold) human_readable += f"\n{temp_human_readable}" context_entry["Lastline"].append(temp_context_entry.get("Lastline")) context_entry["File"].append(temp_context_entry.get("File")) context_entry["DBotScore"].append(temp_context_entry.get("DBotScore")) result.append(temp_result) del self.command_params[hash_type] return human_readable, context_entry, result def check_status(self): result = self.http_request("/analysis/get") human_readable, context_entry = report_generator(result, self.threshold) return human_readable, context_entry, result def get_report(self): result = self.http_request("/analysis/get") if "data" in result and "score" not in result["data"]: uuid = self.command_params.get("uuid") raise DemistoException(f"task {uuid} is not ready") human_readable, context_entry = report_generator(result, self.threshold) return human_readable, context_entry, result def get_task_list(self): for param in ("before", "after"): if param in self.command_params: self.command_params[param] = self.command_params[param].replace("T", " ") result = self.http_request("/analysis/get_completed") if "data" in result: # noqa: RET503 context_entry: list = [] if self.credentials: context_entry = self.get_status_and_time_from_get_history_response(argToList(result["data"])) else: context_entry = self.get_status_and_time(argToList(result["data"].get("tasks"))) for i in range(len(context_entry)): context_entry[i] = {"UUID": context_entry[i][0], "Time": context_entry[i][1], "Status": context_entry[i][2]} human_readable = tableToMarkdown(name="tasks", t=context_entry, headers=["UUID", "Time", "Status"]) return human_readable, {}, result def upload_file(self): entry_id = self.command_params.get("EntryID") self.command_params["push_to_portal"] = True file_params = demisto.getFilePath(entry_id) file_type = os.path.splitext(file_params["name"])[1] self.command_params["md5"] = file_hash(file_params.get("path")) # csv files requires different approach if file_type == ".csv": result = self.handle_csv(file_params) else: result = self.http_request("/analysis/submit/file", file_to_upload=file_params.get("path")) human_readable, context_entry = report_generator(result, self.threshold) return human_readable, context_entry, result def handle_csv(self, file_params): self._session.post(self._base_url + "/papi/login", data=self.credentials, verify=self._verify) with open(file_params["path"], "rb") as file_: result = self._session.post( self._base_url + "/papi/analysis/submit_file", data={"filename": file_params["name"]}, files={"file": (file_params.get("path"), file_.read())}, verify=self._verify, ).json() lastline_exception_handler(result) return result def upload_url(self): result = self.http_request("/analysis/submit/url") human_readable, context_entry = report_generator(result, self.threshold) return human_readable, context_entry, result def test_module_command(self): self.command_params.update({"after": datetime.now().strftime("%Y-%m-%dT%H:%M:%S")}) self.get_task_list() return "ok", {}, {} def get_status_and_time(self, uuids) -> list: task_list: list[list] = [] for uuid in uuids: self.command_params["uuid"] = uuid result = self.http_request("/analysis/get") if "data" in result: task_time = result["data"].get("submission") if "score" in result["data"]: status = "Completed" else: status = "Analyzing" else: task_time = status = "" task_list.append([uuid, task_time.replace(" ", "T"), status]) return task_list def get_status_and_time_from_get_history_response(self, tasks) -> list: task_list: list[list] = [] filtered_tasks: list = [] uuid_set: set = {[x.get("task_uuid") for x in tasks]} for uuid in uuid_set: tasks_same_uuid = [x for x in tasks if x.get("task_uuid") == uuid] latest_date = max(datetime.strptime(x.get("task_start_time"), "%Y-%m-%d %H:%M:%S") for x in tasks_same_uuid) latest_date_str = latest_date.strftime("%Y-%m-%d %H:%M:%S") task = [x for x in tasks_same_uuid if x.get("task_start_time") == latest_date_str][0] filtered_tasks.append(task) for task in filtered_tasks: task_time = task.get("task_start_time") if task.get("status"): status = task.get("status") else: status = "Analyzing" task_list.append([task.get("task_uuid"), task_time.replace(" ", "T"), status]) return task_list def http_request(self, path: str, headers=None, file_to_upload=None) -> dict: if file_to_upload: with open(file_to_upload, "rb") as _file: file_to_upload = {"file": (file_to_upload, _file.read())} result: dict = {} if self.credentials: url_suffix = SUFFIX_TRANSFORMER[path] result = self._http_request( url_suffix["method"], url_suffix["url"], data=self.credentials, params=self.command_params, files=file_to_upload, timeout=2000, ) else: result = self._http_request("POST", path, params=self.command_params, headers=headers, files=file_to_upload) lastline_exception_handler(result) return result def lastline_exception_handler(result: dict): if result.get("success") is not None: if result.get("success") == 0: error_msg = "error " if "error_code" in result: error_msg += "(" + str(result["error_code"]) + ") " if "error" in result: error_msg += result["error"] raise DemistoException(error_msg) else: raise DemistoException("No response") def hash_type_checker(hash_file: str) -> str: hash_types = { str(Client.MD5_LEN): "md5", str(Client.SHA1_LEN): "sha1", str(Client.SHA256_LEN): "sha256", } hash_type = hash_types.get(str(len(hash_file))) if hash_type is not None: return hash_type else: raise DemistoException(f"{INTEGRATION_NAME} File command support md5/ sha1/ sha256 only.") def report_generator(result: dict, threshold=None): context_entry: dict = get_report_context(result, threshold) if "File" in context_entry: key = "File" elif "URL" in context_entry: key = "URL" else: key = "" score = result["data"].get("score") uuid = result["data"].get("task_uuid") submission_time = result["data"].get("submission") if key == "File": indicator = context_entry.get("DBotScore", [{}])[0].get("Indicator", "None") else: indicator = context_entry.get("DBotScore", {}).get("Indicator", "None") if score is not None: meta_data = f"**Score: {score}**\n\nTask UUID: {uuid}\nSubmission Time: {submission_time}" else: meta_data = "**Status: Analyzing**" human_readable = tableToMarkdown( name=f"Lastline analysis for {key.lower()}: {indicator}", metadata=meta_data, t=context_entry.get(key) ) return human_readable, context_entry def get_report_context(result: dict, threshold=None) -> dict: key = "File" context_entry: dict = {} if "data" in result: data: dict = {} dbotscore = {"Vendor": "Lastline", "Score": 0, "Reliability": demisto.params().get("integrationReliability")} dbotscore_list = [] if "score" in result["data"]: status = "Completed" if threshold is None: threshold = Client.DEFAULT_THRESHOLD score = result["data"]["score"] if score > threshold: dbotscore["Score"] = 3 data["Malicious"] = {"Vendor": "Lastline", "Score": score} elif score > 30: dbotscore["Score"] = 2 else: dbotscore["Score"] = 1 else: status = "Analyzing" lastline: dict = { "Submission": { "Status": status, "UUID": result["data"].get("task_uuid"), "SubmissionTime": result["data"].get("submission"), } } if "analysis_subject" in result["data"]: analysis_subject: dict = result["data"]["analysis_subject"] temp_dict: dict = { "YaraSignatures": analysis_subject.get("yara_signatures"), "DNSqueries": analysis_subject.get("dns_queries"), "NetworkConnections": analysis_subject.get("network_connections"), "DownloadedFiles": analysis_subject.get("downloaded_files"), "Process": analysis_subject.get("process"), "DomainDetections": analysis_subject.get("domain_detections"), "IPdetections": analysis_subject.get("ip_detections"), "URLdetections": analysis_subject.get("url_detections"), } temp_dict = {keys: values for keys, values in temp_dict.items() if values} lastline["Submission"].update(temp_dict) if "url" in analysis_subject: key = "URL" dbotscore["Indicator"] = analysis_subject["url"] data["Data"] = analysis_subject.get("url") else: dbotscore["Indicator"] = analysis_subject.get("md5") data["MD5"] = analysis_subject.get("md5") data["SHA1"] = analysis_subject.get("sha1") data["SHA256"] = analysis_subject.get("sha256") data["Type"] = analysis_subject.get("mime_type") dbotscore["Type"] = key if key == "File": dbotscore_copy = dbotscore.copy() dbotscore_copy["Type"] = "file" dbotscore_list = [dbotscore, dbotscore_copy] context_entry["Lastline"] = lastline context_entry[key] = data # in case of a file indicator if dbotscore_list and dbotscore_list[0]["Score"] != 0: context_entry["DBotScore"] = dbotscore_list if key == "URL" and dbotscore["Score"] != 0: context_entry["DBotScore"] = dbotscore return context_entry def file_hash(path: str) -> str: block_size = 65536 file_hasher = hashlib.md5() # nosec with open(path, "rb") as file_obj: buf = file_obj.read(block_size) while len(buf) > 0: file_hasher.update(buf) buf = file_obj.read(block_size) return file_hasher.hexdigest() def main(): params = demisto.params() base_url = params.get("url") verify_ssl = not params.get("insecure", False) proxy = params.get("proxy") credentials = params.get("credentials") api_params = { "key": params.get("creds_key_and_token", {}).get("identifier", "") or params.get("api_key"), "api_token": params.get("creds_key_and_token", {}).get("password", "") or params.get("api_token"), } api_params.update(demisto.args()) threshold = int(api_params.get("threshold", params.get("threshold", 70))) if not credentials or not credentials.get("identifier") or not credentials.get("password"): credentials = {} if not (api_params.get("key") or api_params.get("api_token")): api_params = {} if not (api_params or credentials): raise DemistoException( "Please fill the credentials in the integration params - api key and token or username and password" ) client = Client(base_url, api_params, verify=verify_ssl, proxy=proxy, credentials=credentials, threshold=threshold) command = demisto.command() demisto.debug(f"Command being called is {command}") # Switch case commands = { "test-module": Client.test_module_command, "file": Client.file, f"{INTEGRATION_COMMAND_NAME}-check-status": Client.check_status, f"{INTEGRATION_COMMAND_NAME}-get-report": Client.get_report, f"{INTEGRATION_COMMAND_NAME}-get-task-list": Client.get_task_list, f"{INTEGRATION_COMMAND_NAME}-upload-file": Client.upload_file, f"{INTEGRATION_COMMAND_NAME}-upload-url": Client.upload_url, } try: if command in commands: readable_output, outputs, raw_response = commands[command](client) return_outputs(readable_output, outputs, raw_response) else: raise DemistoException(f"{demisto.command()} is not a command") # Log exceptions except Exception as every_error: err_msg = f"Error in {INTEGRATION_NAME} Integration [{every_error}]" return_error(err_msg, error=every_error) if __name__ in ("__builtin__", "builtins"): main()