Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contrib/binalyze air update #30950

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
50 changes: 41 additions & 9 deletions 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

Expand All @@ -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.

Expand All @@ -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]
Expand All @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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)

Expand All @@ -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)
Expand Down
8 changes: 4 additions & 4 deletions Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR.yml
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand Down
Expand Up @@ -15,7 +15,9 @@ You can use the integration in Automation, Playbooks, or Playground.
**Acquisition**
- !air-acquire *hostname*=\<HOSTNAMEofENDPOINT\> *profile*=\<DEFINED PROFILE\> *caseid*=\<The Case ID\>

**Defined Profiles:**
*You can use custom acquisition profiles you created in the AIR.*

**Pre-defined Profiles:**
- browsing-history
- compromise-assessment
- event-logs
Expand Down
42 changes: 33 additions & 9 deletions Packs/Binalyze/Integrations/BinalyzeAIR/BinalyzeAIR_test.py
Expand Up @@ -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:
Expand Down Expand Up @@ -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',
Expand All @@ -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)
Expand All @@ -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,
Expand All @@ -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
)
Expand Down
148 changes: 76 additions & 72 deletions 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 |