diff --git a/analyzers/BinalyzeAIR/README.md b/analyzers/BinalyzeAIR/README.md new file mode 100644 index 000000000..55c31ec8b --- /dev/null +++ b/analyzers/BinalyzeAIR/README.md @@ -0,0 +1,34 @@ +### What is Binalyze AIR? + +AIR is an "Automated Incident Response" platform that provides the complete feature set for: + +- 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, +- Enriching alerts for eliminating false positives, +- Investigating pre-cursors generated by other security products. + +#### What does this integration do? + +This responder lets you start acquisition and isolation of an endpoint with Binalyze AIR. + +##### 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: + +- Full, +- Quick, +- Memory (RAM + PageFile), +- Event Logs, +- Browsing History, +- Compromise Assessment +- And much more! + +##### Isolation + +Endpoint isolation works by terminating all connections of an endpoint and not allowing any new connections. +When an endpoint is isolated, you can still perform tasks such as Acquisition. + +For more information, please refer to [Knowledge Base](https://kb.binalyze.com/) +The program uses [Binalyze AIR API](https://www.binalyze.com) + diff --git a/analyzers/BinalyzeAIR/assets/binalyze-logo.png b/analyzers/BinalyzeAIR/assets/binalyze-logo.png new file mode 100644 index 000000000..2b5ea0189 Binary files /dev/null and b/analyzers/BinalyzeAIR/assets/binalyze-logo.png differ diff --git a/analyzers/BinalyzeAIR/binalyze.py b/analyzers/BinalyzeAIR/binalyze.py new file mode 100644 index 000000000..6b24b6cc4 --- /dev/null +++ b/analyzers/BinalyzeAIR/binalyze.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 + +import requests +from typing import Dict, Any +from cortexutils.responder import Responder + +requests.packages.urllib3.disable_warnings() + + +class BinalyzeAIR(Responder): + def __init__(self): + Responder.__init__(self) + self.air_console_url = self.get_param( + "air_console_url", None, "Binalyze AIR console URL is missing!" + ) + self.air_api_key = self.get_param( + "air_api_key", None, "Binalyze AIR API key is missing!" + ) + self.proxies = self.get_param("config.proxy", None) + + self.headers: Dict[str, Any] = { + 'Authorization': f'Bearer {self.air_api_key}', + 'User-Agent': 'Binalyze AIR', + 'Content-type': 'application/json', + 'Accept-Charset': 'UTF-8' + } + self.service = self.get_param("config.service", None, "Service Missing!") + self.hostname = self.get_param('hostname', '', None, 'Hostname is Missing!') + self.organization_id = self.get_param('organization_id', 0) + + if self.service == 'acquire': + self.profile = self.get_param('profile', '') + self.case_id = self.get_param('case_id', '') + if self.service == 'isolation': + self.hostname = self.get_param('hostname', '') + self.isolation = self.get_param('isolation', '') + + def run(self): + Responder.run(self) + if self.service == "acquire": + if self.hostname is None: + self.error(f'{self.hostname} is Empty!') + return + if self.profile is None: + self.error(f'{self.profile} is Empty!') + return + if self.profile: + try: + profile = requests.get( + f'https://{self.air_console_url}/api/public/acquisitions/profiles?filter[name]={self.profile}&filter[organizationIds]=0', + headers=self.headers, verify=False).json()['result']['entities'][0]['_id'] + self.profile = profile + except Exception as ex: + self.error(f'{self.profile} is wrong!') + return + if self.case_id is None: + self.error(f'{self.case_id} is Empty!') + return + if self.organization_id is None: + self.error(f'{self.organization_id} is Empty!') + return + + payload: Dict[str, Any] = { + "caseId": self.case_id, + "droneConfig": { + "autoPilot": False, + "enabled": False + }, + "taskConfig": { + "choice": "use-policy" + }, + "acquisitionProfileId": self.profile, + "filter": { + "name": self.hostname, + "organizationIds": [self.organization_id] + } + } + response = requests.post( + f'{self.air_console_url}/api/public/acquisitions/acquire', + headers=self.headers, + json_data=payload + ) + if response.status_code == requests.codes.ok: + self.report({'message': f'Acquisition task has been started in {self.hostname}'}) + else: + self.error( + f'Error, unable to start acquisition task. I received {response.status_code} status code from Binalyze AIR!' + ) + + if self.service == "isolate": + if self.hostname is None: + self.error(f'{self.hostname} is Empty!') + return + if self.isolation is None: + self.error(f'{self.isolation} is Empty!') + return + if self.organization_id is None: + self.error(f'{self.organization_id} is Empty!') + return + if self.isolation is True: + payload: Dict[str, Any] = { + "enabled": True, + "filter": { + "name": self.hostname, + "organizationIds": [self.organization_id] + } + } + return + if self.isolation is False: + payload: Dict[str, Any] = { + "enabled": False, + "filter": { + "name": self.hostname, + "organizationIds": [self.organization_id] + } + } + return + + response = requests.post( + f'{self.air_console_url}/api/public/endpoints/tasks/isolation', + headers=self.headers, + json_data=payload + ) + if response.status_code == requests.codes.ok: + self.report({'message': f'Isolation task has been started in {self.hostname}'}) + else: + self.error( + f'Error, unable to start isolation task. I received {response.status_code} status code from Binalyze AIR!' + ) + + def operations(self, raw): + return [self.build_operation("AddTagToArtifact", tag=f"BinalyzeAIR:{self.service}d the endpoint.")] + + +if __name__ == "__main__": + BinalyzeAIR().run() \ No newline at end of file diff --git a/analyzers/BinalyzeAIR/binalyze_air_acquisition.json b/analyzers/BinalyzeAIR/binalyze_air_acquisition.json new file mode 100644 index 000000000..50c25673e --- /dev/null +++ b/analyzers/BinalyzeAIR/binalyze_air_acquisition.json @@ -0,0 +1,55 @@ +{ + "name": "Binalyze AIR Acquisition", + "version": "1.0", + "author": "Binalyze Integration Team", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "license": "AGPL-V3", + "description": "Start an acquisition with Binalyze AIR.", + "dataTypeList": [ + "thehive:case_artifact" + ], + "command": "BinalyzeAIR/binalyze.py", + "config": { + "service": "air_acquire" + }, + "service_logo": { + "path": "assets/binalyze-logo.png", + "caption": "logo" + }, + "baseConfig": "BinalyzeAIR", + "configurationItems": [ + { + "name": "air_console_url", + "description": "Console URL", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "air_api_key", + "description": "API Key,", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "endpoint_hostname", + "description": "Endpoint Hostname", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "acquisition_name", + "description": "Acquisition name should match with the AIR console.", + "type": "string", + "multi": false, + "default": "quick", + "required": true + } + ], + "registration_required": true, + "subscription_required": true, + "free_subscription": false, + "service_homepage": "https://www.binalyze.com/air" +} diff --git a/analyzers/BinalyzeAIR/binalyze_air_isolation.json b/analyzers/BinalyzeAIR/binalyze_air_isolation.json new file mode 100644 index 000000000..e0212aa44 --- /dev/null +++ b/analyzers/BinalyzeAIR/binalyze_air_isolation.json @@ -0,0 +1,55 @@ +{ + "name": "Binalyze AIR Isolation", + "version": "1.0", + "author": "Binalyze Integration Team", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "license": "AGPL-V3", + "description": "Isolate your endpoints with Binalyze AIR.", + "dataTypeList": [ + "thehive:case_artifact" + ], + "command": "BinalyzeAIR/air.py", + "config": { + "service": "air_isolate" + }, + "service_logo": { + "path": "assets/binalyze-logo.png", + "caption": "logo" + }, + "baseConfig": "BinalyzeAIR", + "configurationItems": [ + { + "name": "air_console_url", + "description": "Console URL", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "air_api_key", + "description": "API Key,", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "endpoint_hostname", + "description": "Endpoint Hostname", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "isolation", + "description": "Isolation operation", + "type": "boolean", + "multi": false, + "default": "true", + "required": true + } + ], + "registration_required": true, + "subscription_required": true, + "free_subscription": false, + "service_homepage": "https://www.binalyze.com/air" +} diff --git a/analyzers/BinalyzeAIR/requirements.txt b/analyzers/BinalyzeAIR/requirements.txt new file mode 100644 index 000000000..a5a9cc7df --- /dev/null +++ b/analyzers/BinalyzeAIR/requirements.txt @@ -0,0 +1,2 @@ +requests>=2.31.0 +cortexutils>=2.2.0