Binalyze AIR

Collect your forensics data under 10 minutes.

Forensics & Malware Analysis · Binalyze AIR

Details

IDBinalyze AIR
ProviderBinalyze
CategoryForensics & Malware Analysis
From Version6.2.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

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 in Cortex

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 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

Configuration parameters

  • server — Binalyze AIR Server URL (required)
  • api_key — API Key (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (2)

  • binalyze-air-acquire

    Acquire evidence from an endpoint.

  • binalyze-air-isolate

    Isolate an endpoint.

import demistomock as demisto  # noqa: F401
from CommonServerPython import *  # noqa: F401
from typing import Any

import urllib3

urllib3.disable_warnings()


class Client(BaseClient):
    def test_api(self):
        return self._http_request(method="GET", url_suffix="/api/public/endpoints?filter[organizationIds]=0")

    def get_profile_id(self, profile: str, organization_id: int | None) -> 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 profile name.'
                )
            return ""

    def air_acquire(self, hostname: str, profile: str, case_id: str, organization_id: int | None) -> 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: 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.

        Create a payload with the parameters
        :return JSON response from /api/app/info endpoint
        :rtype Dict[str, Any]
        """

        payload: dict[str, Any] = {
            "caseId": case_id,
            "droneConfig": {"autoPilot": False, "enabled": False},
            "taskConfig": {"choice": "use-policy"},
            "acquisitionProfileId": self.get_profile_id(profile, organization_id),
            "filter": {"name": hostname, "organizationIds": [organization_id]},
        }
        return self._http_request(method="POST", url_suffix="/api/public/acquisitions/acquire", json_data=payload)

    def air_isolate(self, hostname: str, organization_id: int | None, 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
        :param organization_id int: Organization ID of the endpoint.

        Create a payload with the parameters
        :return JSON response from /api/public/endpoints/tasks/isolation endpoint
        :rtype Dict[str, Any]
        """

        payload: dict[Any, Any] = {"enabled": True, "filter": {"name": hostname, "organizationIds": [organization_id]}}

        if isolation == "disable":
            disable = {"enabled": False}
            payload.update(disable)

        return self._http_request(method="POST", url_suffix="/api/public/endpoints/tasks/isolation", json_data=payload)


def test_connection(client: Client) -> str:
    """Command for test-connection"""
    try:
        client.test_api()
    except DemistoException as ex:
        if "Unauthorized" in str(ex):
            return demisto.results(f"Authorization Error: Make sure API Key is correctly set.{str(ex)}")
        if "ConnectionError" in str(ex):
            return demisto.results(f"Connection Error: Test connection failed. {str(ex)}")
        else:
            raise ex
    return demisto.results("ok")


def air_acquire_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """Command handler for acquire command"""
    hostname = args.get("hostname", "")
    profile = args.get("profile", "")
    case_id = args.get("case_id", "")
    organization_id = args.get("organization_id", "")

    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,
    )

    if result.get("statusCode") == 404:
        return CommandResults(readable_output="No contex for queried hostname.")

    return CommandResults(
        outputs_prefix="BinalyzeAIR.Acquisition",
        outputs_key_field="hostname",
        outputs={"Result": result["result"], "Success": result["success"]},
        readable_output=readable_output,
    )


def air_isolate_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """Command handler isolate"""

    hostname = args.get("hostname", "")
    organization_id = args.get("organization_id", "")
    isolation = args.get("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,
    )
    if result.get("statusCode") == 404:
        return CommandResults(readable_output="No contex for queried hostname.")

    return CommandResults(
        outputs_prefix="BinalyzeAIR.Isolate",
        outputs_key_field="hostname",
        outputs={"Result": result["result"], "Success": result["success"]},
        readable_output=readable_output,
    )


""" Entrypoint """


def main() -> None:  # pragma: no cover
    api_key: str = demisto.params().get("api_key")
    base_url: str = demisto.params()["server"]
    verify_certificate: bool = not demisto.params().get("insecure", False)
    proxy: bool = demisto.params().get("proxy", False)
    command: str = demisto.command()
    args: dict[str, Any] = demisto.args()
    headers: dict[str, Any] = {
        "Authorization": f"Bearer {api_key}",
        "User-Agent": "Binalyze AIR",
        "Content-type": "application/json",
        "Accept-Charset": "UTF-8",
    }
    try:
        demisto.debug(f"Command being called is {demisto.command()}")
        client: Client = Client(base_url=base_url, verify=verify_certificate, headers=headers, proxy=proxy, ok_codes=(404, 200))
        if command == "test-module":
            return_results(test_connection(client))
        elif command == "binalyze-air-acquire":
            return_results(air_acquire_command(client, args))
        elif command == "binalyze-air-isolate":
            return_results(air_isolate_command(client, args))

    except Exception as ex:
        demisto.error(traceback.format_exc())  # print the traceback
        return_error(f'Failed to execute "{command}". Error: {str(ex)}')


if __name__ in ("__main__", "__builtin__", "builtins"):  # pragma: no cover
    main()