Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating to use new API #483

Merged
merged 3 commits into from
Jun 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions analyzers/SinkDB/SinkDB.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
{
"name": "SinkDB",
"author": "Nils Kuhnert, CERT-Bund",
"author": "Mark Kikta, RedLegg Cybersecurity Solutions",
"license": "AGPL-V3",
"url": "https://github.com/BSI-CERT-Bund/sinkdb-analyzer",
"version": "1.0",
"description": "Check if ip is sinkholed via sinkdb.abuse.ch",
"dataTypeList": ["ip"],
"url": "https://github.com/RedLegg/sinkdb-analyzer",
"version": "1.1",
"description": "Check if ip is sinkholed via the new sinkdb.abuse.ch HTTPS API. Original analyzer can be found at https://github.com/BSI-CERT-Bund/sinkdb-analyzer",
"dataTypeList": ["ip", "domain", "mail"],
"command": "SinkDB/sinkdb.py",
"baseConfig": "SinkDB",
"configurationItems": [
{
"name": "key",
"description": "Define the API Key",
"description": "Define the HTTPS API Key",
"type": "string",
"multi": false,
"required": true
Expand Down
95 changes: 60 additions & 35 deletions analyzers/SinkDB/sinkdb.py
Original file line number Diff line number Diff line change
@@ -1,52 +1,77 @@
#!/usr/bin/env python3
import subprocess
#!/usr/bin/env python
import json, requests, traceback

from cortexutils.analyzer import Analyzer


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

if self.data_type != 'ip':
self.error('SinkDB Analyzer only usable with ip data type.')
if self.data_type not in ['ip', 'domain', 'mail']:
self.error('SinkDB Analyzer only usable with the ip, domain, and mail data types.')

self.apikey = self.get_param('config.key', None, 'API Key needed for querying SinkDB.')
self.data = self.get_data().split('.')
self.data.reverse()
self.data = '.'.join(self.data)
self.apikey = self.get_param('config.key', None, 'HTTPS API Key needed for querying SinkDB.')
self.data = self.get_data()

def dig(self, ip):
proc = subprocess.Popen(['dig', '+short', '{}.{}.sinkdb-api.abuse.ch'.format(ip, self.apikey)],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out, err = proc.communicate()
out = out.decode('utf-8').strip('\n')
def query_db(self, indicator):

if err:
self.error('Error while calling dig: {}.'.format(err))
if self.data_type == 'ip':
return self.parse_entries(json.loads(self.do_post("api_key={}&ipv4={}".format(self.apikey, self.data)).text))

if out == '127.0.0.2':
return True
elif self.data_type == 'domain':
return self.parse_entries(json.loads(self.do_post("api_key={}&domain={}".format(self.apikey, self.data)).text))

return False
elif self.data_type == 'mail':
return self.parse_entries(json.loads(self.do_post("api_key={}&email={}".format(self.apikey, self.data)).text))

def run(self):
self.report({
"is_sinkhole": self.dig(self.data)
})
else:
raise TypeError('Error in query_db function. This error should not occur.')

def summary(self, raw):
taxonomies = []
def parse_entries(self, entries):
ret = {
"Sinkhole": [],
"Phishing": [],
"Scanner": []
}
if entries['query_status'] == 'ok':
for entry in entries['results']:
if entry['source'] == 'sinkhole':
ret['Sinkhole'].append(entry)
elif entry['source'] == 'awareness':
ret['Phishing'].append(entry)
elif entry['source'] == 'scanner':
ret['Scanner'].append(entry)
return ret
elif entries['query_status'] == 'no_results':
return ret
elif entries['query_status'] == 'invalid_ipaddress':
self.error("SinkDB did not recognize the IP as valid. Here is the full response:\n{}".format(json.dumps(entries)))
else:
self.error("There was an unknown error communicating with the SinkDB API. Here is the full response:\n{}".format(json.dumps(entries)))

if raw.get('is_sinkhole'):
taxonomies.append(self.build_taxonomy('safe', 'SinkDB', 'IsSinkhole', 'True'))
else:
taxonomies.append(self.build_taxonomy('suspicious', 'SinkDB', 'IsSinkhole', 'False'))
return {
"taxonomies": taxonomies
}
def do_post(self, data):
return requests.post('https://sinkdb-api.abuse.ch/api/v1/', headers={"Content-Type": "application/x-www-form-urlencoded"}, data=data)

def run(self):
try:
self.report(self.query_db(self.data))
except:
self.error("Error when attempting to retrieve data:\n{}".format(traceback.format_exc()))

def summary(self, raw):
taxonomies = []

for k, v in raw.iteritems():
if v:
taxonomies.append(self.build_taxonomy('suspicious', 'SinkDB', k, 'True'))
else:
taxonomies.append(self.build_taxonomy('safe', 'SinkDB', k, 'False'))

return {
"taxonomies": taxonomies
}


if __name__ == '__main__':
SinkDBAnalyzer().run()
SinkDBAnalyzer().run()
81 changes: 77 additions & 4 deletions thehive-templates/SinkDB_1_0/long.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,84 @@
<dt>Status</dt>
<dd>
<p style="font-size: 1.5em;">
<span class="label label-success" ng-if="content.is_sinkhole">
IP is sinkholed.
<span class="label label-warning" ng-if="content.Sinkhole.length > 0">
Artifact is sinkholed.

<table class="table" ng-if="content.Sinkhole.length !== 0 ">
<thead>
<th>SinkDB ID</th>
<th>SinkDB URL</th>
<th>Type</th>
<th>Classification</th>
<th>Operator</th>
</thead>
<tbody ng-repeat="r in content.Sinkhole | orderBy:'-date_added'">
<tr>
<td>{{r.id}}</td>
<td>{{r.sinkdb_reference}}</td>
<td>{{r.type}}</td>
<td>{{r.classification}}</td>
<td>{{r.operator}}</td>
</tr>
</tbody>
</table>
</span>
<span class="label label-success" ng-if="content.Sinkhole.length == 0">
Artifact is <strong>not</strong> sinkholed.
</span>
</p>
<p style="font-size: 1.5em;">
<span class="label label-warning" ng-if="content.Phishing.length > 0">
Artifact is part of a phishing awareness Campaign.

<table class="table" ng-if="content.Phishing.length !== 0 ">
<thead>
<th>SinkDB ID</th>
<th>SinkDB URL</th>
<th>Type</th>
<th>Classification</th>
<th>Operator</th>
</thead>
<tbody ng-repeat="r in content.Phishing | orderBy:'-date_added'">
<tr>
<td>{{r.id}}</td>
<td>{{r.sinkdb_reference}}</td>
<td>{{r.type}}</td>
<td>{{r.classification}}</td>
<td>{{r.operator}}</td>
</tr>
</tbody>
</table>
</span>
<span class="label label-success" ng-if="content.Phishing.length == 0">
Artifact is <strong>not</strong> part of a phishing awareness campaign.
</span>
</p>
<p style="font-size: 1.5em;">
<span class="label label-warning" ng-if="content.Scanner.length > 0">
Artifact is a scanner.

<table class="table" ng-if="content.Scanner.length !== 0 ">
<thead>
<th>SinkDB ID</th>
<th>SinkDB URL</th>
<th>Type</th>
<th>Classification</th>
<th>Operator</th>
</thead>
<tbody ng-repeat="r in content.Scanner | orderBy:'-date_added'">
<tr>
<td>{{r.id}}</td>
<td>{{r.sinkdb_reference}}</td>
<td>{{r.type}}</td>
<td>{{r.classification}}</td>
<td>{{r.operator}}</td>
</tr>
</tbody>
</table>
</span>
<span class="label label-warning" ng-if="!content.is_sinkhole">
IP is <strong>not</strong> sinkholed.
<span class="label label-success" ng-if="content.Scanner.length == 0">
Artifact is <strong>not</strong> a scanner.
</span>
</p>
</dd>
Expand Down