Skip to content

Commit

Permalink
Merge branch 'feat/sekoia_analyzers' of https://github.com/SEKOIA-IO/…
Browse files Browse the repository at this point in the history
…Cortex-Analyzers into SEKOIA-IO-feat/sekoia_analyzers
  • Loading branch information
jeromeleonard committed Aug 5, 2020
2 parents 2f71ce9 + 2223adb commit ab567a2
Show file tree
Hide file tree
Showing 12 changed files with 345 additions and 0 deletions.
50 changes: 50 additions & 0 deletions analyzers/SEKOIAIntelligenceCenter/IntelligenceCenter_Context.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"name": "SEKOIAIntelligenceCenter_Context",
"version": "1.0",
"author": "SEKOIA",
"url": "https://github.com/TheHive-Project/Cortex-Analyzers",
"license": "AGPL-V3",
"description": "Query the Intelligence Center to retrieve the context of an observable",
"dataTypeList": [
"domain",
"fqdn",
"url",
"hash",
"ip"
],
"command": "SEKOIAIntelligenceCenter/sekoia_intelligence_center_analyzer.py",
"baseConfig": "SEKOIAIntelligenceCenter",
"config": {
"service": "context"
},
"configurationItems": [
{
"name": "api_key",
"description": "Intelligence center API key",
"type": "string",
"multi": false,
"required": true
},
{
"name": "url",
"description": "Intelligence center URL",
"type": "string",
"multi": false,
"required": false
}
],
"registration_required": true,
"subscription_required": true,
"free_subscription": false,
"service_homepage": "https://sekoia.io/",
"service_logo": {
"path": "assets/sekoia_logo.png",
"caption": "logo"
},
"screenshots": [
{
"path": "assets/SEKOIAIntelligenceCenter_Context_long.png",
"caption": "SEKOIAIntelligenceCenter_Context long report sample"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"name": "SEKOIAIntelligenceCenter_Indicators",
"version": "1.0",
"author": "SEKOIA",
"url": "https://github.com/TheHive-Project/Cortex-Analyzers",
"license": "AGPL-V3",
"description": "Query the Intelligence Center to retrieve indicators",
"dataTypeList": [
"domain",
"fqdn",
"url",
"hash",
"ip"
],
"command": "SEKOIAIntelligenceCenter/sekoia_intelligence_center_analyzer.py",
"baseConfig": "SEKOIAIntelligenceCenter",
"config": {
"service": "indicators"
},
"configurationItems": [
{
"name": "api_key",
"description": "Intelligence center API key",
"type": "string",
"multi": false,
"required": true
},
{
"name": "url",
"description": "Intelligence center URL",
"type": "string",
"multi": false,
"required": false
}
],
"registration_required": true,
"subscription_required": true,
"free_subscription": false,
"service_homepage": "https://sekoia.io/",
"service_logo": {
"path": "assets/sekoia_logo.png",
"caption": "logo"
},
"screenshots": [
{
"path": "assets/SEKOIAIntelligenceCenter_Indicators_long.png",
"caption": "SEKOIAIntelligenceCenter_Indicators long report sample"
}
]
}
14 changes: 14 additions & 0 deletions analyzers/SEKOIAIntelligenceCenter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Get more context around domain names, IP adresses, urls and file hashes using the
[SEKOIA.IO](https://sekoia.io) Intelligence Database.

The analyzer comes in 2 flavors:

- SEKOIAIntelligenceCenter_**Indicators**: Find indicators matching the observable provided.
- SEKOIAIntelligenceCenter_**Context**: Get indicators and their context for the observable provided.

#### Requirements
You need an active [SEKOIA.IO Intelligence Center](https://sekoia.io/) subscription to use the analyzer:

- Provide your API key as a value for the `api_key` parameter.

To get any help don't hesitate to contact [email protected].
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions analyzers/SEKOIAIntelligenceCenter/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cortexutils
requests
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/usr/bin/env python3
# encoding: utf-8
from ipaddress import ip_address

import requests
from cortexutils.analyzer import Analyzer
from requests import HTTPError


class IntelligenceCenterAnalyzer(Analyzer):

TYPES_MAPPING = {
"url": "url",
"domain": "domain-name",
"fqdn": "domain-name",
"hash": "file",
"ip": ["ipv4-addr", "ipv6-addr"],
}

DEFAULT_URL = "https://app.sekoia.io"

@property
def url(self):
path = ""
if self.service == "context":
path = "/context"
return "{}/api/v2/inthreat/indicators{}".format(self.base_url, path)

def __init__(self):
Analyzer.__init__(self)
self.service = self.get_param("config.service", None, "Service parameter is missing")
self.api_key = self.get_param("config.api_key", None, "Missing Api Key")
self.base_url = self.get_param("config.url", self.DEFAULT_URL)
if not self.base_url:
# Case of empty string
self.base_url = self.DEFAULT_URL

def run(self):
ic_type = self.get_ic_type()
value = self.get_data()
results = self.perform_request({"type": ic_type, "value": value})
self.report({"results": results})

def summary(self, raw):
count = len(raw.get("results", []))
value = "{} result{}".format(count, "s" if count > 1 else "")
if count == 0:
level = "safe"
else:
level = "malicious"

return {"taxonomies": [self.build_taxonomy(level, "SEKOIA", self.service, value)]}

def get_ic_type(self):
if self.data_type not in self.TYPES_MAPPING.keys():
self.error("Invalid data type")
if self.data_type != "ip":
return self.TYPES_MAPPING[self.data_type]

# Check what kind of IP it is.
try:
address = ip_address(self.get_data())
return "ipv4-addr" if address.version == 4 else "ipv6-addr"
except ValueError:
self.error("Invalid IP address")

def perform_request(self, payload):
"""
Send the request to the API.
The main error codes are handled here
"""
headers = {"Authorization": "Bearer {}".format(self.api_key)}
try:
response = requests.get(self.url, params=payload, headers=headers)
response.raise_for_status()
return response.json()["items"]
except HTTPError as ex:
if ex.response.status_code == 401:
self.error("Unauthorized to query the API. Is the API key valid ?")
if ex.response.status_code == 403:
self.error(
"Forbidden to query the API. Does the API key has the right permissions ?"
)
if ex.response.status_code == 429:
self.error("Quota exhausted.")
self.error("API returned with the error code {}".format(str(ex.response.status_code)))


if __name__ == "__main__":
IntelligenceCenterAnalyzer().run()
75 changes: 75 additions & 0 deletions thehive-templates/SEKOIAIntelligenceCenter_Context_1_0/long.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<div class="sekoia-report" ng-if="success">
<div ng-if="content.results.length === 0">
No results found
</div>
<h2 ng-if="content.results.length > 0">{{content.results.length}} Context(s)</h2>
<div ng-repeat="bundle in content.results track by 'id'">
<h4>{{bundle.id}}</h4>
<div ng-if="bundle.objects.length > 0" ng-repeat="item in bundle.objects">
<div class="panel panel-info" ng-if="item.type !== 'relationship' && item.type !== 'marking-definition'">
<div class="panel-heading">
<strong>{{item.name | fang}}</strong>
</div>
<div class="panel-body">
<div>
<dl class="dl-horizontal">
<dt>Type</dt>
<dd class="wrap">{{item.type}}</dd>
</dl>
<dl class="dl-horizontal" ng-if="item.aliases">
<dt>Aliases</dt>
<dd>
<div ng-if="item.aliases.length === 0">No aliases defined</div>
<div ng-if="item.aliases.length > 0">
<span class="label label-info" style="margin: 2px;" ng-repeat="alias in item.aliases">{{alias}}</span>
</div>
</dd>
</dl>
<dl class="dl-horizontal">
<dt>Description</dt>
<dd class="wrap">{{item.description || 'No description' }}</dd>
</dl>
<dl class="dl-horizontal" ng-if="item.type === 'indicator'">
<dt>Pattern</dt>
<dd class="wrap">{{item.pattern }}</dd>
</dl>
<dl class="dl-horizontal" ng-if="item.type === 'indicator'">
<dt>Pattern type</dt>
<dd class="wrap">{{item.pattern_type || 'stix' }}</dd>
</dl>
<dl class="dl-horizontal" ng-if="item.type === 'indicator'">
<dt>Valid from</dt>
<dd class="wrap">{{item.valid_from.split("T")[0] || 'no set' }}</dd>
</dl>
<dl class="dl-horizontal" ng-if="item.type === 'indicator'">
<dt>Valid until</dt>
<dd class="wrap">{{item.valid_until.split("T")[0] || 'no set' }}</dd>
</dl>
<dl class="dl-horizontal" ng-if="item.kill_chain_phases">
<dt>Kill chain phases</dt>
<dd>
<div ng-if="item.kill_chain_phases.length === 0">No kill chain defined</div>
<div ng-if="item.kill_chain_phases.length > 0">
<span class="label label-info" style="margin: 2px;" ng-repeat="chain in item.kill_chain_phases">{{chain.phase_name}}</span>
</div>
</dd>
</dl>
</div>
</div>
</div>
</div>
</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">
<dl class="dl-horizontal" ng-if="content.errorMessage">
<dt><i class="fa fa-warning"></i> SEKOIA: </dt>
<dd class="wrap">{{content.errorMessage}}</dd>
</dl>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<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>
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<div class="sekoia-report" ng-if="success">
<div ng-if="content.results.length === 0">
No results found
</div>
<h2 ng-if="content.results.length > 0">{{content.results.length}} Indicator(s)</h2>
<div class="panel panel-info" ng-if="content.results.length > 0" ng-repeat="indicator in content.results track by 'id'">
<div class="panel-heading">
<strong>{{indicator.name | fang}}</strong>
</div>
<div class="panel-body">
<div>
<dl class="dl-horizontal">
<dt>Description</dt>
<dd class="wrap">{{indicator.description || 'No description' }}</dd>
</dl>
<dl class="dl-horizontal">
<dt>Pattern</dt>
<dd class="wrap">{{indicator.pattern }}</dd>
</dl>
<dl class="dl-horizontal">
<dt>Pattern type</dt>
<dd class="wrap">{{indicator.pattern_type || 'stix' }}</dd>
</dl>
<dl class="dl-horizontal">
<dt>Valid from</dt>
<dd class="wrap">{{indicator.valid_from.split("T")[0] || 'no set' }}</dd>
</dl>
<dl class="dl-horizontal">
<dt>Valid until</dt>
<dd class="wrap">{{indicator.valid_until.split("T")[0] || 'no set' }}</dd>
</dl>
<dl class="dl-horizontal" ng-if="indicator.kill_chain_phases">
<dt>Kill chain phases</dt>
<dd>
<div ng-if="indicator.kill_chain_phases.length === 0">No kill chain defined</div>
<div ng-if="indicator.kill_chain_phases.length > 0">
<span class="label label-info" style="margin: 2px;" ng-repeat="chain in indicator.kill_chain_phases">{{chain.phase_name}}</span>
</div>
</dd>
</dl>
</div>
</div>
</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">
<dl class="dl-horizontal" ng-if="content.errorMessage">
<dt><i class="fa fa-warning"></i> SEKOIA: </dt>
<dd class="wrap">{{content.errorMessage}}</dd>
</dl>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<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>

0 comments on commit ab567a2

Please sign in to comment.