diff --git a/.drone.yml b/.drone.yml index c9409745c..495585ff8 100644 --- a/.drone.yml +++ b/.drone.yml @@ -57,6 +57,14 @@ steps: when: event: [tag] + - name: build report-templates zip package + image: thehiveproject/neurons-build-report-templates + when: + event: [tag] + + +# Bintray will not be used anymore. We keep it until Feb 21 + - name: upload catalogs to bintray image: thehiveproject/drone-bintray settings: @@ -91,7 +99,32 @@ steps: when: event: [tag] - - name: upload catalogs to package server + - name: upload report-templates to bintray + image: thehiveproject/drone-bintray + settings: + user: {from_secret: bintray_user} + key: {from_secret: bintray_key} + subject: thehive-project + package: report-templates + version: latest + override: 1 + publish: 1 + commands: + - | + export PLUGIN_USER + export PLUGIN_KEY + export PLUGIN_SUBJECT + export PLUGIN_PACKAGE + export PLUGIN_VERSION + export PLUGIN_OVERRIDE + export PLUGIN_PUBLISH + upload \ + --file analyzers/report-templates.zip \ + --repo binary + when: + event: [tag] + + - name: upload catalogs and report-templates package to package server image: appleboy/drone-scp settings: host: {from_secret: package_host} @@ -103,6 +136,7 @@ steps: - analyzers/analyzers-stable.json - responders/responders.json - responders/responders-stable.json + - analyzers/report-templates.zip strip_components: 1 when: event: [tag] @@ -112,6 +146,8 @@ steps: when: branch: [develop] + +# Bintray will not be used anymore. We keep it until Feb 21 - name: upload devel catalogs to bintray image: thehiveproject/drone-bintray settings: diff --git a/analyzers/MISPWarningLists/requirements.txt b/analyzers/MISPWarningLists/requirements.txt index 10975ab77..16edc58c8 100644 --- a/analyzers/MISPWarningLists/requirements.txt +++ b/analyzers/MISPWarningLists/requirements.txt @@ -4,3 +4,4 @@ ipaddress tld sqlalchemy psycopg2-binary +tqdm diff --git a/analyzers/MISPWarningLists/warninglists_create_db.py b/analyzers/MISPWarningLists/warninglists_create_db.py index 663b19f0b..3d43dca4d 100755 --- a/analyzers/MISPWarningLists/warninglists_create_db.py +++ b/analyzers/MISPWarningLists/warninglists_create_db.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # coding: utf-8 import re diff --git a/analyzers/Splunk/requirements.txt b/analyzers/Splunk/requirements.txt index ca791b9b8..5e233098b 100644 --- a/analyzers/Splunk/requirements.txt +++ b/analyzers/Splunk/requirements.txt @@ -1 +1,2 @@ splunk-sdk +cortexutils diff --git a/analyzers/URLhaus/URLhaus_analyzer.py b/analyzers/URLhaus/URLhaus_analyzer.py index 2bf5f2276..e68bd4887 100755 --- a/analyzers/URLhaus/URLhaus_analyzer.py +++ b/analyzers/URLhaus/URLhaus_analyzer.py @@ -35,7 +35,8 @@ def summary(self, raw): namespace = "URLhaus" if raw['query_status'] == 'no_results' \ - or raw['query_status'] == 'ok' and raw['md5_hash'] == None and raw['sha256_hash'] == None: + or (raw['query_status'] == 'ok' and not raw.get('md5_hash', None) \ + and not raw.get('sha256_hash', None)): taxonomies.append(self.build_taxonomy( 'info', namespace, diff --git a/responders/Duo_Security/AddObservableType.jpg b/responders/Duo_Security/AddObservableType.jpg new file mode 100644 index 000000000..6d0b57e3d Binary files /dev/null and b/responders/Duo_Security/AddObservableType.jpg differ diff --git a/responders/Duo_Security/Demo_Lock-Unlock_DuoUser.gif b/responders/Duo_Security/Demo_Lock-Unlock_DuoUser.gif new file mode 100644 index 000000000..988b0bc00 Binary files /dev/null and b/responders/Duo_Security/Demo_Lock-Unlock_DuoUser.gif differ diff --git a/responders/Duo_Security/DuoLockUserAccount.json b/responders/Duo_Security/DuoLockUserAccount.json new file mode 100644 index 000000000..f845c1c5f --- /dev/null +++ b/responders/Duo_Security/DuoLockUserAccount.json @@ -0,0 +1,34 @@ +{ + "name": "DuoLockUserAccount", + "version": "1.0", + "author": "Sven Kutzer / Gyorgy Acs, @oscd_initiative", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "license": "AGPL-V3", + "description": "Lock User Account in Duo Security via AdminAPI (The user will not be able to log in)", + "dataTypeList": ["thehive:case_artifact"], + "command": "Duo_Security/duoLockUserAccount.py", + "baseConfig": "Duo_Security_main", + "configurationItems": [ + { + "name": "API_hostname", + "description": "Duo Admin API hostname, api-XXXXXXXX.duosecurity.com", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Integration_Key", + "description": "Integration Key", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Secret_Key", + "description": "Secret Key", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/Duo_Security/DuoUnlockUserAccount.json b/responders/Duo_Security/DuoUnlockUserAccount.json new file mode 100644 index 000000000..9efcec744 --- /dev/null +++ b/responders/Duo_Security/DuoUnlockUserAccount.json @@ -0,0 +1,34 @@ +{ + "name": "DuoUnlockUserAccount", + "version": "1.0", + "author": "Sven Kutzer / Gyorgy Acs, @oscd_initiative", + "url": "https://github.com/TheHive-Project/Cortex-Analyzers", + "license": "AGPL-V3", + "description": "Unlock User Account in Duo Security via AdminAPI (The user must complete secondary authentication)", + "dataTypeList": ["thehive:case_artifact"], + "command": "Duo_Security/duoUnlockUserAccount.py", + "baseConfig": "Duo_Security_main", + "configurationItems": [ + { + "name": "API_hostname", + "description": "Duo Admin API hostname, api-XXXXXXXX.duosecurity.com", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Integration_Key", + "description": "Integration Key", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Secret_Key", + "description": "Secret Key", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/Duo_Security/README.md b/responders/Duo_Security/README.md new file mode 100644 index 000000000..72a4c5db2 --- /dev/null +++ b/responders/Duo_Security/README.md @@ -0,0 +1,31 @@ +# CortexResponder_DuoUserAccount +Rep. for Cortex Responder (TheHive project - https://github.com/TheHive-Project/CortexDocs) +to Lock/Unlock User Accounts in the Duo Admin Portal (Cisco Security) + + +There are two Responder available in order to change the status of a User in Duo Security via the AdminAPI (https://duo.com/docs/adminapi) + +**DuoLockUserAccount** -> changes the "status" to “disabled” - The user will not be able to log in. + +**DuoUnlockUserAccount** -> changes the "status" to “active” - The user must complete secondary authentication. + +The Responder is looking for a "**username**" as input and queries the Duo Admin API, to receive the associated UserID. +The UserID is used to change the "status" of the particular user. + +## How to install: + * copy the folders "DuoLockUserAccount" & "DuoUnlockUserAccount" into your Cortex responders path + * install necessary python modules from the requirements.txt (**pip install -r requirements.txt**) + * restart Cortex to initialize the new Responder "**systemctl restart cortex**" + * add the ResponderConfig + * ![ResponderConfig](ResponderConfig.jpg) + * enable the Responder Actions + * ![Responders](Responders.jpg) + +## Add Observable type in TheHive** + * per default TheHive has no "username" Observable type, so we have to add this in the Admin settings + * ![AddObservableType](AddObservableType.jpg) + +## Run the Responder action in TheHive + +If you have add an observable, you can now take action and lock/unlock the User in Duo Security + * ![Demo_Lock-Unlock_DuoUser](Demo_Lock-Unlock_DuoUser.gif) diff --git a/responders/Duo_Security/ResponderConfig.jpg b/responders/Duo_Security/ResponderConfig.jpg new file mode 100644 index 000000000..fc0cb4eed Binary files /dev/null and b/responders/Duo_Security/ResponderConfig.jpg differ diff --git a/responders/Duo_Security/Responders.jpg b/responders/Duo_Security/Responders.jpg new file mode 100644 index 000000000..25bf7f540 Binary files /dev/null and b/responders/Duo_Security/Responders.jpg differ diff --git a/responders/Duo_Security/duoLockUserAccount.py b/responders/Duo_Security/duoLockUserAccount.py new file mode 100644 index 000000000..d15bbb2be --- /dev/null +++ b/responders/Duo_Security/duoLockUserAccount.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +import requests +import duo_client +from datetime import datetime + +class DuoLockUserAccount(Responder): + def __init__(self): + Responder.__init__(self) + self.API_hostname = self.get_param('config.API_hostname', None, "API hostname is missing") + self.iKey = self.get_param('config.Integration_Key', None, "Integration Key is missing") + self.sKey = self.get_param('config.Secret_Key', None, "Secret Key is missing") + + def run(self): + Responder.run(self) + + if self.get_param('data.dataType') == 'username': + + str_username = self.get_param('data.data', None, 'No artifacts available') + + admin_api = duo_client.Admin(self.iKey, self.sKey, self.API_hostname) + + response = admin_api.get_users_by_name(username=str_username) + +# print(response) + + user_id=response[0]["user_id"] + +# print("user_id:",user_id) + + r = admin_api.update_user(user_id=user_id,status='disabled') + +# print("response:",r) + + if r.get('status') == 'disabled': + self.report({'message': 'User is locked in Duo Security.'}) + else: + self.error('Failed to lock User Account in Duo.') + else: + self.error('Incorrect dataType. "username" expected.') + + def operations(self, raw): + return [self.build_operation('AddTagToArtifact', tag='Duo User: locked')] + +if __name__ == '__main__': + DuoLockUserAccount().run() diff --git a/responders/Duo_Security/duoUnlockUserAccount.py b/responders/Duo_Security/duoUnlockUserAccount.py new file mode 100644 index 000000000..2193d6724 --- /dev/null +++ b/responders/Duo_Security/duoUnlockUserAccount.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +import requests +import duo_client +from datetime import datetime + +class DuoUnlockUserAccount(Responder): + def __init__(self): + Responder.__init__(self) + self.API_hostname = self.get_param('config.API_hostname', None, "API hostname is missing") + self.iKey = self.get_param('config.Integration_Key', None, "Integration Key is missing") + self.sKey = self.get_param('config.Secret_Key', None, "Secret Key is missing") + + def run(self): + Responder.run(self) + + if self.get_param('data.dataType') == 'username': + + str_username = self.get_param('data.data', None, 'No artifacts available') + + admin_api = duo_client.Admin(self.iKey, self.sKey, self.API_hostname) + + response = admin_api.get_users_by_name(username=str_username) + +# print(response) + + user_id=response[0]["user_id"] + +# print("user_id:",user_id) + + r = admin_api.update_user(user_id=user_id,status='active') + +# print("response:",r) + + if r.get('status') == 'active': + self.report({'message': 'User is unlocked in Duo Security. The user must complete secondary authentication.'}) + else: + self.error('Failed to unlock User Account in Duo.') + else: + self.error('Incorrect dataType. "username" expected.') + + def operations(self, raw): + return [self.build_operation('AddTagToArtifact', tag='Duo User: reactivated')] + +if __name__ == '__main__': + DuoUnlockUserAccount().run() diff --git a/responders/Duo_Security/requirements.txt b/responders/Duo_Security/requirements.txt new file mode 100644 index 000000000..5efeab85d --- /dev/null +++ b/responders/Duo_Security/requirements.txt @@ -0,0 +1,4 @@ +cortexutils +requests +datetime +duo_client