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

[OSCD Initiative] Vulners analyzer #880

Merged
merged 11 commits into from
Jan 21, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
46 changes: 46 additions & 0 deletions analyzers/Vulners/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Vulners-analyzer

This analyzer consists of 2 parts.
1. **Vulners_IOC**: As a result of collaboration between Vulners and RST Threat Feed, the idea was to send IOC analysis results through theHive analyzer: blog post
2. **Vulners_CVE**: Vulners have a strong vulnerability database. This data is useful if:
"if the case (incident) is related to the exploitation of a vulnerability, then the analyst (manually / automatically) can add it to observables and quickly get all the basic information on it in order to continue analyzing the case."

Vulners API key required.

## Setting up analyzer

* copy the folders "Vulners" analyzer & "Vulners" into your Cortex analyzer path
* install necessary python modules from the requirements.txt (**pip install -r requirements.txt**)
* restart Cortex to initialize the new Responder "**systemctl restart cortex**"

Get your Vulners api key: ![Vulners API](assets/vulners_api.png)

Add your Vulners API in Cortex settings: ![API key in Cortex](assets/Cortex_settings.png)

## Add Observable type in TheHive

By default theHive does not have a "cve" type to be observables, so we have to add it to Administrator Settings:

![add observable](assets/theHive_add_cve.PNG)​

## Run the Analyzer in TheHive

####Network IOCs:

Short template:

![Short IOC template](assets/ioc_short_template.png)

Long template:

![Long IOC template](assets/ioc_long_template.png)

####Vulnerabilities:

Short template:

![Short CVE template](assets/cve_short_template.png)

Long template:

![Long CVE template](assets/cve_long_template.gif)
8 changes: 8 additions & 0 deletions analyzers/Vulners/Vulners_IOC.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@
}
],
"screenshots": [
{
"path": "assets/vulners_api.png",
"caption": "Vulners API key for analyzer"
},
{
"path": "assets/Cortex_settings.png",
"caption": "Paste Vulners API key in Cortex settings"
},
{
"path": "assets/ioc_long_template.png",
"caption": "Long template for network IOCs (ip, url, domain)"
Expand Down
Binary file added analyzers/Vulners/assets/Cortex_settings.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified analyzers/Vulners/assets/ioc_long_template.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified analyzers/Vulners/assets/ioc_short_template.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added analyzers/Vulners/assets/vulners_api.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
77 changes: 46 additions & 31 deletions analyzers/Vulners/vulners_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,22 @@ def __init__(self):
def summary(self, raw):
taxonomies = []
namespace = "Vulners"
if raw['service'] == 'ioc':
if self.service == 'ioc':
predicate = "IOC"
tags = ', '.join(raw['tags'])
if raw['fp_descr'] and not raw['tags']:
level = 'informative'
value = f"{raw['ioc_score']} score"
elif raw['fp_descr'] and raw['tags']:
tags = ', '.join(
set([', '.join(result['tags']) for result in raw['results']])
)
if tags:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is something strange here. The code will not reach the else clause in any case.

Copy link
Contributor Author

@uchakin uchakin Oct 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dadokkio done
You're right. I fixed and simplified this part.

level = 'malicious'
value = f"Finded IOCs: {len(raw['results'])} / tags: {tags}"
elif not tags:
level = 'suspicious'
value = f"{raw['ioc_score']} score / tags: {tags} / possible FP descr: {raw['fp_descr']}"
value = f"Finded IOCs: {len(raw['results'])}"
else:
level = 'malicious'
value = f"{raw['ioc_score']} score / tags: {tags} "
level = 'info'
value = 'No results'

if raw['service'] == 'vulnerability':
if self.service == 'vulnerability':
predicate = "CVE"
if not raw['exploits']:
level = 'suspicious'
Expand All @@ -43,28 +45,41 @@ def run(self):
if self.service == 'ioc':
if self.data_type in ['ip', 'domain', 'url']:
data = self.get_param('data', None, 'Data is missing')
document_id = self.vulners.search(f'iocType:{self.data_type} AND {self.data_type}:"{data}"')

if document_id or 'type' in document_id:
if document_id['type'] == 'rst':
full_document_info = self.vulners.document(
document_id[0]['id'], fields=["*"])
ioc_report = {
'service': self.service,
'first_seen': full_document_info['published'],
'last_seen': full_document_info['lastseen'],
'tags': full_document_info['tags'],
'ioc_score': full_document_info['iocScore']['ioc_total'],
'ioc_url': full_document_info['id'],
'fp_descr': full_document_info['fp']['descr']
}
if self.data_type == 'ip':
ioc_report['geo_info'] = full_document_info['geodata']
ioc_report['asn_info'] = full_document_info['asn']

self.report(ioc_report)
all_short_results = self.vulners.search(
f'type:rst AND iocType:{self.data_type} AND {self.data_type}:"{data}"')

results = []

if all_short_results:
if all_short_results[0]['type'] == 'rst' or 'type' in all_short_results[0]:

full_documents_info = self.vulners.documentList(
[doc_id['id'] for doc_id in all_short_results], fields=["*"])

for document_results in full_documents_info:
ioc_report = {
'service': self.service,
'first_seen': full_documents_info[f'{document_results}']['published'],
'last_seen': full_documents_info[f'{document_results}']['lastseen'],
'tags': full_documents_info[f'{document_results}']['tags'],
'ioc_score': full_documents_info[f'{document_results}']['iocScore']['ioc_total'],
'ioc_url': full_documents_info[f'{document_results}']['id'],
'fp_descr': full_documents_info[f'{document_results}']['fp']['descr']
}
if self.data_type == 'ip':
ioc_report['ioc_result'] = full_documents_info[f'{document_results}']['ip']
ioc_report['geo_info'] = full_documents_info[f'{document_results}']['geodata']
ioc_report['asn_info'] = full_documents_info[f'{document_results}']['asn']
elif self.data_type == 'url':
ioc_report['ioc_result'] = full_documents_info[f'{document_results}']['url']
elif self.data_type == 'domain':
ioc_report['ioc_result'] = full_documents_info[f'{document_results}']['domain']

results.append(ioc_report)

self.report({'results': results})
else:
self.error('No data found')
self.error({'results': 'No data found'})
else:
self.error('Invalid data type')

Expand Down
53 changes: 32 additions & 21 deletions thehive-templates/Vulners_IOC_1_0/long.html
Original file line number Diff line number Diff line change
@@ -1,58 +1,69 @@
<div class="panel panel-ingo" ng-if="success">
<!-- Success -->
<div class="panel panel-info" ng-if="success">
<div class="panel-heading">
Vulners information for <strong>{{artifact.data | fang}}</strong>
</div>
<div class="panel-body">
<div class="panel-body" ng-if="content.results == 'No data found'">
<dd style="color:#ff0000">
No data found :(
</dd>
</div>
<div class="panel-body" ng-repeat="result in content.results">
<div>
<dl class="dl-horizontal">
<dt>Matching result</dt>
<dd ng-repeat="match in result.ioc_result">{{match}}</dd>
</dl>
<dl class="dl-horizontal">
<dt>First seen</dt>
<dd>{{content.first_seen | limitTo : 10}}</dd>
<dd>{{result.first_seen | limitTo : 10}}</dd>
</dl>
<dl class="dl-horizontal">
<dt>Last seen</dt>
<dd>{{content.last_seen | limitTo : 10}}</dd>
<dd>{{result.last_seen | limitTo : 10}}</dd>
</dl>
<dl class="dl-horizontal">
<dt>Score</dt>
<dd>{{content.ioc_score}}</dd>
<dd>{{result.ioc_score}}</dd>
</dl>
<dl class="dl-horizontal">
<dt ng-if="content.tags">Tags</dt>
<dd ng-if="content.tags">
<span ng-repeat="tag in content.tags" class="label label-danger">
<dt ng-if="result.tags">Tags</dt>
<dd ng-if="result.tags">
<span ng-repeat="tag in result.tags" class="label label-danger">
{{tag}}
</span>
</dd>
</dd>
</dl>
<dl class="dl-horizontal" ng-if="content.fp_descr">
<dl class="dl-horizontal" ng-if="result.fp_descr">
<dt>Possible FP</dt>
<dd>
<span class="label label-warning">
{{content.fp_descr}}
{{result.fp_descr}}
</span>
</dd>
</dl>
<dl class="dl-horizontal" ng-if="content.asn_info">
<dl class="dl-horizontal" ng-if="result.asn_info">
<dt>Asn info</dt>
<dd>
ASN {{content.asn_info.num}}: First IP {{content.asn_info.firstip.netv4}}, Last IP {{content.asn_info.lastip.netv4}}<br />
ASN name "{{content.asn_info.isp}}"<br />
ASN hosts {{content.asn_info.domains}} domains<br />
ASN {{result.asn_info.num}}: First IP {{result.asn_info.firstip.netv4}}, Last IP {{result.asn_info.lastip.netv4}}<br />
ASN name "{{result.asn_info.isp}}"<br />
ASN hosts {{result.asn_info.domains}} domains<br />
</dd>
</dl>
<dl class="dl-horizontal" ng-if="content.geo_info">
<dl class="dl-horizontal" ng-if="result.geo_info">
<dt>Geo info</dt>
<dd>
Country: {{content.geo_info.country}}<br />
Region: {{content.geo_info.region}}<br />
City: {{content.geo_info.city}}<br />
Country: {{result.geo_info.country}}<br />
Region: {{result.geo_info.region}}<br />
City: {{result.geo_info.city}}<br />
</dd>
</dl>
</div>
<p><br>Source info:
<a href="https://vulners.com/rst/{{content.ioc_url}}" target="_blank">https://vulners.com/rst/{{content.ioc_url}}</a>
<a href="https://vulners.com/rst/{{result.ioc_url}}" target="_blank">https://vulners.com/rst/{{result.ioc_url}}</a>
</p>
<hr><br />
</div>
</div>

Expand All @@ -62,9 +73,9 @@
<strong>{{(artifact.data) | fang}}</strong>
</div>
<div class="panel-body">
<dl class="dl-horizontal" ng-if="content.errorMessage">
<dl class="dl-horizontal" ng-if="content.results.errorMessage">
<dt><i class="fa fa-warning"></i> ANALYZERNAME: </dt>
<dd class="wrap">{{content.errorMessage}}</dd>
<dd class="wrap">{{content.result.errorMessage}}</dd>
</dl>
</div>
</div>