DataBee
DataBee, from Comcast Technology Solutions, is a cloud-native security and compliance data fabric that ingests data from multiple disparate feeds and then aggregates, compresses, standardizes, enriches, correlates, and normalizes the data before transferring a full time-series dataset to your data lake of choice.
Analytics & SIEM · DataBee
Details
| ID | DataBee |
|---|---|
| Provider | Comcast Corporation |
| Category | Analytics & SIEM |
| From Version | 6.10.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
DataBee, from Comcast Technology Solutions, is a cloud-native security and compliance data fabric that ingests data from multiple disparate feeds and then aggregates, compresses, standardizes, enriches, correlates, and normalizes the data before transferring a full time-series dataset to your data lake of choice.
This integration was integrated and tested with version 1.0 of DataBee.
Configure DataBee in Cortex
| Parameter | Description | Required |
|---|---|---|
| Base URL | True | |
| Incident type | False | |
| Username | True | |
| Password | True | |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | False | |
| Additional findings context outputs | Choose additional context data to retrieve from the API. Be aware that requesting extensive context data may impact your server’s performance. | False |
| Fetch incidents | False | |
| Maximum incidents per fetch | True | |
| First fetch timestamp | Timestamp in ISO format or <number> <time unit>, e.g., 2022-01-01T00:00:00.000Z, 12 hours, 7 days, 3 months, now. | True |
| Severity Filter | Filter findings based on their severity level. For example, a level such as “High” is acceptable. | False |
| Impact Filter | Filter findings based on their impact level. For example, a level such as “High” is acceptable. | 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.
databee-device-search
Search for devices based on filters.
Base Command
databee-device-search
Input
| Argument Name | Description | Required |
|---|---|---|
| page | The optional size of the page to retrieve. Must be an integer greater than 0 or less than or equal to 1000. | Optional |
| page_size | The optional 0-based index of the page to retrieve. Must be an integer greater than or equal to 0. | Optional |
| limit | The maximum number of records to retrieve. Default is 50. | Optional |
| search_operator | The search operator applied to filter criteria such as the hostname, MAC address, name, and IP address. It accommodates list objects for filter values, enabling the specification of multiple filter values separated by commas. Specifically, when using the “In” or “Not In” operators, you can input values in formats like “test.com” for a single entry or “test.com,test2.com” for multiple entries. Possible values are: In, Not In. | Optional |
| hostname | Filter devices based on their hostname, using one of the following operators: “Contains”, “In”, or “Not In”. The default operator is “Contains”. Depending on the selected operator, the format for the value varies. For “Contains”, a single hostname such as “test.com” is acceptable. For “In” or “Not In,” you can specify a single hostname or a list of hostnames separated by commas, such as “test.com” or “test.com,test2.com”. | Optional |
| uid | Filter devices based on their UID, using one of the following operators: “Contains”, “In”, or “Not In”. The default operator is “Contains”. Depending on the selected operator, the format for the value varies. For “Contains”, a single ID such as “aa3437c2-a938-419e-95ea-15c04e8bdb98” is acceptable. For “In” or “Not In,” you can specify a single hostname or a list of hostnames separated by commas, such as “aa3437c2-a938-419e-95ea-15c04e8bdb98” or “aa3437c2-a938-419e-95ea-15c04e8bdb98,ed3437c2-a938-419e-95ea-15c04e8bdb98”. | Optional |
| mac | Filter devices based on their MAC address, using one of the following operators: “Contains”, “In”, or “Not In”. The default operator is “Contains”. Depending on the selected operator, the format for the value varies. For “Contains”, a single hostname such as “00-00-00-00-00-00” is acceptable. For “In” or “Not In,” you can specify a single MAC address or a list of MAC addresses separated by commas, such as “00-00-00-00-00-00” or “00-00-00-00-00-00,11-11-11-11-11-11”. | Optional |
| name | Filter devices based on their name, using one of the following operators: “Contains”, “In”, or “Not In”. The default operator is “Contains”. Depending on the selected operator, the format for the value varies. For “Contains”, a single hostname such as “test” is acceptable. For “In” or “Not In,” you can specify a single name or a list of names separated by commas, such as “test” or “test,test2”. | Optional |
| ip | Filter devices based on their IP address, using one of the following operators: “CIDR Block”, “In”, or “Not In”. The default is “CIDR Block”.Depending on the selected operator, the format for the value varies. For “Contains”, a single hostname such as “1.2.3.4” is acceptable. For “In” or “Not In,” you can specify a single IP address or a list of IP addresses separated by commas, such as “1.2.3.4,1.2.3.5”. | Optional |
| query | Insert a query instead of using the filters. The format should be {filter} {operator} {value}. “and” separates between queries. Wrap with brackets when the value has special letters. Using this argument overrides the other filter arguments. For example, hostname contains test and mac in (00-00-00-00-00-00) and domain in (test.com). | Optional |
| time_range | Filter to devices with a verbal time range. The verbal field are: X Minutes, X Hour, X Days, X Months. For example, 1 Week. Using the time range automatically cancels the start time and end time arguments. | Optional |
| start_time | Filter to devices that was created between the start_time and the end_time arguments. For example, 2024-03-26T11:03:18Z. | Optional |
| end_time | Filter to devices that was created between the start_time and the end_time arguments. For example, 2024-03-26T11:03:18Z. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| DataBee.Device.uid | String | A unique identifier for the device. |
| DataBee.Device.type | String | The type of the device. |
| DataBee.Device.region | String | The region where the virtual machine is located. For example, an AWS Region. |
| DataBee.Device.owner | String | The primary owner of a device. |
| DataBee.Device.name | String | The alternate device name. |
| DataBee.Device.ip | String | The device IP address, in either IPv4 or IPv6 format. |
| DataBee.Device.mac | String | The device MAC address. |
| DataBee.Device.interface_uid | String | The unique identifier of the network interface. |
| DataBee.Device.interface_name | String | The name of the network interface (e.g., eth2). |
| DataBee.Device.instance_uid | String | The unique identifier of a VM instance. |
| DataBee.Device.hostname | String | The device hostname. |
| DataBee.Device.end_time | String | The end time of when a particular state of the user was valid. |
| DataBee.Device.start_time | String | The start time when a particular state of the user became valid. |
| DataBee.Device.modified_time | String | The time when the device was modified. |
Command example
!databee-device-search hostname=a limit=1
Context Example
{
"DataBee": {
"Device": {
"Os": {
"build": "BCKFLR98UX",
"language": "hsb",
"name": "Windows",
"type": "Windows",
"type_id": 100,
"version": "0.10"
},
"Owner": {
"account": {
"name": "Guest Account",
"type": "AWS IAM User",
"type_id": 3,
"uid": "g2468101"
},
"backtrace": {
"email_addr": {
"feed": "sap",
"provider": "sap_successfactors",
"source": "17:11:41.830"
},
"name": {
"feed": "sap",
"provider": "sap_successfactors",
"source": "17:11:41.830"
}
},
"credential_uid": "7C8C8617-5E39-45D2-847F-4E1F849B783D",
"domain": "secret",
"email_addr": "secret",
"employee_uid": "62626",
"end_time": "2024-06-07T07:20:02.352612",
"full_name": "Steve Testborne",
"given_name": "Stephen",
"groups": [
{
"name": "Legal",
"type": "Contract",
"uid": "Kc7rVYkS"
},
{
"name": "Accounting",
"type": "Parttime",
"uid": "F4EeDpX9"
}
],
"id": 556,
"job_title": "Developer-2 Technical sales engineer",
"location": {
"city": "Sterling",
"continent": "na",
"coordinates": [
39.00622,
-77.4286
],
"country": "us",
"desc": "City :Sterling,Latitude",
"is_on_premises": true,
"isp": "comcast cable",
"postal_code": "12390",
"provider": "Bing maps",
"region": "east-2"
},
"manager": {
"account": {
"name": "User",
"type": "LDAP Account",
"type_id": 1,
"uid": "u1234567"
},
"backtrace": {
"email_addr": {
"feed": "microsoft",
"provider": "microsoft_graph_api",
"source": "2024-06-07 04:13:04.961"
},
"name": {
"feed": "microsoft",
"provider": "microsoft_graph_api",
"source": "2024-06-07 04:13:04.961"
}
},
"credential_uid": "2DEEB170-C56D-4E0E-B234-39AC4B67BF8E",
"domain": "secret",
"email_addr": "secret",
"employee_uid": "82891",
"end_time": "2024-05-30T20:13:22.403195",
"full_name": "Tracy Carr",
"given_name": "Tracy",
"groups": [
{
"name": "Legal",
"type": "Contract",
"uid": "Kc7rVYkS"
},
{
"name": "Customer Service",
"type": "Parttime",
"uid": "b6LzGnC0"
}
],
"id": 169,
"job_title": "Director-2 Homeopath",
"location": {
"city": "Kendall",
"continent": "na",
"coordinates": [
25.67927,
-80.31727
],
"country": "us",
"desc": "City :Kendall,Latitude",
"is_on_premises": true,
"isp": "AT&T",
"postal_code": "72203",
"provider": "others",
"region": "west-1"
},
"name": "tracy548",
"org": {
"name": "Rodriguez, Rodriguez and Hoffman"
},
"start_time": "2024-05-29T19:55:53.093122",
"sur_name": "Carr",
"type": "User",
"type_id": 1,
"uid": "a5e67347dc1ea0f81173cd6bfbb18cf9b256decadb0ebc360d6a18b570b1d132"
},
"name": "stephen253",
"org": {
"name": "Rodriguez, Rodriguez and Hoffman"
},
"start_time": "2024-06-07T01:34:50.139715",
"sur_name": "Osborne",
"type": "User",
"type_id": 1,
"uid": "d46e7818712a815121f2e1a58288eda8f69d4237e8d7294961e4eadcfae4c703"
},
"hostname": "secret",
"instance_uid": "especially",
"interface_name": "follow",
"interface_uid": "skin",
"ip": "test",
"mac": "70-a7-1d-da-0c-cd",
"modified_time": "2024-06-11T19:08:41.429310",
"name": "GDFE654-FAKE",
"start_time": "2024-06-09T14:39:18.801072",
"type": "Browser",
"uid": "143795e5-741a-4914-b29c-186a060d430f"
}
}
}
Human Readable Output
Device List
Uid Type Name Ip Interface Uid Interface Name Instance Uid Hostname Start Time Modified Time 143795e5-741a-4914-b29c-186a060d430f Browser GDFE654-FAKE test skin follow especially secret 2024-06-09T14:39:18.801072 2024-06-11T19:08:41.429310
databee-user-search
Search for users based on filters.
Base Command
databee-user-search
Input
| Argument Name | Description | Required |
|---|---|---|
| page | The optional size of the page to retrieve. Must be an integer greater than 0 or less than or equal to 1000. | Optional |
| page_size | The optional 0-based index of the page to retrieve. Must be an integer greater than or equal to 0. | Optional |
| limit | The maximum number of records to retrieve. Default is 50. | Optional |
| search_operator | The search operator applied to filter criteria such as the email address, full name, and name. It accommodates list objects for filter values, enabling the specification of multiple filter values separated by commas. Specifically, when using the “In” or “Not In” operators, you can input values in formats like “test” for a single entry or “test,test2” for multiple entries. Possible values are: In, Not In. | Optional |
| email_address | Filter users based on their email address, using one of the following operators: “Contains”, “In”, or “Not In”. The default operator is “Contains”. Depending on the selected operator, the format for the value varies. For “Contains”, a single hostname such as “test@test.com” is acceptable. For “In” or “Not In,” you can specify a single email address or a list of email addresses separated by commas, such as “test@test.com” or “test@test.com,test2@test.com”. | Optional |
| full_name | Filter users based on their full name, using one of the following operators: “Contains”, “In”, or “Not In”. The default operator is “Contains”. Depending on the selected operator, the format for the value varies. For “Contains”, a single hostname such as “Bob Dan” is acceptable. For “In” or “Not In,” you can specify a single full name or a list of full names separated by commas, such as “Bob Dan” or “Bob Dan,Alice Dan”. | Optional |
| name | Filter users based on their name, using one of the following operators: “Contains”, “In”, or “Not In”. The default operator is “Contains”. Depending on the selected operator, the format for the value varies. For “Contains”, a single hostname such as “Bob” is acceptable. For “In” or “Not In,” you can specify a single name or a list of names separated by commas, such as “Bob” or “Bob,Alice”. | Optional |
| query | Insert a query instead of using the filters. The format should be {filter} {operator} {value}. “and” separates between queries. Wrap with brackets when the value has special letters. Using this argument overrides the other filter arguments. For example, hostname contains test and mac in (00-00-00-00-00-00). | Optional |
| time_range | Filter to devices with a verbal time range. The verbal field are: X Minutes, X Hour, X Days, X Months. For example, 1 Week. Using the time range automatically cancels the start time and end time arguments. | Optional |
| start_time | Filter to devices that was created between the start_time and the end_time arguments. For example, 2024-03-26T11:03:18Z. | Optional |
| end_time | Filter to devices that was created between the start_time and the end_time arguments. For example, 2024-03-26T11:03:18Z. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| DataBee.User.uid | String | The unique user identifier. |
| DataBee.User.type | String | The type of the user. For example, System, AWS IAM User, etc. |
| DataBee.User.name | String | The username. |
| DataBee.User.start_time | String | The start time when a particular state of the user became valid. |
| DataBee.User.end_time | String | The end time of when a particular state of the user was valid. |
| DataBee.User.modified_time | String | The time when the user was modified. |
Command example
!databee-user-search full_name=a limit=1
Context Example
{
"DataBee": {
"User": {
"modified_time": "2024-06-13T13:17:51.025057",
"name": "bradley459",
"start_time": "2024-06-10T06:58:37.202327",
"type": "User",
"uid": "4c12656e73b90df215e63ca7e3317ace78b8e21540961831b207e69313d7dc5a"
}
}
}
Human Readable Output
User List
Uid Type Name Start Time Modified Time 4c12656e73b90df215e63ca7e3317ace78b8e21540961831b207e69313d7dc5a User bradley459 2024-06-10T06:58:37.202327 2024-06-13T13:17:51.025057
databee-finding-search
Search for security findings based on filters.
Base Command
databee-finding-search
Input
| Argument Name | Description | Required |
|---|---|---|
| page | The optional size of the page to retrieve. Must be an integer greater than 0 or less than or equal to 1000. | Optional |
| page_size | The optional 0-based index of the page to retrieve. Must be an integer greater than or equal to 0. | Optional |
| limit | The maximum number of records to retrieve. Default is 50. | Optional |
| search_operator | The search operator applied to filter criteria such as the analytic name, confidence level, device environment, device risk level, impact, risk level, and severity. It accommodates list objects for filter values, enabling the specification of multiple filter values separated by commas. Specifically, when using the “In” or “Not In” operators, you can input values in formats like “High” for a single entry or “High,Low” for multiple entries. Possible values are: In, Not In. | Optional |
| analytic_name | Filter findings based on their analytic name, using one of the following operators: “In”, or “Not In”. The default operator is “In”. You can specify a single analytic name or a list of analytic names separated by commas, such as “about” or “about, matter”. | Optional |
| confidence | Filter findings based on their confidence level, using one of the following operators: “Contains”, “In”, or “Not In”. The default operator is “Contains”. Depending on the selected operator, the format for the value varies. For “Contains”, a single confidence level such as “High” is acceptable. For “In” or “Not In,” you can specify a single confidence level or a list of confidence levels separated by commas, such as “High” or “High,Medium”. Possible values are: High, Medium, Low, Other, Unknown, Stable. | Optional |
| device_environment | Filter findings based on their device environment, using one of the following operators: “In”, or “Not In”. The default operator is “In”. You can specify a single device environment or a list of device environments separated by commas, such as “Development” or “Development,Production”. | Optional |
| device_risk_level | Filter findings based on their device environment, using one of the following operators: “In”, or “Not In”. The default operator is “In”. You can specify a single device risk level or a list of device risk levels separated by commas, such as “Critical” or “Critical,High”. Possible values are: Critical, High, Info. | Optional |
| impact | Filter findings based on their impact level, using one of the following operators: “Contains”, “In”, or “Not In”. The default operator is “Contains”. Depending on the selected operator, the format for the value varies. For “Contains”, a single impact level such as “High” is acceptable. For “In” or “Not In,” you can specify a single impact level or a list of impact levels separated by commas, such as “High” or “High,Medium”. Possible values are: Critical, High, Medium, Low, Other, Unknown. | Optional |
| risk_level | Filter findings based on their risk level, using one of the following operators: “Contains”, “In”, or “Not In”. The default operator is “Contains”. Depending on the selected operator, the format for the value varies. For “Contains”, a single risk level such as “High” is acceptable. For “In” or “Not In,” you can specify a single risk level or a list of risk levels separated by commas, such as “High” or “High,Medium”. Possible values are: Critical, High, Medium, Low, Info. | Optional |
| severity | Filter findings based on their severity level, using one of the following operators: “Contains”, “In”, or “Not In”. The default operator is “Contains”. Depending on the selected operator, the format for the value varies. For “Contains”, a single severity level such as “High” is acceptable. For “In” or “Not In,” you can specify a single severity level or a list of severity levels separated by commas, such as “High” or “High,Medium”. Possible values are: Fatal, Critical, High, Medium, Low, Information, Other, Unknown. | Optional |
| query | Insert a query instead of using the filters. The format should be {filter} {operator} {value}. “and” separates between queries. Wrap with brackets when the value has special letters. Using this argument overrides the other filter arguments. For example, hostname contains test and mac in (00-00-00-00-00-00). | Optional |
| time_range | Filter to devices with a verbal time range. The verbal field are: X Minutes, X Hour, X Days, X Months. For example, 1 Week. Using the time range automatically cancels the start time and end time arguments. | Optional |
| start_time | Filter to devices that was created between the start_time and the end_time arguments. For example, 2024-03-26T11:03:18Z. | Optional |
| end_time | Filter to devices that was created between the start_time and the end_time arguments. For example, 2024-03-26T11:03:18Z. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| DataBee.Finding.device_id | Integer | Unique identifier of the device involved in the finding. |
| DataBee.Finding.user_id | Integer | Unique identifier of the user involved in the finding. |
| DataBee.Finding.activity_id | Integer | Identifier for the activity associated with the finding. |
| DataBee.Finding.activity_name | String | Name of the activity related to the finding. |
| DataBee.Finding.Analytic.category | String | Category of the analytics used in the finding. |
| DataBee.Finding.Analytic.desc | String | Detailed description of the analytic approach or rule. |
| DataBee.Finding.Analytic.name | String | Name of the analytic rule or method used. |
| DataBee.Finding.Analytic.type | String | Type of analytic method employed, such as rule-based or heuristic. |
| DataBee.Finding.Analytic.uid | String | Unique identifier for the specific analytic method used. |
| DataBee.Finding.Attack.Tactic.id | String | Unique identifier for each tactic involved in the attack. |
| DataBee.Finding.Attack.Tactic.name | String | Name of the tactic used in the attack. |
| DataBee.Finding.Attack.Tactic.uid | String | Unique identifier (UID) of the tactic used in the attack. |
| DataBee.Finding.Attack.Technique.id | String | Unique identifier for the technique used within the attack. |
| DataBee.Finding.Attack.Technique.name | String | Name of the technique employed in the attack. |
| DataBee.Finding.Attack.Technique.uid | String | Unique identifier (UID) for the technique used in the attack. |
| DataBee.Finding.category_name | String | Name of the category to which the finding is classified. |
| DataBee.Finding.CisCsc.control | String | Description of the control measure from CIS CSC associated with the finding. |
| DataBee.Finding.CisCsc.id | Integer | Identifier for the CIS CSC control relevant to the finding. |
| DataBee.Finding.CisCsc.version | String | Version information of the CIS CSC control relevant to the finding. |
| DataBee.Finding.class_name | String | Classification of the finding that indicates its nature and type. |
| DataBee.Finding.confidence | String | confidence. |
| DataBee.Finding.data_source | String | List of data sources that provided information for the finding. |
| DataBee.Finding.Device.ip | String | IP address of the device associated with the finding. |
| DataBee.Finding.Device.mac | String | MAC address of the device associated with the finding. |
| DataBee.Finding.Device.hostname | String | Hostname of the device involved in the finding. |
| DataBee.Finding.Device.os | Unknown | Operating system running on the device at the time of the finding. |
| DataBee.Finding.duration | String | Duration over which the finding was active or observed. |
| DataBee.Finding.end_time | String | Timestamp marking the end of the occurrence or observation of the finding. |
| DataBee.Finding.Evidence | Unkonwn | Comprehensive details of all evidence related to the finding, documenting the activities, actors, devices, and processes involved. |
| DataBee.Finding.Finding.created_time | String | The timestamp when the finding was initially created in the monitoring or detection system. |
| DataBee.Finding.Finding.desc | String | A brief description of the finding, outlining the main observations or conclusions. |
| DataBee.Finding.Finding.first_seen_time | String | The first time the issue or behavior described in the finding was observed. |
| DataBee.Finding.Finding.last_seen_time | String | The last time the issue or behavior described in the finding was observed, marking the duration of its known activity. |
| DataBee.Finding.Finding.modified_time | String | The timestamp when the finding record was last updated or modified. |
| DataBee.Finding.Finding.product_uid | String | Unique identifier for the product or system associated with the finding, which can be used to track back to specific tools or systems. |
| DataBee.Finding.Finding.RelatedEvent | Unkonwn | Any events that are related to the finding, providing connections or correlations with other incidents or activities. |
| DataBee.Finding.Finding.Remediation | Unkonwn | Remediation steps or recommendations provided to address or mitigate the finding. |
| DataBee.Finding.Finding.src_url | String | A URL or link to more detailed information or a full report concerning the finding, often pointing to an internal knowledge base or external resource. |
| DataBee.Finding.Finding.supporting_data | Unknown | Supporting data or additional documentation that helps to substantiate or explain the finding, which may include logs, images, or other forensic materials. |
| DataBee.Finding.Finding.title | String | The title of the finding, which typically summarizes the issue or key point in a concise format. |
| DataBee.Finding.Finding.types_ | String | The types or categories of the finding, which help to classify the nature of the issue within established frameworks or standards. |
| DataBee.Finding.Finding.uid | String | A unique identifier assigned to the finding, used for tracking and management within the system. |
| DataBee.Finding.id | Integer | Unique identifier of the finding. |
| DataBee.Finding.impact | String | Describes the impact of the finding on the organization or system. |
| DataBee.Finding.impact_score | Integer | Numerical score representing the severity of the impact from the finding. |
| DataBee.Finding.KillChain | String | Identifies the stages of the kill chain that the finding relates to. |
| DataBee.Finding.message | String | Summary or detailed message explaining the finding. |
| DataBee.Finding.Metadata | Unkonwn | Metadata associated with the finding that provides additional context or background information. |
| DataBee.Finding.Observable.name | String | The name or identifier of the observable item, providing a descriptor of the observable’s nature or purpose. |
| DataBee.Finding.Observable.Reputation | Unkonwn | Reputation details associated with the observable, including scores and source information. |
| DataBee.Finding.Observable.type | String | The type of observable, such as IP address, URL, file hash, etc., classifying the observable’s format or domain. |
| DataBee.Finding.Observable.value | String | The value of the observable, which could be an IP address, a file hash, a URL, or any other relevant data point. |
| DataBee.Finding.Process.cmd_line | String | The command line used to initiate the process, providing insights into the process’s function or purpose. |
| DataBee.Finding.Process.container | String | Identifies whether the process is running within a container, specifying the container environment if applicable. |
| DataBee.Finding.Process.created_time | String | The timestamp when the process was initiated or first observed. |
| DataBee.Finding.Process.File | Unkonwn | Details about files associated with the process, including names, paths, and security details. |
| DataBee.Finding.Process.File.company_name | String | The name of the company associated with the file, often indicating software ownership or authorship. |
| DataBee.Finding.Process.File.desc | String | A description of the file’s purpose or functionality. |
| DataBee.Finding.Process.File.Hashes | Unkonwn | Contains hash values of the file for integrity and identification purposes, such as MD5, SHA-1, or SHA-256. |
| DataBee.Finding.Process.File.is_system | Boolean | Indicates whether the file is a system file, helping to identify its criticality and origin within the operating system. |
| DataBee.Finding.Process.File.md5 | String | MD5 hash of the file, used for verifying the file’s integrity and for quick identification in threat intelligence databases. |
| DataBee.Finding.Process.File.mime_type | String | MIME type of the file, describing the file’s format and potentially its intended use or behavior. |
| DataBee.Finding.Process.File.modified_time | String | Timestamp of the last modification made to the file, providing context for its use or alteration. |
| DataBee.Finding.Process.File.name | String | Name of the file involved in the process, which may indicate its functionality or relevance. |
| DataBee.Finding.Process.File.owner | String | Owner of the file, which could be a user name or system account under whose authority the file operates. |
| DataBee.Finding.Process.File.parent_folder | String | The directory in which the file resides, providing context for its location within the file system. |
| DataBee.Finding.Process.File.path | String | Full path to the file, detailing its exact location on the file system. |
| DataBee.Finding.Process.File.security_descriptor | String | Security settings and permissions associated with the file, outlining access controls and protection mechanisms. |
| DataBee.Finding.Process.File.sha1 | String | SHA-1 hash of the file, used for more secure integrity checking compared to MD5. |
| DataBee.Finding.Process.File.sha256 | String | SHA-256 hash of the file, providing a highly reliable method for verifying the file’s integrity. |
| DataBee.Finding.Process.File.sha512 | String | SHA-512 hash of the file, offering an even more robust hashing option for security purposes. |
| DataBee.Finding.Process.File.signature | String | Information about any digital signatures attached to the file, which can verify its authenticity and source. |
| DataBee.Finding.Process.File.size | Integer | The size of the file in bytes, providing a basic measure of its content and potential load when processed. |
| DataBee.Finding.Process.File.type | String | Type of file, such as executable, document, or archive, which helps classify its role and usage. |
| DataBee.Finding.Process.File.xattributes | String | Extended attributes of the file, offering additional metadata or control flags specific to certain operating systems. |
| DataBee.Finding.Process.name | String | Name of the process associated with the finding, often indicative of the process’s purpose or origin. |
| DataBee.Finding.Process.namespace_pid | Integer | Process ID specific to a particular namespace, used in environments where processes are isolated or containerized. |
| DataBee.Finding.Process.parent_process | String | Identifier of the parent process from which the current process was spawned. |
| DataBee.Finding.Process.pid | Integer | Process ID (PID) of the process, uniquely identifying it within the system at the time of observation. |
| DataBee.Finding.Process.sandbox | String | Indicates whether the process is running within a sandboxed environment, which can affect its ability to interact with the system. |
| DataBee.Finding.Process.user | String | User account under which the process is running, providing insights into the process’s permissions and role within the system. |
| DataBee.Finding.risk_level | String | Categorizes the finding by the level of risk it poses to the organization or system. |
| DataBee.Finding.risk_score | Integer | A calculated score that quantifies the risk level of the finding. |
| DataBee.Finding.severity | String | The severity rating of the finding, which helps prioritize responses and remediation efforts. |
| DataBee.Finding.start_time | String | The time when the incident or activity that led to the finding began. |
| DataBee.Finding.state | String | The current state of the finding within the incident response or review process. |
| DataBee.Finding.status | String | Current status of the finding, indicating where it is in the workflow or lifecycle. |
| DataBee.Finding.status_detail | String | Provides additional details on the status of the finding, offering more granular insights into its processing state. |
| DataBee.Finding.time | String | The timestamp documenting when the finding was last observed or updated. |
| DataBee.Finding.type_name | String | The type name categorizes the finding according to a predefined classification system. |
| DataBee.Finding.User | Unkonwn | Information about the user associated with the finding, if applicable. |
Command example
!databee-finding-search impact=High limit=1
Context Example
{
"DataBee": {
"Finding": {
"Analytic": {
"category": null,
"desc": null,
"name": "Potential AD User Enumeration From Non-Machine Account",
"type": "Rule",
"uid": "ab6bffca-beff-4baa-af11-6733f296d57a"
},
"Attack": [
{
"Tactic": [
{
"id": 606,
"name": "interview",
"uid": "TA0002"
},
{
"id": 272,
"name": "certain",
"uid": "TA0010"
}
],
"Technique": {
"id": 538,
"name": "moment",
"uid": "T1036.004"
}
},
{
"Tactic": [
{
"id": 914,
"name": "TV",
"uid": "TA0043"
},
{
"id": 368,
"name": "risk",
"uid": "TA0010"
}
],
"Technique": {
"id": 316,
"name": "provide",
"uid": "T1070.004"
}
}
],
"CisCsc": [
{
"control": "anyone",
"id": 697,
"version": "unit"
},
{
"control": "act",
"id": 717,
"version": "institution"
}
],
"Device": {
"hostname": "secret",
"ip": "secret",
"mac": "e4-b0-ba-5c-a7-ad",
"os": {
"build": "ZPD3QQJEKH",
"language": "sk",
"name": "AIX",
"type": "AIX",
"type_id": 401,
"version": "1.2"
}
},
"Evidence": {},
"Finding": {
"RelatedEvent": null,
"Remediation": null,
"created_time": "2024-05-10 09:25:21.512958",
"desc": "decade",
"first_seen_time": "2024-05-19 01:49:44.121595",
"last_seen_time": "2024-06-02 07:29:06.277547",
"modified_time": "2024-05-13 20:00:36.121908",
"product_uid": "practice",
"src_url": "secret",
"supporting_data": {
"director": "prevent"
},
"title": "assume",
"types_": null,
"uid": "P-8043"
},
"KillChain": [
{
"id": 238,
"phase": "black",
"phase_id": 7
},
{
"id": 73,
"phase": "apply",
"phase_id": 7
}
],
"Metadata": {},
"Observable": [
{
"Reputation": {
"base_score": 0.8084,
"id": 320,
"provider": "Congress",
"score": "move",
"score_id": 10
},
"name": "our",
"type": "shake",
"value": "plan"
},
{
"Reputation": {
"base_score": 2.8203,
"id": 460,
"provider": "east",
"score": "gun",
"score_id": 10
},
"name": "eye",
"type": "oil",
"value": "guess"
}
],
"Process": {},
"User": {
"account": {
"name": "User",
"type": "LDAP Account",
"type_id": 1,
"uid": "u1234567"
},
"backtrace": {
"email_addr": {
"feed": "ping",
"provider": "ping_one",
"source": "2024-06-07 11:47:57.905"
},
"name": {
"feed": "ping",
"provider": "ping_one",
"source": "2024-06-07 11:47:57.905"
}
},
"cost_center": "tend",
"created_time": "2024-05-12 19:01:23.687349",
"credential_uid": "0A16A88C-5332-4791-A1A2-7630245D373A",
"deleted_time": "2024-06-03 20:12:44.361040",
"domain": "test.com",
"email_addr": "test.com",
"email_addresses": [],
"employee_uid": "54873",
"end_time": null,
"full_name": "Kathleen Moore",
"given_name": "Kathleen",
"groups": [
{
"name": "HR",
"type": "Intern",
"uid": "X3tPwGzR"
},
{
"name": "Marketing",
"type": "Fulltime",
"uid": "v5JmQnU1"
}
],
"hid": 528,
"hire_datetime": "2024-05-12 14:49:51.534152",
"id": 356,
"job_title": "Developer-2 Chartered accountant",
"labels": [
"approach",
"today"
],
"last_login_time": "2024-05-26 15:58:28.269928",
"ldap_person": {
"cost_center": "tend",
"created_time": "2024-05-12 19:01:23.687349",
"deleted_time": "2024-06-03 20:12:44.361040",
"email_addrs": [],
"employee_uid": "54873",
"given_name": "Kathleen",
"hire_time": "2024-05-17 07:29:01.749971",
"id": 356,
"job_title": "Developer-2 Chartered accountant",
"labels": [
"approach",
"today"
],
"last_login_time": "2024-05-26 15:58:28.269928",
"ldap_cn": "worry",
"ldap_dn": "risk",
"leave_time": "2024-06-02 02:50:40.018950",
"location": {
"city": "Far Rockaway",
"continent": "na",
"coordinates": [
40.60538,
-73.75513
],
"country": "us",
"desc": "City :Far Rockaway,Latitude",
"is_on_premises": true,
"isp": "comcast cable",
"postal_code": "91823",
"provider": "Bing maps",
"region": "west-1"
},
"manager": {
"account": {
"name": "Guest Account",
"type": "AWS IAM User",
"type_id": 3,
"uid": "g2468101"
},
"backtrace": {
"email_addr": {
"feed": "ping",
"provider": "ping_one",
"source": "22:23:01.919"
},
"name": {
"feed": "ping",
"provider": "ping_one",
"source": "22:23:01.919"
}
},
"credential_uid": "25ECFB7D-2372-4787-A584-9B068DE54F22",
"domain": "test.com",
"email_addr": "test.com",
"employee_uid": "99342",
"end_time": "2024-06-02T08:45:59.223622",
"full_name": "Mr. Juan Young",
"given_name": "Mr.",
"groups": [
{
"name": "Procurement",
"type": "Fulltime",
"uid": "S2JrDkV0"
}
],
"id": 250,
"job_title": "Director-1 Environmental education officer",
"location": {
"city": "Brenham",
"continent": "na",
"coordinates": [
30.16688,
-96.39774
],
"country": "us",
"desc": "City :Brenham,Latitude",
"is_on_premises": true,
"isp": "comcast cable",
"postal_code": "20248",
"provider": "google maps",
"region": "north-1"
},
"merge_history": [],
"name": "mr.728",
"org": {
"name": "Rodriguez, Rodriguez and Hoffman"
},
"start_time": "2024-05-18T23:56:45.184722",
"sur_name": "Young",
"type": "User",
"type_id": 1,
"uid": "25c758bdf94e7356eec4afd5ffb0075085d52cae83703191ffa2d47d2b135323"
},
"modified_time": "2024-05-25 12:28:48.049312",
"office_location": "give",
"surname": "Moore"
},
"leave_datetime": "2024-05-16 16:46:41.852020",
"location": {
"city": "Far Rockaway",
"continent": "na",
"coordinates": [
40.60538,
-73.75513
],
"country": "us",
"desc": "City :Far Rockaway,Latitude",
"is_on_premises": true,
"isp": "comcast cable",
"postal_code": "91823",
"provider": "Bing maps",
"region": "west-1"
},
"manager": {
"account": {
"name": "Guest Account",
"type": "AWS IAM User",
"type_id": 3,
"uid": "g2468101"
},
"backtrace": {
"email_addr": {
"feed": "ping",
"provider": "ping_one",
"source": "22:23:01.919"
},
"name": {
"feed": "ping",
"provider": "ping_one",
"source": "22:23:01.919"
}
},
"credential_uid": "25ECFB7D-2372-4787-A584-9B068DE54F22",
"domain": "test.com",
"email_addr": "test.com",
"employee_uid": "99342",
"end_time": "2024-06-02T08:45:59.223622",
"full_name": "Mr. Juan Young",
"given_name": "Mr.",
"groups": [
{
"name": "Procurement",
"type": "Fulltime",
"uid": "S2JrDkV0"
}
],
"id": 250,
"job_title": "Director-1 Environmental education officer",
"location": {
"city": "Brenham",
"continent": "na",
"coordinates": [
30.16688,
-96.39774
],
"country": "us",
"desc": "City :Brenham,Latitude",
"is_on_premises": true,
"isp": "comcast cable",
"postal_code": "20248",
"provider": "google maps",
"region": "north-1"
},
"merge_history": [],
"name": "mr.728",
"org": {
"name": "Rodriguez, Rodriguez and Hoffman"
},
"start_time": "2024-05-18T23:56:45.184722",
"sur_name": "Young",
"type": "User",
"type_id": 1,
"uid": "25c758bdf94e7356eec4afd5ffb0075085d52cae83703191ffa2d47d2b135323"
},
"merge_history": [],
"modified_time": "2024-05-25 12:28:48.049312",
"name": "kathleen302",
"office_location": "give",
"org": {
"name": "Rodriguez, Rodriguez and Hoffman"
},
"risk_level": "sure",
"risk_level_id": 4,
"risk_score": 275,
"start_time": "2024-06-07T10:09:23.330821",
"surname": "Moore",
"type": "User",
"type_id": 1,
"uid": "cf8df11ed6bc75707ef66a58d25e013253463a386ed834d2d983edd44b201415",
"uid_alt": "watch"
},
"activity_id": 1,
"activity_name": "Create",
"category_name": "Findings",
"class_name": "Security Finding",
"confidence": "Medium",
"data_source": [
"inside",
"challenge"
],
"device_id": 1852,
"duration": 679,
"end_time": "2024-06-05T20:26:55.159433",
"id": 2004,
"impact": "High",
"impact_score": 739,
"message": "Activity from Suspicious IP Addresses user",
"risk_level": "Low",
"risk_score": 243,
"severity": "High",
"start_time": "2024-06-05T19:44:15.659120",
"state": "Completed",
"status": "Completed",
"status_detail": "Link Clicked",
"time": "2024-06-16T06:24:02.639735",
"type_name": "Security Finding: Create",
"user_id": 356
}
}
}
Human Readable Output
Finding List
Time Activity Name Impact State Severity Confidence 2024-06-16T06:24:02.639735 Create High Completed High Medium
endpoint
Returns information about an endpoint.
Base Command
endpoint
Input
| Argument Name | Description | Required |
|---|---|---|
| id | The endpoint ID. | Optional |
| ip | The endpoint IP address. | Optional |
| hostname | The endpoint hostname. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Endpoint.Hostname | String | The endpoint’s hostname. |
| Endpoint.OS | String | The endpoint’s operation system. |
| Endpoint.IPAddress | String | The endpoint’s IP address. |
| Endpoint.ID | String | The endpoint’s ID. |
| Endpoint.MACAddress | String | The endpoint’s MAC address. |
| Endpoint.Vendor | String | The integration name of the endpoint vendor. |
| Endpoint.OSVersion | String | The endpoint’s operation system version. |
Command example
!endpoint ip=8.8.8.8
Context Example
{
"Endpoint": {
"Hostname": "test.com",
"ID": "ed3437c2-a938-419e-95ea-15c04e8bdb98",
"IPAddress": "8.8.8.8",
"MACAddress": "aa-fa-fd-37-0a-de",
"OS": "Linux",
"OSVersion": "1.4",
"Vendor": "DataBee"
}
}
Human Readable Output
DataBee Endpoint
Hostname ID IPAddress MACAddress OS OSVersion Vendor test.com ed3437c2-a938-419e-95ea-15c04e8bdb98 8.8.8.8 aa-fa-fd-37-0a-de Linux 1.4 DataBee
Configuration parameters
url— Base URL (required)incidentType— Incident typeincidentFetchInterval— Incidents Fetch Intervalcredentials— Username (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settingsadditional_context— Additional findings context outputsisFetch— Fetch incidentsmax_fetch— Maximum incidents per fetch (required)first_fetch— First fetch timestamp (required)severity— Severity Filterimpact— Impact Filter
Commands (4)
-
databee-device-searchSearch for devices based on filters.
-
databee-finding-searchSearch for security findings based on filters.
-
databee-user-searchSearch for users based on filters.
-
endpointReturns information about an endpoint.
from dataclasses import dataclass from datetime import datetime from enum import Enum from http import HTTPStatus from typing import Any import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 DEFAULT_OFFSET = 0 DEFAULT_LIMIT = 10 DATE_FORMAT = "%m/%d/%Y %H:%M" XSOAR_DATE_FORMAT = "%Y-%m-%dT%H:%M:%S.000Z" INTEGRATION_PREFIX = "DataBee" class AdditionalContext(str, Enum): evidence = "Finding.Evidence" related_event = "Finding.Finding.RelatedEvent" remediation = "Finding.Finding.Remediation" metadata = "Finding.Metadata" observable = "Finding.Observable" process = "Finding.Process" class SearchTypes(str, Enum): USER = "user" DEVICE = "device" FINDING = "security_finding" @dataclass class SearchConfiguration: type: SearchTypes headers: list[str] title: str output_prefix: str output_keys: list[str] filters: list[tuple[str, str]] SEARCH_CONFIGURATIONS: dict[SearchTypes, SearchConfiguration] = { SearchTypes.USER: SearchConfiguration( filters=[("email_address", "email_addr"), ("full_name", "full_name"), ("name", "name")], type=SearchTypes.USER, headers=["uid", "type", "name", "start_time", "end_time", "modified_time"], title="User", output_prefix="User", output_keys=["uid", "type", "name", "start_time", "end_time", "modified_time"], ), SearchTypes.DEVICE: SearchConfiguration( filters=[("hostname", "hostname"), ("mac", "mac"), ("name", "name"), ("ip", "ip"), ("id", "uid"), ("uid", "uid")], type=SearchTypes.DEVICE, headers=[ "uid", "type", "region", "name", "ip", "interface_uid", "interface_name", "instance_uid", "hostname", "start_time", "end_time", "modified_time", ], title="Device", output_prefix="Device", output_keys=[ "uid", "type", "region", "owner", "os", "name", "ip", "interface_uid", "interface_name", "instance_uid", "hostname", "start_time", "end_time", "modified_time", "mac", ], ), SearchTypes.FINDING: SearchConfiguration( filters=[ ("analytic_name", "analytic.name"), ("confidence", "confidence"), ("device_environment", "device.environment"), ("device_risk_level", "device.risk_level"), ("impact", "impact"), ("risk_level", "risk_level"), ("severity", "severity"), ], type=SearchTypes.FINDING, headers=[ "time", "activity_name", "impact", "state", "severity", "user", "device", "analytic", "confidence", ], title="Finding", output_prefix="Finding", output_keys=[], ), } class Client(BaseClient): """Client class to interact with DataBee API.""" def __init__( self, base_url: str, verify: bool, proxy: bool, password: str, username: str | None = None, ): base_url = urljoin(base_url, "api") if not username: super().__init__( base_url=base_url, headers={"Authorization": f"Token {password}"}, verify=verify, proxy=proxy, ) else: super().__init__( base_url=base_url, verify=verify, proxy=proxy, ) api_token = self.authenticate( username=username, password=password, ).json()["api_key"] super().__init__( base_url=base_url, headers={"Authorization": f"Token {api_token}"}, verify=verify, proxy=proxy, ) def _http_request(self, *args, **kwargs) -> requests.Response: """ Warp to _http_request command, for adding error handler. Returns: requests.Response: API response from DataBee API. """ kwargs["error_handler"] = self.error_handler res = super()._http_request(*args, **kwargs) return res def error_handler(self, res: requests.Response): """ Handling with request errors. Args: res (requests.Response): API response from DataBee API. Raises: DemistoException: Error response. """ match res.status_code: case HTTPStatus.UNAUTHORIZED: raise DemistoException("Unauthorized error. Please check your API token/ username/ password.") case _: if "application/json" in res.headers.get("Content-Type", ""): json_response = res.json() if detail := json_response.get("detail"): raise DemistoException(detail) raise DemistoException(json_response) raise DemistoException(res) def authenticate( self, username: str, password: str, ) -> requests.Response: """Get API token with username and password. Args: username (str): DataBee username. password (str): DataBee password. Returns: Response: API response from DataBee. """ return self._http_request( method="POST", url_suffix="login/", json_data={ "username": username, "password": password, }, resp_type="response", ) def search( self, table: str, query: str, limit: int | None = None, offset: int = 0, ) -> requests.Response: """Search data in DataBee. Args: table (str): Table (to search for) name. query (str): Query. limit (int | None): requests.Response limit. Defaults to None. offset (int): Offset. Defaults to 0. Returns: requests.Response: API response from DataBee. """ return self._http_request( method="GET", url_suffix=f"/search/{table}", params=remove_empty_elements( { "query": query, "offset": offset, "limit": limit, } ), resp_type="response", ) def parse_response( type: str, data: list[dict[str, Any]], keys: list[str], additional_context: list[AdditionalContext], ) -> list[dict[str, Any]]: """ Parse response to outputs. Args: type (str): The search table type. data (list[dict[str, Any]]): The readable output title. keys (list[str]): The output prefix. Returns: list[dict[str, Any]]: XSOAR context outputs. """ if type == SearchTypes.FINDING: normalize_data = [normalize_finding(d, additional_context) for d in data] else: fixed_data = [ remove_empty_elements( {camelize_string(key) if isinstance(obj.get(key), dict) else key: obj.get(key) for key in keys if key in obj} ) for obj in data ] normalize_data = fixed_data return normalize_data def generate_command_results( title: str, outputs_prefix: str, outputs_key_field: str, headers: list[str], outputs: list[dict[str, Any]] | dict[str, Any], raw_response: list[dict[str, Any]] | dict[str, Any], readable_outputs: dict[str, Any] = None, ) -> CommandResults: """ Generates Command Results object. Args: title (str): The readable output title. outputs_prefix (str): The output prefix. outputs_key_field (str): The output key field. headers (list): The readable output headers. outputs (list[dict[str, Any]] | dict[str, Any]): The outputs. raw_response (dict[str, Any]): The raw response. readable_outputs (dict[str, Any], optional): Readable outputs data. Defaults to None. Returns: CommandResults: outputs, readable outputs and raw response for XSOAR. """ return CommandResults( outputs_prefix=f"{INTEGRATION_PREFIX}.{outputs_prefix}", outputs_key_field=outputs_key_field, raw_response=raw_response, outputs=outputs, readable_output=tableToMarkdown( title, readable_outputs or outputs, headers=headers, removeNull=True, headerTransform=string_to_table_header, ), ) def create_query(operator: str | None, key: str, value: str | list | None): """ Create query single filter. Args: operator (str | None): The filter operator. key (str): The DataBee key filter. value (str | list | None): The value. Returns: str: Formated query for search. """ operator = operator.replace(" ", "") if operator else operator if value: if operator and operator != "between": values = (",").join(argToList(value)) return f"{key} {operator.lower()} ({values})" elif "." in key: operator = operator or "in" values = (",").join(argToList(value)) return f"{key} {operator.lower()} ({values})" else: operator = operator or "contains" return f"{key} {operator.lower()} {value}" return None def build_full_query(search_type: SearchTypes, args: dict[str, Any]) -> str: """ Build full query for table search. Args: search_type (SearchTypes): The search type (user/ device/ finding). args (dict[str, Any]): Command arguments from XSOAR. Raises: ValueError: In case query or filters not provided. Returns: str: Formated query for search. """ if query := args.get("query"): return query query = [] filter_keys = [] # Handle with common filters start_time = arg_to_datetime(args.get("start_time")) end_time = arg_to_datetime(args.get("end_time")) time_range = parse_date_range(date_range=args["time_range"], date_format=DATE_FORMAT) if args.get("time_range") else None if start_time and end_time: format_start_time = start_time.strftime(DATE_FORMAT) format_end_time = end_time.strftime(DATE_FORMAT) query.append(create_query(operator="between", key="start_time", value=f"{format_start_time},{format_end_time}")) if time_range: query.append(create_query(operator="between", key="start_time", value=f"{time_range[0]},{time_range[1]}")) # Handle with custom filters filter_keys = SEARCH_CONFIGURATIONS[search_type].filters search_operator = args.get("search_operator") for xsoar_key, databee_key in filter_keys: query.append(create_query(operator=search_operator, key=databee_key, value=args.get(xsoar_key))) query = remove_empty_elements(query) if len(query) == 0: raise ValueError("You have to provide at least one filter or use the query argument.") if search_type == SearchTypes.FINDING: query.append("metadata.product.name in databee") return (" and ").join(query) def get_pagination_args( page: str, limit: str, page_size: str | None, ) -> tuple[int, int]: """ Get XSOAR pagination in DataBee format. Args: page (str): Page. limit (str): Limit. page_size (str): Page Size. Returns: tuple[int, int]: DataBee limit and offset. """ xsoar_limit = arg_to_number(page_size if page_size else limit) xsoar_offset = DEFAULT_OFFSET if page_size and (new_page := arg_to_number(page)) and (new_page_size := arg_to_number(page_size)): xsoar_offset = new_page * new_page_size return (xsoar_limit or DEFAULT_LIMIT, xsoar_offset or DEFAULT_OFFSET) def search_command( client: Client, args: dict[str, Any], settings: SearchConfiguration, additional_context: list[AdditionalContext], ) -> CommandResults: """ Search for DataBee tables. Args: client (Client): DataBee API client. args (Dict[str, Any]): Command arguments from XSOAR. Returns: CommandResults: outputs, readable outputs and raw response for XSOAR. """ limit, offset = get_pagination_args( page=args["page"], limit=args["limit"], page_size=args.get("page_size"), ) response = client.search( table=settings.type.value, query=build_full_query(search_type=settings.type, args=args), limit=limit, offset=offset, ).json() return generate_command_results( title=f"{settings.title} List", outputs_prefix=settings.output_prefix, outputs_key_field="uid", headers=settings.headers, outputs=parse_response( type=settings.type, data=response.get("results") or [], keys=settings.output_keys, additional_context=additional_context, ), raw_response=response, ) def get_endpoint_command( client: Client, args: dict[str, Any], ) -> list[CommandResults]: hostname = args.get("hostname") ip = args.get("ip") id = args.get("id") if not ip and not hostname and not id: # in order not to return all the devices raise ValueError("Please add a filter argument - ip, hostname ot id.") # use OR operator between filters (https://github.com/demisto/etc/issues/46353) raw_res = client.search( table=SearchTypes.DEVICE.value, query=build_full_query( search_type=SEARCH_CONFIGURATIONS[SearchTypes.DEVICE].type, args=(args | {"search_operator": "in"}), ), ).json() devices = raw_res.get("results", []) if not devices: raise ValueError("No devices was found") standard_endpoints = [] for single_device in devices: endpoint = Common.Endpoint( id=single_device.get("uid"), hostname=single_device.get("hostname"), ip_address=single_device.get("ip"), os=dict_safe_get(single_device, ["os", "type"]), os_version=dict_safe_get(single_device, ["os", "version"]), mac_address=single_device.get("mac"), vendor=INTEGRATION_PREFIX, ) standard_endpoints.append(endpoint) command_results = [] for endpoint in standard_endpoints: endpoint_context = endpoint.to_context().get(Common.Endpoint.CONTEXT_PATH) hr = tableToMarkdown("DataBee Endpoint", endpoint_context) command_results.append(CommandResults(readable_output=hr, raw_response=raw_res, indicator=endpoint)) return command_results def test_module(client: Client) -> str: """ Test module. Args: client (Client): DataBee client. params (Dict): Integration parameters. Raises: ValueError: In case of wrong request. Returns: str: Output message. """ try: response = client.search(table=SearchTypes.USER.value, query="start_time is None", limit=1) if response.status_code == HTTPStatus.OK: return "ok" else: raise ValueError(response.status_code) except Exception as error: demisto.debug(str(error)) return f"Error: {error}" def fetch_incidents( client: Client, args: dict[str, Any], params: dict[str, Any], current_time: datetime ) -> tuple[list[dict], dict[str, Any]]: """ Retrieves findings every interval (default is 1 minute). By default it's invoked by XSOAR every minute. It will use last_run to save the time of the last incident it processed and previous incident IDs. If last_run is not provided, first_fetch_time will be used to determine when to start fetching the first time. Args: client (Client): DataBee client. args (dict[str, Any]): Command arguments from XSOAR. params (dict[str, Any]: Instance params from XSOAR. end_time (str): The current time string formated. Returns: tuple[list[dict], dict[str, Any]]: incidents: List of incidents that will be created in XSOAR. next_run: Contains information that will be used in the next run. """ end_time = current_time.strftime(DATE_FORMAT) incidents = [] first_fetch = arg_to_datetime(params.get("first_fetch")) if not first_fetch: raise ValueError("First fetch time must be specified.") max_fetch = arg_to_number(params["max_fetch"]) last_run = arg_to_datetime(demisto.getLastRun().get("time")) demisto.debug(f"fetch: last_run is: {last_run}.") start_date = last_run or first_fetch start_time = start_date.strftime(DATE_FORMAT) query = f"start_time between {start_time},{end_time} and metadata.product.name in databee" if severity := params.get("severity"): query = f"{query} and severity contains {severity}" if impact := params.get("impact"): query = f"{query} and impact contains {impact}" demisto.debug(f"fetch: Start to fetch incidents, query: {query}.") data = None offset = 0 while data is None or len(data) > 0: response = client.search( table=SearchTypes.FINDING.value, limit=(max_fetch or DEFAULT_LIMIT), query=query, offset=(offset or DEFAULT_OFFSET), ).json() count = response["count"] data = response["results"] offset += len(data) demisto.debug(f"fetch: fetched status {offset}/{count}.") next_run = start_date for finding in data: time = arg_to_datetime(finding["time"]) incidents.append( { "name": str(finding["id"]), "occurred": time.strftime(XSOAR_DATE_FORMAT) if time else None, "rawJSON": json.dumps(finding), } ) if time and time > next_run: next_run = time new_last_run = (current_time).strftime(XSOAR_DATE_FORMAT) demisto.debug(f"fetch: Update last run time to {new_last_run}.") demisto.debug(f"fetch: Fetched {len(incidents)} incidents.") return incidents, {"time": new_last_run} """ HELPER COMMANDS """ def normalize_finding(data: dict[str, Any], additional_context: list[AdditionalContext]): process: dict[str, Any] = data.get("process", {}) normalize_data = { "device_id": data.get("device_id"), "user_id": data.get("user_id"), "activity_id": data.get("activity_id"), "activity_name": data.get("activity_name"), "Analytic": { "category": dict_safe_get(data, ["analytic", "category"]), "desc": dict_safe_get(data, ["analytic", "desc"]), "name": dict_safe_get(data, ["analytic", "name"]), "type": dict_safe_get(data, ["analytic", "type"]), "uid": dict_safe_get(data, ["analytic", "uid"]), }, "Attack": [ { "Tactic": [ { "id": tactic.get("id"), "name": tactic.get("name"), "uid": tactic.get("uid"), } for tactic in attack.get("tactics", []) ], "Technique": { "id": dict_safe_get(attack, ["technique", "id"]), "name": dict_safe_get(attack, ["technique", "name"]), "uid": dict_safe_get(attack, ["technique", "uid"]), }, } for attack in data.get("attacks", []) ], "category_name": data.get("category_name"), "CisCsc": [ { "control": value.get("control"), "id": value.get("id"), "version": value.get("version"), } for value in data.get("cis_csc", []) ], "class_name": data.get("class_name"), "confidence": data.get("confidence"), "data_source": data.get("data_sources", []), "Device": { "ip": dict_safe_get(data, ["device", "ip"]), "mac": dict_safe_get(data, ["device", "mac"]), "hostname": dict_safe_get(data, ["device", "hostname"]), "os": dict_safe_get(data, ["device", "os"]), }, "duration": data.get("duration"), "end_time": data.get("end_time"), "Evidence": (data.get("evidence", {}) if AdditionalContext.evidence in additional_context else {}), "Finding": { "created_time": dict_safe_get(data, ["finding", "created_time"]), "desc": dict_safe_get(data, ["finding", "desc"]), "first_seen_time": dict_safe_get(data, ["finding", "first_seen_time"]), "last_seen_time": dict_safe_get(data, ["finding", "last_seen_time"]), "modified_time": dict_safe_get(data, ["finding", "modified_time"]), "product_uid": dict_safe_get(data, ["finding", "product_uid"]), "RelatedEvent": ( dict_safe_get(data, ["finding", "related_events"]) if AdditionalContext.related_event in additional_context else None ), "Remediation": ( dict_safe_get(data, ["finding", "remediation"]) if AdditionalContext.remediation in additional_context else None ), "src_url": dict_safe_get(data, ["finding", "src_url"]), "supporting_data": dict_safe_get(data, ["finding", "supporting_data"]), "title": dict_safe_get(data, ["finding", "title"]), "types_": dict_safe_get(data, ["finding", "types_"]), "uid": dict_safe_get(data, ["finding", "uid"]), }, "id": data.get("id"), "impact": data.get("impact"), "impact_score": data.get("impact_score"), "KillChain": data.get("kill_chain", {}), "message": data.get("message"), "Metadata": (data.get("metadata") if AdditionalContext.metadata in additional_context else {}), "Observable": ( [ { "name": ob.get("name"), "Reputation": ob.get("reputation"), "type": ob.get("type"), "value": ob.get("value"), } for ob in data.get("observables", []) ] if AdditionalContext.observable not in additional_context else None ), "Process": ( { "cmd_line": process.get("cmd_line"), "container": process.get("container"), "created_time": process.get("created_time"), "File": { "company_name": dict_safe_get(process, ["file", "company_name"]), "desc": dict_safe_get(process, ["file", "desc"]), "Hashes": [ { "algorithm": hash.get("algorithm"), "fingerprint_value": hash.get("fingerprint_value"), "value": hash.get("value"), } for hash in dict_safe_get(process, ["file", "hashes"], []) ], "is_system": dict_safe_get(process, ["file", "is_system"]), "md5": dict_safe_get(process, ["file", "md5"]), "mime_type": dict_safe_get(process, ["file", "mime_type"]), "modified_time": dict_safe_get(process, ["file", "modified_time"]), "name": dict_safe_get(process, ["file", "name"]), "owner": dict_safe_get(process, ["file", "owner"]), "parent_folder": dict_safe_get(process, ["file", "parent_folder"]), "path": dict_safe_get(process, ["file", "path"]), "security_descriptor": dict_safe_get(process, ["file", "security_descriptor"]), "sha1": dict_safe_get(process, ["file", "sha1"]), "sha256": dict_safe_get(process, ["file", "sha256"]), "sha512": dict_safe_get(process, ["file", "sha512"]), "signature": dict_safe_get(process, ["file", "signature"]), "size": dict_safe_get(process, ["file", "size"]), "type": dict_safe_get(process, ["file", "type"]), "xattributes": dict_safe_get(process, ["file", "xattributes"]), }, "name": process.get("name"), "namespace_pid": process.get("namespace_pid"), "parent_process": process.get("parent_process"), "pid": process.get("pid"), "sandbox": process.get("sandbox"), "user": process.get("user"), } if AdditionalContext.process in additional_context else {} ), "risk_level": data.get("risk_level"), "risk_score": data.get("risk_score"), "severity": data.get("severity"), "start_time": data.get("start_time"), "state": data.get("state"), "status": data.get("status"), "status_detail": data.get("status_detail"), "time": data.get("time"), "type_name": data.get("type_name"), "User": data.get("user", {}), } return normalize_data def main() -> None: params: dict[str, Any] = demisto.params() args: dict[str, Any] = demisto.args() base_url = params["url"] username = dict_safe_get(params, ["credentials", "identifier"]) password = dict_safe_get(params, ["credentials", "password"]) insecure: bool = not params.get("insecure", False) proxy = argToBoolean(params.get("proxy", "")) command = demisto.command() demisto.debug(f"The command being called is {command}.") search_types: dict[str, SearchConfiguration] = { "databee-user-search": SEARCH_CONFIGURATIONS[SearchTypes.USER], "databee-device-search": SEARCH_CONFIGURATIONS[SearchTypes.DEVICE], "databee-finding-search": SEARCH_CONFIGURATIONS[SearchTypes.FINDING], } try: client: Client = Client( base_url=base_url, username=username, password=password, verify=insecure, proxy=proxy, ) if command == "test-module": return_results(test_module(client)) elif command in search_types: return_results(search_command(client, args, search_types[command], params.get("additional_context", []))) elif command == "fetch-incidents": incidents, last_run = fetch_incidents( client=client, args=args, params=params, current_time=datetime.now(), ) demisto.setLastRun(last_run) demisto.incidents(incidents) elif command == "endpoint": return_results(get_endpoint_command(client, args)) else: raise NotImplementedError(f"{command} command is not implemented.") except Exception as e: return_error(str(e)) if __name__ in ["__main__", "builtin", "builtins"]: main()