diff --git a/Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR.py b/Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR.py index 25d3bf44574e..f80a474753fb 100644 --- a/Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR.py +++ b/Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR.py @@ -1,6 +1,6 @@ import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 -from typing import Dict, Any +from typing import Dict, Any, Optional import urllib3 @@ -15,11 +15,43 @@ def test_api(self): url_suffix='/api/public/endpoints?filter[organizationIds]=0' ) - def air_acquire(self, hostname: str, profile: str, case_id: str, organization_id: int) -> Dict[str, str]: + def get_profile_id(self, profile: str, organization_id: Optional[int]) -> str: + '''Gets the profile ID based on the profile name and organization ID by making a GET request to the + '/api/public/acquisitions/profiles' endpoint. + Args: + profile (str): The name of the profile to query. + organization_id (int): The organization ID associated with the profile. + Returns: + str: The profile ID obtained from the API response. + Raises: + DemistoException: If there is an error making the HTTP request or processing the API response. + ''' + preset_profiles = ["browsing-history", "compromise-assessment", "event-logs", "full", "memory-ram-pagefile", "quick"] + if profile in preset_profiles: + return profile + else: + result = self._http_request( + method='GET', + url_suffix=f'/api/public/acquisitions/profiles?filter[name]={profile}&filter[organizationIds]=' + f'{organization_id}').get("result", {}).get("entities", []) + profile_id = "" + for entity in result: + if entity.get("name") == profile: + profile_id = entity.get("_id") + if profile_id: + return profile_id + # There is no match with profile_id. + if not profile_id: + return_error(f'The acquisition profile "{profile}" cannot be found. Please ensure that you enter a valid ' + f'profile name.') + return "" + + def air_acquire(self, hostname: str, profile: str, case_id: str, organization_id: Optional[int]) -> Dict[str, Any]: ''' Makes a POST request /api/public/acquisitions/acquire endpoint to verify acquire evidence :param hostname str: endpoint hostname to start acquisition. - :param profile str: predefined 5 acquisiton profile name. + :param profile str: get the profile string makes a query, and uses profile_id for mapping correct profile. + :param case_id str: The Case ID to associate with in AIR Server. :param organization_id int: Organizsation ID of the endpoint. @@ -37,7 +69,7 @@ def air_acquire(self, hostname: str, profile: str, case_id: str, organization_id "taskConfig": { "choice": "use-policy" }, - "acquisitionProfileId": profile, + "acquisitionProfileId": self.get_profile_id(profile, organization_id), "filter": { "name": hostname, "organizationIds": [organization_id] @@ -49,7 +81,7 @@ def air_acquire(self, hostname: str, profile: str, case_id: str, organization_id json_data=payload ) - def air_isolate(self, hostname: str, organization_id: int, isolation: str) -> Dict[str, str]: + def air_isolate(self, hostname: str, organization_id: Optional[int], isolation: str) -> Dict[str, Any]: ''' Makes a POST request /api/public/acquisitions/acquire endpoint to verify acquire evidence :param hostname str: endpoint hostname to start acquisition. :param isolation str: To isolate enable, to disable isolate use disable @@ -60,7 +92,7 @@ def air_isolate(self, hostname: str, organization_id: int, isolation: str) -> Di :rtype Dict[str, Any] ''' - payload: Dict[str, Any] = { + payload: Dict[Any, Any] = { "enabled": True, "filter": { "name": hostname, @@ -100,8 +132,8 @@ def air_acquire_command(client: Client, args: Dict[str, Any]) -> CommandResults: case_id = args.get('case_id', '') organization_id = args.get('organization_id', '') - result: Dict[str, Any] = client.air_acquire(hostname, profile, case_id, organization_id) - readable_output = tableToMarkdown('Binalyze AIR Isolate Results', result, + result: Dict[str, Any] = client.air_acquire(hostname, profile, case_id, arg_to_number(organization_id)) + readable_output = tableToMarkdown('Binalyze AIR Acquisition Results', result, headers=('success', 'result', 'statusCode', 'errors'), headerTransform=string_to_table_header) @@ -126,7 +158,7 @@ def air_isolate_command(client: Client, args: Dict[str, Any]) -> CommandResults: organization_id = args.get('organization_id', '') isolation = args.get('isolation', '') - result: Dict[str, Any] = client.air_isolate(hostname, organization_id, isolation) + result: Dict[Any, Any] = client.air_isolate(hostname, arg_to_number(organization_id), isolation) readable_output = tableToMarkdown('Binalyze AIR Isolate Results', result, headers=('success', 'result', 'statusCode', 'errors'), headerTransform=string_to_table_header) diff --git a/Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR.yml b/Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR.yml index 7588a3bb5097..a6806ffaa1f4 100644 --- a/Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR.yml +++ b/Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR.yml @@ -40,7 +40,7 @@ script: - '0' - '1' - '2' - description: Organization ID of the endpoint. + description: Organization ID of the endpoint. For a custom organization ID, you can specify a custom value outside the predefined set. - name: isolation required: true auto: PREDEFINED @@ -74,7 +74,7 @@ script: - memory-ram-pagefile - quick - full - description: Acquisition profile. + description: Acquisition profile. To use a custom acquisition profile, you can specify a custom profile outside the predefined set. - name: case_id required: true description: ID for the case,e.g. C-2022-0001. @@ -85,13 +85,13 @@ script: - '0' - '1' - '2' - description: Organization ID of the endpoint. + description: Organization ID of the endpoint. For a custom organization ID, you can specify a custom value outside the predefined set. outputs: - contextPath: BinalyzeAIR.Acquire.result._id description: Acquisition unique task ID. type: string - contextPath: BinalyzeAIR.Acquire.result.name - description: Acquisiton task name. + description: Acquisition task name. type: string - contextPath: BinalyzeAIR.Acquire.result.organizationId description: Organization Id of endpoint. diff --git a/Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR_description.md b/Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR_description.md index 021f34bfb060..788121803845 100644 --- a/Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR_description.md +++ b/Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR_description.md @@ -15,7 +15,9 @@ You can use the integration in Automation, Playbooks, or Playground. **Acquisition** - !air-acquire *hostname*=\ *profile*=\ *caseid*=\ -**Defined Profiles:** +*You can use custom acquisition profiles you created in the AIR.* + +**Pre-defined Profiles:** - browsing-history - compromise-assessment - event-logs diff --git a/Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR_test.py b/Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR_test.py index 1d745ea3fa52..2b0c3a17b923 100644 --- a/Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR_test.py +++ b/Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR_test.py @@ -4,8 +4,6 @@ from CommonServerPython import * from typing import Dict, Any -MOCK_URL = 'https://nonexistent-domain.com' - def util_load_json(path): with io.open(path, mode='r', encoding='utf-8') as f: @@ -76,16 +74,40 @@ def test_api_connection_fail(requests_mock: Any) -> None: assert mocked_command_result == expected_mocked_command_result +def test_get_profile_id_preset() -> None: + from BinalyzeAIR import Client + client: Client = Client( + base_url='https://nonexistent-domain.com', + verify=False + ) + mocked_profile = "full" + result = client.get_profile_id(mocked_profile, 1) + assert result == mocked_profile + + +def test_get_profile_id_custom(requests_mock: Any) -> None: + from BinalyzeAIR import Client + mock_response = util_load_json('test_data/profile_id.json') + requests_mock.get('https://nonexistent-domain.com/api/public/acquisitions/profiles?' + 'filter[name]=profile&filter[organizationIds]=0', + json=mock_response) + client: Client = Client( + base_url='https://nonexistent-domain.com', + verify=False + ) + result = client.get_profile_id("profile", 0) + expected_mocked_profile_id = mock_response.get('result', {}).get('entities', {})[0].get('_id', None) + assert expected_mocked_profile_id == result + + def test_air_acquire_command(requests_mock: Any) -> None: from BinalyzeAIR import Client, air_acquire_command - args: Dict[str, Any] = { 'hostname': 'endpointhostname', - 'profile': 'quick', + 'profile': "quick", 'case_id': 'case_id will be here', 'organization_id': 0 } - headers: Dict[str, Any] = { 'Authorization': 'Bearer api_key', 'User-Agent': 'Binalyze AIR', @@ -95,11 +117,14 @@ def test_air_acquire_command(requests_mock: Any) -> None: mock_response = util_load_json('test_data/test_acquire_success.json') client: Client = Client( - base_url=MOCK_URL, + base_url='https://nonexistent-domain.com', verify=False, headers=headers ) - + mock_get_response = util_load_json('test_data/profile_id.json') + requests_mock.get('https://nonexistent-domain.com/api/public/acquisitions/profiles?' + 'filter[name]=profile_name&filter[organizationIds]=0', + json=mock_get_response) requests_mock.post('https://nonexistent-domain.com/api/public/acquisitions/acquire', json=mock_response) mocked_command_result: CommandResults = air_acquire_command(client, args) @@ -118,7 +143,6 @@ def test_air_acquire_command(requests_mock: Any) -> None: def test_air_isolate_command(requests_mock: Any) -> None: from BinalyzeAIR import Client, air_isolate_command - args: Dict[str, Any] = { 'hostname': 'endpointhostname', 'organization_id': 0, @@ -133,7 +157,7 @@ def test_air_isolate_command(requests_mock: Any) -> None: mock_response = util_load_json('test_data/test_isolate_success.json') client: Client = Client( - base_url=MOCK_URL, + base_url='https://nonexistent-domain.com', verify=False, headers=headers ) diff --git a/Packs/Binalyze/Integrations/BinalyzeAIR/README.md b/Packs/Binalyze/Integrations/BinalyzeAIR/README.md index 15407673dc15..bafbc1ae6e7c 100644 --- a/Packs/Binalyze/Integrations/BinalyzeAIR/README.md +++ b/Packs/Binalyze/Integrations/BinalyzeAIR/README.md @@ -1,73 +1,77 @@ -## Binalyze AIR Integration -This integration allows you to use the Binalyze AIR's isolation and evidence collecting features easily. ---- - -Collect your forensics data under 10 minutes. -This integration was integrated and tested with version 2.6.2 of Binalyze AIR - -## Configure Binalyze AIR on Cortex XSOAR - -1. Navigate to **Settings** > **Integrations** > **Servers & Services**. -2. Search for Binalyze AIR. -3. Click **Add instance** to create and configure a new integration instance. -4. Click **Test** to validate the URLs, token, and connection. - - | **Parameter** | **Description** | **Required** | - | --- | --- | --- | - | Binalyze AIR Server URL | Binalyze AIR Server URL | True | - | API Key | e.g.: api_1234567890abcdef1234567890abcdef | True | - | Trust any certificate (not secure) | | False | - | Use system proxy settings | | False | -## Commands -You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook. -After you successfully execute a command, a DBot message appears in the War Room with the command details. -### binalyze-air-isolate -*** -Isolate an endpoint - - -#### Base Command - -`binalyze-air-isolate` -#### Input - -| **Argument Name** | **Description** | **Required** | -| --- | --- | --- | -| hostname | Hostname of endpoint. | Required | -| organization_id | Organization ID of the endpoint. Possible values are: 0, 1, 2. | Required | -| isolation | To isolate use enable. Possible values are: enable, disable. | Required | - - -#### Context Output - -| **Path** | **Type** | **Description** | -| --- | --- | --- | -| BinalyzeAIR.Isolate.result._id | string | Isolation unique task ID | -| BinalyzeAIR.Isolate.result.name | string | Isolation task name | -| BinalyzeAIR.Isolate.result.organizationId | number | Organization Id of endpoint | - -### binalyze-air-acquire -*** -Acquire evidence from an endpoint - - -#### Base Command - -`binalyze-air-acquire` -#### Input - -| **Argument Name** | **Description** | **Required** | -| --- | --- | --- | -| hostname | Hostname of endpoint. | Required | -| profile | Acquisition profile. Possible values are: compromise-assessment, browsing-history, event-logs, memory-ram-pagefile, quick, full. | Required | -| case_id | ID for the case,e.g. C-2022-0001. | Required | -| organization_id | Organization ID of the endpoint. Possible values are: 0, 1, 2. | Required | - - -#### Context Output - -| **Path** | **Type** | **Description** | -| --- | --- | --- | -| BinalyzeAIR.Acquire.result._id | string | Acquisition unique task ID | -| BinalyzeAIR.Acquire.result.name | string | Acquisiton task name | +## Binalyze AIR Integration +This integration allows you to use the Binalyze AIR's isolation and evidence collecting features easily. +--- + +Collect your forensics data under 10 minutes. +This integration was integrated and tested with version 2.6.2 of Binalyze AIR + +## Configure Binalyze AIR on Cortex XSOAR + +1. Navigate to **Settings** > **Integrations** > **Servers & Services**. +2. Search for Binalyze AIR. +3. Click **Add instance** to create and configure a new integration instance. +4. Click **Test** to validate the URLs, token, and connection. + + | **Parameter** | **Description** | **Required** | + | --- | --- | --- | + | Binalyze AIR Server URL | Binalyze AIR Server URL | True | + | API Key | e.g.: api_1234567890abcdef1234567890abcdef | True | + | Trust any certificate (not secure) | | False | + | Use system proxy settings | | False | + +## Commands + +You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook. +After you successfully execute a command, a DBot message appears in the War Room with the command details. + +### binalyze-air-isolate + +*** +Isolate an endpoint + + +#### Base Command + +`binalyze-air-isolate` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| hostname | Hostname of endpoint. | Required | +| organization_id | Organization ID of the endpoint. For the use of a custom organization ID, you can specify a custom value outside the predefined set. | Required | +| isolation | To isolate use enable. Possible values are: enable, disable. | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| BinalyzeAIR.Isolate.result._id | string | Isolation unique task ID | +| BinalyzeAIR.Isolate.result.name | string | Isolation task name | +| BinalyzeAIR.Isolate.result.organizationId | number | Organization Id of endpoint | + +### binalyze-air-acquire +*** +Acquire evidence from an endpoint + + +#### Base Command + +`binalyze-air-acquire` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| --- | +| hostname | Hostname of endpoint. | Required | +| profile | Acquisition profile. To use a custom acquisition profile, you can specify a custom value outside the predefined set. Possible values are: compromise-assessment, browsing-history, event-logs, memory-ram-pagefile, quick, full. | Required | +| case_id | ID for the case,e.g. C-2022-0001. | Required | +| organization_id | Organization ID of the endpoint. For the use of a custom organization ID, you can specify a custom value outside the predefined set. | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| BinalyzeAIR.Acquire.result._id | string | Acquisition unique task ID | +| BinalyzeAIR.Acquire.result.name | string | Acquisiton task name | | BinalyzeAIR.Acquire.result.organizationId | number | Organization Id of endpoint | \ No newline at end of file diff --git a/Packs/Binalyze/Integrations/BinalyzeAIR/command_examples b/Packs/Binalyze/Integrations/BinalyzeAIR/command_examples index e107024ce41b..186f2b46d95e 100644 --- a/Packs/Binalyze/Integrations/BinalyzeAIR/command_examples +++ b/Packs/Binalyze/Integrations/BinalyzeAIR/command_examples @@ -1,15 +1,17 @@ -!binalyze-air-isolate endpoint="hostname" organization_id=0 isolation=enable - -!binalyze-air-isolate endpoint="hostname" organization_id=0 isolation=disable - -!binalyze-air-acquire endpoint="hostname" profile="quick" caseid="c-2022-0001" organization_id=0 - -!binalyze-air-acquire endpoint="hostname" profile="browsing-history" caseid="c-2022-0001" organization_id=0 - -!binalyze-air-acquire endpoint="hostname" profile="compromise-assessment" caseid="c-2022-0001" organization_id=0 - -!binalyze-air-acquire endpoint="hostname" profile="event-logs" caseid="c-2022-0001" organization_id=0 - -!binalyze-air-acquire endpoint="hostname" profile="memory-ram-pagefile" caseid="c-2022-0001" organization_id=0 - -!binalyze-air-acquire endpoint="hostname" profile="full" caseid="c-2022-0001" organization_id=0 +!binalyze-air-isolate endpoint="hostname" organization_id=0 isolation=enable + +!binalyze-air-isolate endpoint="hostname" organization_id=0 isolation=disable + +!binalyze-air-acquire endpoint="hostname" profile="quick" caseid="c-2022-0001" organization_id=0 + +!binalyze-air-acquire endpoint="hostname" profile="browsing-history" caseid="c-2022-0001" organization_id=0 + +!binalyze-air-acquire endpoint="hostname" profile="compromise-assessment" caseid="c-2022-0001" organization_id=0 + +!binalyze-air-acquire endpoint="hostname" profile="event-logs" caseid="c-2022-0001" organization_id=0 + +!binalyze-air-acquire endpoint="hostname" profile="memory-ram-pagefile" caseid="c-2022-0001" organization_id=0 + +!binalyze-air-acquire endpoint="hostname" profile="full" caseid="c-2022-0001" organization_id=0 + +!binalyze-air-acquire endpoint="hostname" profile="custom_profile" caseid="c-2022-0001" organization_id=0 diff --git a/Packs/Binalyze/Integrations/BinalyzeAIR/test_data/profile_id.json b/Packs/Binalyze/Integrations/BinalyzeAIR/test_data/profile_id.json new file mode 100644 index 000000000000..c4f827f356ac --- /dev/null +++ b/Packs/Binalyze/Integrations/BinalyzeAIR/test_data/profile_id.json @@ -0,0 +1,20 @@ +{ + "success": true, + "result": { + "entities": [ + { + "_id": "RANDOMSTRINGHERE", + "name": "profile", + "organizationIds": [], + "averageTime": 1, + "createdAt": "2012-12-12T12:12:12.122Z", + "createdBy": "username@user.com", + "lastUsedAt": "2012-12-12T112:12:12.917Z", + "lastUsedBy": "someone", + "deletable": true + } + ] + }, + "statusCode": 200, + "errors": [] +} \ No newline at end of file diff --git a/Packs/Binalyze/README.md b/Packs/Binalyze/README.md index 60b849ecc792..f183deea8737 100644 --- a/Packs/Binalyze/README.md +++ b/Packs/Binalyze/README.md @@ -2,7 +2,7 @@ AIR is an "Automated Incident Response" platform that provides the complete feature set for: -- Remotely collecting 150+ evidence types in minutes, +- Remotely collecting 300+ evidence types in minutes, - Capturing the "Forensic State" of an endpoint as a well-organized HTML/JSON report, - Performing triage on thousands of endpoints using YARA, - Integrating with SIEM/SOAR/EDR products for automating the response phase IR, @@ -15,14 +15,16 @@ You can use two features of Binalyze AIR within CORTEX XSoar: **1. Acquisition** -One of the core features of AIR is collecting evidence remotely. This feature is made possible by "Acquisition Profiles," a group of different evidence categories. With this integration, you can use following profiles: +One of the core features of AIR is collecting evidence remotely. This feature is made possible by "Acquisition Profiles," a group of different evidence categories. Using the AIR's UI, you can create, update, and delete custom Acquisition Profiles tailored to your unique needs. Specify the evidence categories, settings, and parameters relevant to your investigation. +With this integration, you can use your custom profiles as well as following preset profiles: - Full, - Quick, - Memory (RAM + PageFile), - Event Logs, - Browsing History, -- Compromise Assesment. +- Compromise Assessment. + **2. Isolation** diff --git a/Packs/Binalyze/ReleaseNotes/1_1_0.md b/Packs/Binalyze/ReleaseNotes/1_1_0.md new file mode 100644 index 000000000000..5f3fba62e322 --- /dev/null +++ b/Packs/Binalyze/ReleaseNotes/1_1_0.md @@ -0,0 +1,4 @@ +#### Integrations +##### Binalyze AIR +- Added support for all acquisition profiles. +- Typos fixed and documentation updated accordingly. \ No newline at end of file diff --git a/Packs/Binalyze/pack_metadata.json b/Packs/Binalyze/pack_metadata.json index e56bcb306bcb..b0967c301f58 100644 --- a/Packs/Binalyze/pack_metadata.json +++ b/Packs/Binalyze/pack_metadata.json @@ -1,8 +1,8 @@ { "name": "Binalyze AIR", - "description": "Collect over 150 different types of evidence under 10 minutes.", + "description": "Collect over 300 different types of evidence under 10 minutes.", "support": "partner", - "currentVersion": "1.0.17", + "currentVersion": "1.1.0", "author": "Binalyze Integration Team", "url": "https://kb.binalyze.com/air/integrations/cortex-xsoar-integration", "email": "support@binalyze.com",