-
Notifications
You must be signed in to change notification settings - Fork 379
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1256 from deepanshu-eiq/eiq-analyser
Added EclecticIQ Analyser
- Loading branch information
Showing
7 changed files
with
255 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
{ | ||
"name": "EclecticIQ_SearchObservable", | ||
"author": "BW", | ||
"license": "AGPL-V3", | ||
"url": "https://github.com/TheHive-Project/Cortex-Analyzers/", | ||
"version": "2.0", | ||
"description": "Query EclecticIQ Intelligence Center for a specific observable.", | ||
"dataTypeList": [ | ||
"domain", | ||
"ip", | ||
"url", | ||
"fqdn", | ||
"uri_path", | ||
"user-agent", | ||
"hash", | ||
"mail", | ||
"mail_subject", | ||
"registry", | ||
"regexp", | ||
"other", | ||
"filename" | ||
], | ||
"config": { | ||
"service": "search_observable" | ||
}, | ||
"baseConfig": "EclecticIQ", | ||
"command": "EclecticIQ/eclecticiq.py", | ||
"configurationItems": [ | ||
{ | ||
"name": "name", | ||
"description": "Name of EclecticIQ instance", | ||
"multi": false, | ||
"required": false, | ||
"type": "string" | ||
}, | ||
{ | ||
"name": "url", | ||
"description": "URL of EclecticIQ instance", | ||
"type": "string", | ||
"multi": false, | ||
"required": true | ||
}, | ||
{ | ||
"name": "key", | ||
"description": "API key for EclecticIQ instance", | ||
"type": "string", | ||
"multi": false, | ||
"required": true | ||
}, | ||
{ | ||
"name": "cert_check", | ||
"description": "Verify server certificate", | ||
"type": "boolean", | ||
"multi": false, | ||
"required": true, | ||
"defaultValue": true | ||
} | ||
], | ||
"registration_required": true, | ||
"subscription_required": true, | ||
"free_subscription": false, | ||
"service_homepage": "https://www.eclecticiq.com", | ||
"service_logo": { "path": "assets/logo.png", "caption": "logo" }, | ||
"screenshots": [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[EclecticIQ](https://www.eclecticiq.com/) is a cyber threat intelligence platform which provides aggregation and analysis capabilities for threat intelligence data and integration with organization assets. | ||
|
||
The analyzer comes in one flavor to look for an observable in the platform and return any parent entities and their context. | ||
|
||
- EclecticIQ\_**SearchObservable**: returns entity data for a specific observable | ||
|
||
#### Requirements | ||
|
||
The EclecticIQ analyzer requires you to have access to an [EclecticIQ Intelligence Center](https://www.eclecticiq.com/) instance. | ||
|
||
Three parameters are required for each instance to make the analyzer work: | ||
|
||
- `url` : URL of the instance, e.g. "https://intel-platform.local" | ||
- `key` : API Key for a user of the EclecticIQ Intelligence Center instance |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
#!/usr/bin/env python3 | ||
import typing as tp | ||
|
||
import requests | ||
|
||
from cortexutils.analyzer import Analyzer | ||
|
||
|
||
class EclecticIQAnalyzer(Analyzer): | ||
"""Searches for given Observables in configured EclecticIQ instance. | ||
All standard Cortex data types are supported.""" | ||
|
||
def __init__(self): | ||
Analyzer.__init__(self) | ||
|
||
self.service = self.get_param("config.service", default="search_observable") | ||
|
||
self.name = self.get_param( | ||
"config.name", message="No EclecticIQ instance name given." | ||
) | ||
self.url = self.get_param("config.url", message="No EclecticIQ url given.") | ||
self.key = self.get_param("config.key", message="No EclecticIQ api key given.") | ||
self.data = self.get_param("data", message="Data is missing") | ||
|
||
if self.get_param("config.cert_check", True): | ||
self.ssl = self.get_param("config.cert_path", True) | ||
else: | ||
self.ssl = False | ||
|
||
self.session = requests.Session() | ||
self.session.verify = self.ssl | ||
self.session.proxies = self.get_param("config.proxy") | ||
self.session.headers.update( | ||
{"Accept": "application/json", "Authorization": f"Bearer {self.key}"} | ||
) | ||
|
||
def summary(self, raw): | ||
level = "info" | ||
namespace = "EIQ" | ||
predicate = "API" | ||
found = len(raw["results"].get("entities", [])) | ||
value = f"Found {found} entities" if found > 0 else "Not found" | ||
taxonomy = self.build_taxonomy(level, namespace, predicate, value) | ||
return {"taxonomies": [taxonomy]} | ||
|
||
def get_source(self, url): | ||
response = self.session.get(url) | ||
return response.json()["data"]["name"] | ||
|
||
@staticmethod | ||
def get_confidence(data): | ||
confidence = data.get("confidence", None) | ||
if isinstance(confidence, dict): | ||
confidence = confidence.get("value") | ||
return confidence | ||
|
||
def run(self): | ||
""" | ||
Query EclecticIQ instance for data by querying observable for | ||
observable id and then querying entities endpoint for parent entities | ||
Return dict response to cortex | ||
""" | ||
|
||
results = { | ||
"name": self.name, | ||
"url": self.url, | ||
"obs_value": self.data, | ||
} | ||
obs_id = self.add_observable_info(results) | ||
if not obs_id: | ||
# exit early for no data | ||
return self.report({}) | ||
|
||
entities_info = self.get_entities_info(obs_id) | ||
if not entities_info: | ||
# exit early for no data | ||
return self.report({}) | ||
|
||
results["count"] = entities_info["count"] | ||
results["entities"] = [] | ||
for entity in entities_info["data"]: | ||
source_name = self.get_source(entity["sources"][0]) | ||
entity_data = entity.get("data", {}) | ||
results["entities"].append( | ||
{ | ||
"id": entity["id"], | ||
"title": entity_data.get("title"), | ||
"type": entity_data.get("type"), | ||
"confidence": self.get_confidence(entity_data), | ||
"tags": entity.get("meta", {}).get("tags"), | ||
"timestamp": entity.get("meta", {}).get( | ||
"estimated_threat_start_time" | ||
), | ||
"source_name": source_name, | ||
} | ||
) | ||
|
||
self.report({"results": results}) | ||
|
||
def add_observable_info(self, results: dict) -> tp.Optional[str]: | ||
url = self.url + "/api/v2/observables" # set observable url | ||
params = {"filter[value]": self.data} # use data in filter param | ||
response = self.session.get(url, params=params) | ||
if not response.json().get("count"): | ||
return None | ||
|
||
data = response.json()["data"] | ||
results["obs_type"] = data[0]["type"] | ||
results["obs_score"] = data[0].get("meta", {}).get("maliciousness") | ||
return data[0]["id"] | ||
|
||
def get_entities_info(self, obs_id: str) -> tp.Optional[dict]: | ||
url = self.url + "/api/v2/entities" # set entity url | ||
params = {"filter[observables]": obs_id} # use observable id in filter param | ||
|
||
response = self.session.get(url, params=params) | ||
response_json = response.json() | ||
|
||
if not response_json.get("count"): | ||
return None | ||
|
||
return response_json | ||
|
||
|
||
if __name__ == "__main__": | ||
EclecticIQAnalyzer().run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
cortexutils | ||
requests |
40 changes: 40 additions & 0 deletions
40
thehive-templates/EclecticIQ_SearchObservable_1_0/long.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<div class="panel panel-info" ng-if="!content.results">No Data</div> | ||
|
||
<div class="panel panel-info" ng-repeat="res in content.results.entities"> | ||
<div class="panel-heading">{{res.type}} - {{res.title}}</div> | ||
<div class="panel-body"> | ||
<dl class="dl-horizontal"> | ||
<dt>ID:</dt> | ||
<dd> | ||
<a target="_blank" href="{{content.results.url}}/entity/{{res.id}}" | ||
>{{res.type}}--{{res.id}}</a | ||
> | ||
</dd> | ||
</dl> | ||
<dl class="dl-horizontal"> | ||
<dt>Entity Type:</dt> | ||
<dd>{{res.type}}</dd> | ||
</dl> | ||
<dl class="dl-horizontal"> | ||
<dt>Timestamp:</dt> | ||
<dd>{{res.timestamp}}</dd> | ||
</dl> | ||
<dl class="dl-horizontal"> | ||
<dt>Source Name:</dt> | ||
<dd>{{res.source_name}}</dd> | ||
</dl> | ||
<dl class="dl-horizontal" ng-if="res.tags.length > 0"> | ||
<dt>Tags:</dt> | ||
<dd><ul><li ng-repeat="tag in ::res.tags | orderBy:'toString()'">{{tag}}</li></ul></dd> | ||
</dl> | ||
</div> | ||
</div> | ||
|
||
|
||
<!-- General error --> | ||
<div class="panel panel-danger" ng-if="!success"> | ||
<div class="panel-heading"> | ||
<strong>{{(artifact.data || artifact.attachment.name) | fang}}</strong> | ||
</div> | ||
<div class="panel-body">{{content.errorMessage}}</div> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<span | ||
class="label" | ||
ng-repeat="t in content.taxonomies" | ||
ng-class="{'info': 'label-info', 'safe': 'label-success', 'suspicious': 'label-warning', 'malicious':'label-danger'}[t.level]" | ||
> | ||
{{t.namespace}} {{t.predicate}} {{t.value}} | ||
</span> |