Skip to content

Commit

Permalink
Added SoltraEdge Analyzer
Browse files Browse the repository at this point in the history
  • Loading branch information
michael committed Jun 4, 2018
1 parent 13778d7 commit 769e927
Show file tree
Hide file tree
Showing 5 changed files with 339 additions and 0 deletions.
47 changes: 47 additions & 0 deletions analyzers/SoltraEdge/Soltra_search.json
@@ -0,0 +1,47 @@
{
"name": "SoltraEdge",
"version": "1.0",
"author": "Michael Stensrud, Nordic Financial CERT",
"url": "http://soltra.com/en/",
"license" : "AGPL-V3",
"description": "Query against Soltra Edge.",
"dataTypeList": ["domain", "ip", "url", "fqdn", "uri_path","user-agent", "hash", "email", "mail", "mail_subject" , "registry", "regexp", "other", "filename"],
"command": "SoltraEdge/soltra.py",
"baseConfig": "Soltra_Edge",
"config": {
"check_tlp": true,
"service": "search"
},
"configurationItems": [
{
"name": "token",
"description": "Define the Token Key",
"type": "string",
"multi": false,
"required": true
},
{
"name": "username",
"description": "Define the Username",
"type": "string",
"multi": false,
"required": true
},
{
"name": "base_url",
"description": "Base API URL for Soltra Edge Server. (Example: https://test.soltra.com/api/stix)",
"type": "string",
"multi": false,
"required": true,
"defaultValue": "https://feed.yourdomain./api/stix"
},
{
"name": "verify_ssl",
"description": "Verify server certificate",
"type": "boolean",
"multi": false,
"required": true,
"defaultValue": true
}
]
}
4 changes: 4 additions & 0 deletions analyzers/SoltraEdge/requirements.txt
@@ -0,0 +1,4 @@
json
base64
requests
cortexutils
166 changes: 166 additions & 0 deletions analyzers/SoltraEdge/soltra.py
@@ -0,0 +1,166 @@
#!/usr/bin/env python
# encoding: utf-8

import json
import requests
from base64 import b64encode
from cortexutils.analyzer import Analyzer

class SoltraEdge(Analyzer):

def __init__(self):
Analyzer.__init__(self)

self.base_url = self.get_param("config.base_url", None)
self.token = self.get_param("config.token", None)
self.username = self.get_param("config.username", None)
self.service = self.get_param('config.service', None, 'Service parameter is missing')
self.verify_ssl = self.get_param("config.verify_ssl", True)

self.headers = {
"User-Agent": "Cortex 2",
"Accept": "application/json",
"Authorization": self.auth_string()
}


def auth_string(self):
'''
Authenticate based on username and token which is base64-encoded
'''

username_token = '{username}:{token}'.format(username=self.username, token=self.token)
b64encoded_string = b64encode(username_token)
auth_string = 'Token {b64}'.format(b64=b64encoded_string)

return auth_string


def api_overview(self, query):
'''
Request to SoltraEdge API
'''

url = "{0}/?q={1}&format=json".format(self.base_url, query)
response = requests.get(url, headers=self.headers, verify=self.verify_ssl)

if response.status_code == 200:
return response.json()
else:
self.error('Received status code: {0} from Soltra Server. Content:\n{1}'.format(
response.status_code, response.text)
)


def api_related(self, query):
'''
Find related objects through SoltraEdge API
'''

url = "{0}/{1}/related/?format=json".format(self.base_url, query)
response = requests.get(url, headers=self.headers, verify=self.verify_ssl)

if response.status_code == 200:
return response.json()
else:
self.error('Received status code: {0} from Soltra Server. Content:\n{1}'.format(
response.status_code, response.text)
)


def tlp_classifiers(self, name_tlp, val_tlp):
'''
Classifier between Cortex and Soltra.
Soltra uses name-TLP, and Cortex "value-TLP"
'''

classifier = {
"WHITE": 0,
"GREEN": 1,
"AMBER": 2,
"RED": 3
}

valid = True

if classifier[name_tlp] > val_tlp:
valid = False

return valid


def pop_object(self, element):
'''
Pop the object element if the object contains an higher TLP then allowed.
'''

redacted_text = "Redacted. Object contained TLP value higher than allowed."

element['id'] = ''
element['url'] = ''
element['type'] = ''
element['tags'] = []
element['etlp'] = None
element['title'] = redacted_text
element['tlpColor'] = element['tlpColor']
element['uploaded_on'] = ''
element['uploaded_by'] = ''
element['description'] = redacted_text
element['children_types'] = []

element['summary']['type'] = ''
element['summary']['value'] = ''
element['summary']['title'] = redacted_text
element['summary']['description'] = redacted_text

return element


def run(self):

result = {}
content = self.getData()

if self.service == "search":
self.predicate = "Search"
self.level = "suspicious"

response = self.api_overview(content)

for obj in response['hits']:
name_tlp = obj['tlpColor'].upper()
if not self.tlp_classifiers(name_tlp, self.tlp):
self.pop_object(obj)
else:
# Add object relations if found
obj['object_related'] = self.api_related(obj['id'])

else:
# Did not match any services
self.error("Invalid service")

self.response = response

result["findings"] = response
result["findings"]['soltra_host'] = self.base_url.split("/api/stix")[0]

return self.report(result)


def summary(self, raw_report):

return {
"estimate": self.response["estimate"],
"took": self.response["took"],
"taxonomies": [{
"namespace": "Soltra",
"predicate": self.predicate,
"value": self.response['estimate'],
"level": self.level
}]
}



if __name__ == '__main__':
SoltraEdge().run()
119 changes: 119 additions & 0 deletions thehive-templates/SoltraEdge_1_0/long.html
@@ -0,0 +1,119 @@


<div class="panel panel-info">
<style>
table {
table-layout:fixed;
width:100%;
word-break: break-all;
}
</style>


<div class="panel panel-info" ng-if="content.findings.count !== 0">
<div class="panel-heading">
<strong>Soltra Edge</strong>
</div>
<div class="panel-body">

<table class="table table-hover">

<tr>
<th style="width:10%;">Source</th>
<th style="width:8%;">TLP</th>
<th style="width:30%;">Soltra ID</th>
<th style="width:10%;">Relations</th>
<th style="width:42%;">Description</th>

</tr>

<tr ng-repeat="(key, res) in content.findings.hits">
<td>{{res.id.split(":")[0]}}</td>
<td>
<span class="label" ng-class="{'WHITE': 'label-info', 'GREEN': 'label-success', 'AMBER': 'label-warning', 'RED':'label-danger'}[res.tlpColor]">
{{res.tlpColor}}
</span>
</td>
<td>
<span>
<i class="fa fa-search"></i>
<a ng-href="{{content.findings.soltra_host}}/object/{{res.id}}/" target="_blank"></a>
{{res.id}}
</a>
</span>
</td>
<td>
<div ng-if="res.object_related.length !== 0">

<button id=relationsButton{{key}} class="btn btn-info" onClick="open_modal(this.id)">Show relations</button>

<div class="modal fade" id="relationsModal{{key}}" tabindex="-1" role="dialog" aria-labelledby="modalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title" id="modalLabel">{{res.id}}</h3>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">

<div class="panel panel-info">
<div class="panel-heading">
<strong>Relations Found</strong>
</div>
<div class="panel-body">
<table class="table table-hover">

<tr ng-repeat="relation in res.object_related">
<td>
<span>
<i class="fa fa-search"></i>
<a ng-href="{{content.findings.soltra_host}}/object/{{relation.id}}/" target="_blank">
{{relation.id}}
</a>
</span>
</td>
</tr>
</table>
</div>
</div>

</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>


</div>
<div ng-if="res.object_related.length === 0">
<p>None</p>
</div>
</td>
<td colspan="2">
{{res.description}}
</td>
</tr>

</table>
</div>
</div>

</div>


<script type="text/javascript">

function open_modal(button_id){


var modalID = '#relationsModal'+button_id.split("relationsButton")[1];

console.log(modalID);
$(modalID).modal('show');
}

</script>
3 changes: 3 additions & 0 deletions thehive-templates/SoltraEdge_1_0/short.html
@@ -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 769e927

Please sign in to comment.