Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…into nsmfoo-zscaler
  • Loading branch information
jeromeleonard committed Jan 24, 2022
2 parents 0de9ebd + 9b0eddd commit 6070f7b
Show file tree
Hide file tree
Showing 9 changed files with 243 additions and 0 deletions.
9 changes: 9 additions & 0 deletions analyzers/Zscaler/README.md
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.
76 changes: 76 additions & 0 deletions analyzers/Zscaler/Zscaler.json
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"
}]
}
Binary file added analyzers/Zscaler/assets/zscaler_logo.png
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.
3 changes: 3 additions & 0 deletions analyzers/Zscaler/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
cortexutils
requests

112 changes: 112 additions & 0 deletions analyzers/Zscaler/zscaler.py
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()

40 changes: 40 additions & 0 deletions thehive-templates/Zscaler_1_3/long.html
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>

3 changes: 3 additions & 0 deletions thehive-templates/Zscaler_1_3/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>

0 comments on commit 6070f7b

Please sign in to comment.