-
Notifications
You must be signed in to change notification settings - Fork 385
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'zscaler' of https://github.com/nsmfoo/Cortex-Analyzers …
…into nsmfoo-zscaler
- Loading branch information
Showing
9 changed files
with
243 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Zscaler | ||
|
||
### General requirements | ||
|
||
You will need to have an active Zscaler ZIA subscription to be able to utilize this analyzer. | ||
|
||
### Credit | ||
|
||
Full credit should go to Simon Lavigne for creating this analyzer in the first place. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
{ | ||
"name": "Zscaler", | ||
"author": "Simon Lavigne, Mikael Keri", | ||
"license": "AGPL-V3", | ||
"url": "https://github.com/TheHive-Project/Cortex-Analyzers", | ||
"version": "1.3", | ||
"description": "Check Zscaler category for a domain, fqdn, IP address or FQDN. This analyzer requires a paid subscription to Zscaler ZIA", | ||
"dataTypeList": ["ip", "domain", "url", "fqdn"], | ||
"baseConfig": "Zscaler", | ||
"config": { | ||
"check_tlp": true, | ||
"max_tlp": 2, | ||
"check_pap": true, | ||
"max_pap": 2 | ||
}, | ||
"command": "Zscaler/zscaler.py", | ||
"configurationItems": [ | ||
{ | ||
"name": "username", | ||
"description": "Zscaler username", | ||
"type": "string", | ||
"multi": false, | ||
"required": true | ||
}, | ||
{ | ||
"name": "password", | ||
"description": "Zscaler password", | ||
"type": "string", | ||
"multi": false, | ||
"required": true | ||
}, | ||
{ | ||
"name": "api_key", | ||
"description": "API key", | ||
"type": "string", | ||
"multi": false, | ||
"required": true | ||
}, | ||
{ | ||
"name": "base_uri", | ||
"description": "The base URL of your Zscaler subscription", | ||
"type": "string", | ||
"multi": false, | ||
"required": true | ||
}, | ||
{ | ||
"name": "malicious_categories", | ||
"description": "List of Zscaler categories to be considered as malicious", | ||
"type": "string", | ||
"multi": true, | ||
"required": true, | ||
"defaultValue": ["PHISHING", "MALWARE_SITE", "BOTNET", "SPYWARE_OR_ADWARE", "ADSPYWARE_SITES", "ADWARE_OR_SPYWARE", "CRYPTOMINING", "WEB_SPAM", "MALICIOUS_TLD"] | ||
}, | ||
{ | ||
"name": "suspicious_categories", | ||
"description": "List of Zscaler categories to be considered as suspicious", | ||
"type": "string", | ||
"multi": true, | ||
"required": true, | ||
"defaultValue": ["SHAREWARE_DOWNLOAD", "REMOTE_ACCESS", "MISCELLANEOUS_OR_UNKNOWN", "NEWLY_REG_DOMAINS", "OTHER_ILLEGAL_OR_QUESTIONABLE", "COPYRIGHT_INFRINGEMENT", "GAMBLING", "COMPUTER_HACKING", "ANONYMIZER", "MISCELLANEOUS_OR_UNKNOWN", "DNS_OVER_HTTPS", "ENCR_WEB_CONTENT"] | ||
} | ||
], | ||
"registration_required": true, | ||
"subscription_required": true, | ||
"free_subscription": false, | ||
"service_homepage": "https://www.zscaler.com/", | ||
"service_logo": {"path":"assets/zscaler_logo.png", "caption": "logo"}, | ||
"screenshots": [ | ||
{"path":"assets/zscaler_sample_lookup_long.png", | ||
"caption":"Zscaler Lookup sample Information full report" | ||
}, | ||
{ | ||
"path": "assets/zscaler_sample_lookup_short.png", | ||
"caption:":"Zscaler Lookup sample mini report" | ||
}] | ||
} |
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
cortexutils | ||
requests | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
#!/usr/bin/env python3 | ||
# encoding: utf-8 | ||
|
||
import os | ||
import requests | ||
import json | ||
import time | ||
from urllib.parse import urlparse | ||
from cortexutils.analyzer import Analyzer | ||
|
||
|
||
class ZscalerAnalyzer(Analyzer): | ||
|
||
def __init__(self): | ||
Analyzer.__init__(self) | ||
self.api_key = self.get_param('config.api_key', None, 'Zscaler API key is missing') | ||
self.base_uri = self.get_param('config.base_uri', None, 'Zscaler base URI is missing') | ||
self.username = self.get_param('config.username', None, 'Zscaler username is missing') | ||
self.password = self.get_param('config.password', None, 'Zscaler password is missing') | ||
self.headers = { | ||
'Content-Type': 'application/json', | ||
'Accept': 'application/json', | ||
'User-Agent': 'Cortex-Analyzer' | ||
} | ||
|
||
def summary(self, raw): | ||
taxonomies = [] | ||
|
||
if 'urlClassifications' in raw: | ||
url = raw.get('url') | ||
mal_category = self.get_param('config.malicious_categories', []) | ||
sus_category = self.get_param('config.suspicious_categories', []) | ||
url_classification = raw.get('urlClassifications', []) | ||
url_sec_classification = raw.get('urlClassificationsWithSecurityAlert', []) | ||
|
||
if url_classification: | ||
if set(url_classification).intersection(mal_category): | ||
value = ", ".join(set(url_classification).intersection(mal_category)) | ||
level = "malicious" | ||
elif set(url_classification).intersection(sus_category): | ||
value = ", ".join(set(url_classification).intersection(sus_category)) | ||
level = "suspicious" | ||
else: | ||
value = ", ".join(url_classification) | ||
level = "info" | ||
|
||
if url_sec_classification: | ||
if set(url_sec_classification).intersection(mal_category): | ||
value = ", ".join(set(url_sec_classification).intersection(mal_category)) | ||
level = "malicious" | ||
elif set(url_sec_classification).intersection(sus_category): | ||
value = ", ".join(set(url_sec_classification).intersection(mal_category)) | ||
level = "suspicious" | ||
else: | ||
value = url_sec_classification | ||
level = "suspicious" | ||
|
||
else: | ||
level = "info" | ||
|
||
taxonomies.append(self.build_taxonomy(level, "Zscaler", "Classification", value)) | ||
result = {"taxonomies": taxonomies} | ||
|
||
return result | ||
|
||
|
||
def run(self): | ||
Analyzer.run(self) | ||
|
||
if self.data_type == 'domain' or self.data_type == 'fqdn' or self.data_type == 'ip' or self.data_type == 'url': | ||
data = self.get_param('data', None, 'Data is missing') | ||
|
||
# Mange the schema part of URLs | ||
if self.data_type == 'url': | ||
url_data = urlparse(data) | ||
data = url_data.netloc + url_data.path + url_data.params + url_data.query | ||
|
||
# Get JSESSIONID | ||
now = str(int(time.time() * 1000)) | ||
n = now[-6:] | ||
r = str(int(n) >> 1).zfill(6) | ||
obfuscated_key = "" | ||
for i in range(0, len(n), 1): | ||
obfuscated_key += self.api_key[int(n[i])] | ||
for j in range(0, len(r), 1): | ||
obfuscated_key += self.api_key[int(r[j])+2] | ||
|
||
payload = { | ||
"username": self.username, | ||
"password": self.password, | ||
"apiKey": obfuscated_key, | ||
"timestamp": int(now) | ||
} | ||
|
||
session = requests.Session() | ||
|
||
url_to_query = [] | ||
url_to_query.append(data) | ||
r = session.post(self.base_uri + '/api/v1/authenticatedSession', headers=self.headers, json=payload) | ||
s = session.post(self.base_uri + '/api/v1/urlLookup', headers=self.headers, json=url_to_query) | ||
s.close() | ||
response = s.json() | ||
try: | ||
self.report(response[0]) | ||
except Exception as e: | ||
self.error('Invalid data type') | ||
else: | ||
self.error('Invalid data type') | ||
|
||
if __name__ == '__main__': | ||
ZscalerAnalyzer().run() | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<div class="panel panel-info" ng-if="success"> | ||
<div class="panel-heading"> | ||
Zscaler URL Categorisation of | ||
<strong>{{artifact.data}}</strong> | ||
</div> | ||
<!-- URL details --> | ||
<div class="panel-body"> | ||
<table class="table"> | ||
<thead> | ||
<th>URL</th> | ||
<th>URL Classifications</th> | ||
</thead> | ||
<tbody ng-repeat="r in content.urlClassifications"> | ||
<tr> | ||
<td>{{content.url}}</td> | ||
<td>{{r}}</td> | ||
</tr> | ||
</tbody> | ||
<tbody ng-repeat="r in content.urlClassificationsWithSecurityAlert"> | ||
<tr> | ||
<td>{{content.url}}</td> | ||
<td>{{r}}</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
</div> | ||
</div> | ||
<!-- General error --> | ||
<div class="panel panel-danger" ng-if="!success"> | ||
<div class="panel-heading"> | ||
<strong>{{(artifact.data) | fang}}</strong> | ||
</div> | ||
<div class="panel-body"> | ||
<dl class="dl-horizontal" ng-if="content.errorMessage"> | ||
<dt><i class="fa fa-warning"></i> Zscaler: </dt> | ||
<dd class="wrap">{{content.errorMessage}}</dd> | ||
</dl> | ||
</div> | ||
</div> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |