Aella Star Light
Aella Star Light Integration.
Data Enrichment & Threat Intelligence · Aella Star Light
Details
| ID | Aella Star Light |
|---|---|
| Provider | AellaData |
| Category | Data Enrichment & Threat Intelligence |
| From Version | 6.5.0 |
| Docker Image | demisto/python3:3.12.12.7090913 |
| Supported Modules | Agentix XSIAM |
README
Overview
Use the Aella Starlight integration to get detailed information for security events detected by Aella Breach Detection software.
This integration was integrated and tested with Aella Startlight v2.2.1.
Use cases
- Monitor security events and get event details
Periodically fetch new security events detected by Aella Starlight. Each security event will have a unique event_id, which you can pass to the |aella-get-eventcommand to get the detailed information for. You can perform a follow-up action, such as sending a notification to security staff.
Fetched Incidents Data
name: Incident name
label: "Starlight event"
aella_eid: Aella event ID
aella_event: Aella event name
event_severity: Severity of the event
Configure Aella Starlight on Cortex XSOAR
- Navigate to Settings > Integrations > Servers & Services.
- Search for Aella Star Light.
- Click Add instance to create and configure a new integration instance.
You should configure the following settings:
- Name: a textual name for the integration instance.
- Server URL (e.g. https://starlight.companyname.com:8889)
- User name
- Fetch incidents
- Incident type
- Fetching interval in minutes (default is 15, minimum is 15 )
- The specific security event to look for. Default is all events
- Security event severity threshold, between 0-100
- Trust any certificate (not secure)
- Use system proxy settings
- Click Test to validate the URLs, token, and connection.
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.
1. Get event details
Get details for a specific Startlight event.
Base Command
aella-get-event
Input
| Argument Name | Description | Required |
|---|---|---|
| event_id | Event ID from the Starlight incident | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Aella.Event.event_name | string | Event name |
| Aella.Event.severity | string | Severity score |
| Aella.Event.dstip | string | Destination IP |
| Aella.Event.srcip | string | Source IP |
| Aella.Event.tenantid | string | Tenant ID |
| Aella.Event.srcip_reputation | string | Source IP reputation |
| Aella.Event.dstip_reputation | string | Destination IP reputation |
| Aella.Event.dstip_geo | unknown | Destination IP geolocation |
| Aella.Event.srcip_geo | unknown | Source IP geolocation |
Configuration parameters
url— Server URL (e.g. https://starlight.companyname.com:8889) (required)credentials— User name (required)isFetch— Fetch incidentsincidentType— Incident typeincidentFetchInterval— Incidents Fetch Intervalfetch_interval— Fetching interval in minutes (default is 15, minimum is 15 )event_name— The specific security event to look for. Default is all eventsseverity— Security event severity threshold, between 0-100insecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (1)
-
aella-get-eventQuery the details for a specific Start Light event
import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 import requests import json import time import os from typing import Any import urllib3 from urllib3.exceptions import InsecureRequestWarning urllib3.disable_warnings(InsecureRequestWarning) if not demisto.params()["proxy"]: # Remove proxy environment variables if they exist for proxy_var in ["HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy"]: os.environ.pop(proxy_var, None) """ GLOBAL VARS """ URL = demisto.getParam("url") + "/aellaelastic" USERNAME = demisto.getParam("credentials")["identifier"] PASSWORD = demisto.getParam("credentials")["password"] FETCH_INTERVAL = demisto.getParam("fetch_interval") VALIDATE_CERT = not demisto.params().get("insecure", True) """ HELPER FUNCTIONS """ def make_rest_call(end_point, username, password, action_result, headers={}, params=None, data=None, method="get"): headers.update({"Accept": "application/json"}) headers.update({"Content-Type": "application/json"}) resp_json = None request_func = getattr(requests, method) if not request_func: action_result["status"] = f"Unsupported method {method}" return try: r = request_func( end_point, auth=(username, password), data=json.dumps(data) if data else None, headers=headers, verify=VALIDATE_CERT, params=params, ) except Exception as e: action_result["status"] = f"Server REST API exception {e}" return if r is not None: action_result["r_text"] = r.text action_result["headers"] = r.headers action_result["r_status_code"] = r.status_code try: resp_json = r.json() except Exception as e: demisto.debug(f"Error while parsing response JSON: {e}") action_result["status"] = "Json parse error {}".format(r.text.replace("{", " ").replace("}", " ")) return if 200 <= r.status_code <= 399: action_result["status"] = "Success" else: action_result["status"] = "Failed" action_result["data"] = resp_json return """ FUNCTIONS """ def fetch_incidents_command(): fetch_interval = demisto.getParam("fetch_interval") if fetch_interval is None: fetch_interval = 15 * 60 # 15 minutes else: try: fetch_interval = int(fetch_interval) * 60 if fetch_interval < 15 * 60: # Min is 15 minutes fetch_interval = 15 * 60 except ValueError as e: demisto.debug(f"Error in parsing fetch_interval: {e}") fetch_interval = 15 * 60 cur_t = time.time() checkTime = cur_t - fetch_interval event = demisto.getParam("event_name") if event is None: event = "*" score = demisto.getParam("severity") if score: try: score = int(score) if score < 0 or score > 100: score = 50 except ValueError: demisto.debug(f"Failed to convert the value of severity to an integer: {score}") score = 50 else: # Default score score = 50 index_str = "aella-ser*" query_str = f"event_name:{event} AND severity:>{score}" ts_str = str(int(checkTime * 1000)) query_json = { "query": { "bool": { "must": [ {"query_string": {"query": query_str, "analyze_wildcard": True}}, {"range": {"timestamp": {"gt": ts_str}}}, ] } } } end_point = URL + f"/{index_str}/amsg/_search" action_result: dict[Any, Any] = {} make_rest_call(end_point, USERNAME, PASSWORD, action_result, data=query_json) if action_result["status"] == "Success": demisto.info("Poll incidents ok") data = action_result.get("data") if not isinstance(data, dict): demisto.error(f"Data returned in wrong format {data}") demisto.incidents([]) return hits = data.get("hits", {}).get("hits", []) incidents = [] try: cached_event = demisto.getLastRun().get("cached_event", {}) except Exception as e: demisto.debug(f"Error while accessing the last run data: {e}") cached_event = {} new_cached_event = {} for hit in hits: source = hit.get("_source", None) if not source: continue event_name = source.get("event_name", None) try: event_severity = int(source.get("severity", None)) if event_severity > 75: severity = 3 elif event_severity > 50: severity = 2 else: severity = 1 except ValueError as e: demisto.debug(f"Error while converting the severity value to int: {e}") severity = 0 if not event_name: continue eid = hit["_id"] new_cached_event[eid] = True if cached_event.get(eid, False): continue sdi = f"{event_name}_{eid}" incident = { "name": sdi, "severity": severity, "rawJSON": json.dumps( { "name": sdi, "label": "Starlight event", "aella_eid": eid, "aella_event": event_name, "event_severity": event_severity, } ), } incidents.append(incident) demisto.info(f"Incidents is {incidents}") demisto.setLastRun({"cached_event": new_cached_event}) demisto.incidents(incidents) else: demisto.info(f"Poll incidents failed {action_result}") demisto.incidents([]) def aella_get_event_command(): demisto.info("Aella started get-event with {}".format(demisto.args()["event_id"])) event_id = demisto.args()["event_id"] query_json = {"query": {"match": {"_id": event_id}}} end_point = URL + "/{}/{}/_search".format("aella-ser*", "amsg") action_result: dict[Any, Any] = {} make_rest_call(end_point, USERNAME, PASSWORD, action_result, data=query_json) if action_result["status"] == "Success": demisto.info("Run Query is successful") response = action_result.get("data", {}) timed_out = response.get("timed_out", False) hits = response.get("hits", {}).get("hits", []) source = {} dbot_scores = [] if len(hits) == 0: demisto.info("Get event got empty result") for item in hits: index = item.get("_index", "") source = item.get("_source", {}) if index: source["_index"] = index source["timed_out"] = timed_out demisto.debug(f"This is my run_query result aellaEvent {source}") # Check url reputation url_str = source.get("url", "") if url_str: url_reputation = source.get("url_reputation", "") if url_reputation and url_reputation != "Good": dbot_score = { "Vendor": "Aella Data", "Indicator": url_str, "Type": "url", "Score": 3, "Malicious": { "Vendor": "Aella Data", "Detections": f"URL reputation {url_reputation}", "URL": url_str, }, } else: dbot_score = {"Vendor": "Aella Data", "Indicator": url_str, "Type": "url", "Malicious": None} if url_reputation is None: # Unknonw dbot_score["Score"] = 0 else: # Good dbot_score["Score"] = 1 dbot_scores.append(dbot_score) # Check src ip reputation srcip_str = source.get("srcip", "") if srcip_str: srcip_reputation = source.get("srcip_reputation", "") if srcip_reputation and srcip_reputation != "Good": dbot_score = { "Vendor": "Aella Data", "Indicator": srcip_str, "Type": "ip", "Score": 3, "Malicious": { "Vendor": "Aella Data", "Detections": f"Source IP reputation {srcip_reputation}", "IP": srcip_str, }, } else: dbot_score = {"Vendor": "Aella Data", "Indicator": srcip_str, "Type": "ip", "Malicious": None} if srcip_reputation is None: # Unknonw dbot_score["Score"] = 0 else: # Good dbot_score["Score"] = 1 dbot_scores.append(dbot_score) # Check dst ip reputation dstip_str = source.get("dstip", "") if dstip_str: dstip_reputation = source.get("dstip_reputation", "") if dstip_reputation and dstip_reputation != "Good": dbot_score = { "Vendor": "Aella Data", "Indicator": dstip_str, "Type": "ip", "Score": 3, "Malicious": { "Vendor": "Aella Data", "Detections": f"Destination IP reputation {dstip_reputation}", "IP": dstip_str, }, } else: dbot_score = {"Vendor": "Aella Data", "Indicator": dstip_str, "Type": "ip", "Malicious": None} if dstip_reputation is None: # Unknonw dbot_score["Score"] = 0 else: # Good dbot_score["Score"] = 1 dbot_scores.append(dbot_score) break demisto.results( { "Type": entryTypes["note"], "ContentsFormat": formats["json"], "Contents": source, "HumanReadable": tableToMarkdown(f"Aella Star Light Event <{event_id}>", source), "EntryContext": { "Aella.Event(val._id==obj._id)": source, "DBotScore": createContext(dbot_scores, removeNull=True), }, } ) else: demisto.info(f"Get event failed {action_result}") demisto.results(return_error("Failed to get event")) """ EXECUTION CODE """ demisto.info(f"Command is {demisto.command()}") if demisto.command() == "test-module": # This is the call made when pressing the integration test button. action_result: dict[Any, Any] = {} make_rest_call(URL + "/_cluster/health", USERNAME, PASSWORD, action_result) if action_result["status"] == "Success": demisto.results("ok") else: demisto.results("failed") if demisto.command() == "fetch-incidents": fetch_incidents_command() if demisto.command() == "aella-get-event": aella_get_event_command()