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

Censys.io analyzer #153

Merged
merged 1 commit into from
Dec 13, 2017
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
13 changes: 13 additions & 0 deletions analyzers/Censys/Censys.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "Censys",
"author": "Nils Kuhnert, CERT-Bund",
"license": "AGPL-V3",
"url": "https://github.com/BSI-CERT-Bund/censys-analyzer",
"version": "1.0",
"baseConfig": "Censys",
"config": {},
"description": "Check IPs, certificate hashs or domains against censys.io.",
"dataTypeList": ["ip", "hash", "domain"],
"command": "Censys/censys_analyzer.py"
}

118 changes: 118 additions & 0 deletions analyzers/Censys/censys_analyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#!/usr/bin/env python3
from cortexutils.analyzer import Analyzer
from censys.certificates import CensysCertificates
from censys.ipv4 import CensysIPv4
from censys.websites import CensysWebsites
from censys.base import CensysNotFoundException, CensysRateLimitExceededException, CensysUnauthorizedException


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

self.__uid = self.get_param(
'config.uid',
None,
'No UID for Censys given. Please add it to the cortex configuration.'
)
self.__api_key = self.get_param(
'config.key',
None,
'No API-Key for Censys given. Please add it to the cortex configuration.'
)

def search_hosts(self, ip):
"""
Searches for a host using its ipv4 address

:param ip: ipv4 address as string
:type ip: str
:return: dict
"""
c = CensysIPv4(api_id=self.__uid, api_secret=self.__api_key)
return c.view(ip)

def search_certificate(self, hash):
"""
Searches for a specific certificate using its hash

:param hash: certificate hash
:type hash: str
:return: dict
"""
c = CensysCertificates(api_id=self.__uid, api_secret=self.__api_key)
return c.view(hash)

def search_website(self, dom):
"""
Searches for a website using the domainname
:param dom: domain
:type dom: str
:return: dict
"""
c = CensysWebsites(api_id=self.__uid, api_secret=self.__api_key)
return c.view(dom)

def run(self):
try:
if self.data_type == 'ip':
self.report({
'ip': self.search_hosts(self.get_data())
})
elif self.data_type == 'hash':
self.report({
'cert': self.search_certificate(self.get_data())
})
elif self.data_type == 'domain' or self.data_type == 'fqdn':
self.report({
'website': self.search_website(self.get_data())
})
else:
self.error('Data type not supported. Please use this analyzer with data types hash, ip or domain.')
except CensysNotFoundException:
self.error('{} not found.'.format(self.get_data()))
except CensysUnauthorizedException:
self.error('Censys raised NotAuthorizedException. Please check your credentials.')
except CensysRateLimitExceededException:
self.error('Rate limit exceeded.')

def summary(self, raw):
taxonomies = []
if 'ip' in raw:
raw = raw['ip']
service_count = len(raw.get('protocols', []))
heartbleed = raw.get('443', {}).get('https', {}).get('heartbleed', {}).get('heartbleed_vulnerable', False)

taxonomies.append(self.build_taxonomy('info', 'Censys', 'OpenServices', service_count))
if heartbleed:
taxonomies.append(self.build_taxonomy('malicious', 'Censys', 'Heartbleed', 'vulnerable'))
elif 'website' in raw:
raw = raw['website']
service_count = len(raw.get('tags', []))

taxonomies.append(self.build_taxonomy('info', 'Censys', 'OpenServices', service_count))
elif 'cert' in raw:
raw = raw['cert']
trusted_count = len(raw.get('validation', []))
validator_count = len(raw.get('validation', []))

for _, validator in raw.get('validation', []).items():
if validator.get('blacklisted', False) or \
validator.get('in_revocation_set', False) or \
(not validator.get('whitelisted', False) and not validator.get('valid', False)):
trusted_count -= 1
if trusted_count < validator_count:
taxonomies.append(self.build_taxonomy('suspicious', 'Censys', 'TrustedCount', '{}/{}'.format(
trusted_count, validator_count
)))
else:
taxonomies.append(self.build_taxonomy('info', 'Censys', 'TrustedCount', '{}/{}'.format(
trusted_count, validator_count
)))
return {
'taxonomies': taxonomies
}


if __name__ == '__main__':
CensysAnalyzer().run()
2 changes: 2 additions & 0 deletions analyzers/Censys/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cortexutils
censys
212 changes: 212 additions & 0 deletions thehive-templates/Censys_1_0/long.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
<div class="panel panel-info" ng-if="success">
<div class="panel-heading">
Censys.io information for <strong>{{artifact.data}}</strong>
</div>
<div class="panel-body">
<dl class="dl-horizontal">
<dt>Results:</dt>
<dd>
<div id="ip-results" ng-if="content.ip">
<table class="table">
<thead>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>IP</td>
<td>{{content.ip.ip}}</td>
</tr>
<tr>
<td>Last update</td>
<td>{{content.ip.updated_at}}</td>
</tr>
<tr>
<td>Location</td>
<td>
{{content.ip.location.continent}} -
{{content.ip.location.country}} -
{{content.ip.location.province}} -
{{content.ip.location.city}}
</td>
</tr>
<tr>
<td>AS</td>
<td>{{content.ip.autonomous_system.asn}}: {{content.ip.autonomous_system.name}}</td>
</tr>
<tr ng-repeat="protocol in content.ip.ports">
<td>Info on port {{protocol}}</td>
<td>
<button class="btn btn-primary"
type="button"
data-toggle="collapse"
data-target="#collapse-{{protocol}}"
aria-expanded="false"
aria-controls="collapse-{{protocol}}">
Show/hide
</button>
<br />
<div class="collapse" id="collapse-{{protocol}}">
<div class="card card-body">
<pre>{{content.ip[protocol] | json}}</pre>
<button class="btn btn-primary"
type="button"
data-toggle="collapse"
data-target="#collapse-{{protocol}}"
aria-expanded="false"
aria-controls="collapse-{{protocol}}">
Show/hide
</button>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div id="hash-results" ng-if="content.cert">
<table class="table">
<thead>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Metadata</td>
<td>
<p>Source: {{content.cert.metadata.source}}</p>
<p>Added at: {{content.cert.metadata.added_at}}</p>
<p>Updated at: {{content.cert.metadata.updated_at}}</p>
</td>
</tr>
<tr>
<td>Added to CT</td>
<td>
<p>Comodo Mammoth<br />{{content.cert.ct.comodo_mammoth.added_to_ct_at}}</p>
<p>Comodo Sabre<br />{{content.cert.ct.comodo_sabre.added_to_ct_at}}</p>
<p>Google Pilot<br />{{content.cert.ct.google_pilot.added_to_ct_at}}</p>
<p>Google Rocketeer<br />{{content.cert.ct.google_rocketeer.added_to_ct_at}}</p>
<p>Symantec WS CT<br />{{content.cert.ct.symantec_ws_ct.added_to_ct_at}}</p>
</td>
</tr>
<tr>
<td>Issuer</td>
<td>
<p ng-repeat="cn in content.cert.parsed.issuer.common_name">{{cn}}</p>
</td>
</tr>
<tr>
<td>Validity</td>
<td>
<p>Valid since: {{content.cert.parsed.validity.start}}</p>
<p>Valid until: {{content.cert.parsed.validity.end}}</p>
</td>
</tr>
<tr>
<td>Full certificate data</td>
<td>
<button class="btn btn-primary"
type="button"
data-toggle="collapse"
data-target="#collapse-certdata"
aria-expanded="false"
aria-controls="collapse-certdata">
Show/hide
</button>
<br />
<div class="collapse" id="collapse-certdata">
<div class="card card-body">
<pre>{{content.cert | json}}</pre>
<button class="btn btn-primary"
type="button"
data-toggle="collapse"
data-target="#collapse-certdata"
aria-expanded="false"
aria-controls="collapse-certdata">
Show/hide
</button>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div id="website-results" ng-if="content.website">
<table class="table">
<thead>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Domain</td>
<td>{{content.website.domain}}</td>
</tr>
<tr>
<td>Last update</td>
<td>{{content.website.updated_at}}</td>
</tr>
<tr>
<td>Location</td>
<td>
{{content.website.location.continent}} -
{{content.website.location.country}} -
{{content.website.location.province}} -
{{content.website.location.city}}
</td>
</tr>
<tr>
<td>AS</td>
<td>{{content.website.autonomous_system.asn}}: {{content.website.autonomous_system.name}}</td>
</tr>
<tr ng-repeat="protocol in content.website.ports">
<td>Info on port {{protocol}}</td>
<td>
<button class="btn btn-primary"
type="button"
data-toggle="collapse"
data-target="#collapse-{{protocol}}"
aria-expanded="false"
aria-controls="collapse-{{protocol}}">
Show/hide
</button>
<br />
<div class="collapse" id="collapse-{{protocol}}">
<div class="card card-body">
<pre>{{content.website[protocol] | json}}</pre>
<button class="btn btn-primary"
type="button"
data-toggle="collapse"
data-target="#collapse-{{protocol}}"
aria-expanded="false"
aria-controls="collapse-{{protocol}}">
Show/hide
</button>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</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>
3 changes: 3 additions & 0 deletions thehive-templates/Censys_1_0/short.html
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>