TheHiveHooks
Requirements
The following instructions are based on CentOS7 and Oracle Enterprise Linux 8, and assumes TheHiveHooks is installed on the same server as TheHive.
TheHive 4.x
Python 3.6
TheHive4Py 1.8.1+
Command Line/Terminal access to TheHive server
Root/Sudo access at the Command Line/Terminal on TheHive server
Internet/Web access from TheHive Server (or local copies of all packages reference for localinstall)
TheHive 4.x org-admin role/profile for desired organizations
Installation
Install Supporting Packages
Elevate to Root (for convenience): sudo su -
If you can only access internet sites via a web proxy:
set HTTP_PROXY=http://IPADDRESS:PORT
set HTTPS_PROXY=http://IPADDRESS:PORT
set PIP_CERT=/etc.pki/tls/certs/ca-bundle.crt (assumes your updated the OS Trusted Certificates with the Certificate Authority used by the web proxy)
Ensure PIP is up to date: python3 -m pip install --upgrade pip
Install Supervirod: python3 -m pip install supervisor
Install Virtual Env for Python: yum install virtualenv
Install Git for TheHiveHooks download: yum install git
If you use a web proxy, set Git's proxy:
Set: git config --global http.proxy http://IPADDRESS:PORT
Verify: git config --global --get-regex http.*
Install TheHiveHooks
Log in to TheHive's Web UI as an org-admin for the desired organization (or to the 'admin' organization):
IMPORTANT: If you have more than one organization you wish to use TheHiveHooks with, you must perform the following for each desired organization and the username for each organization's TheHiveHooks account must be unique. If you use the exactly same username it will only work for the first organization where that account was created (its default organization).
Create a local account to be used by TheHiveHooks (e.g. username: thehivehooks@thehive.local) in the desired organization with the org-admin role.
Click the Create API Key button for this local account, then click the Reveal API Key - note this somewhere safe for later.
Return to the command line/terminal, and change directories to /opt: cd /opt
Download TheHiveHooks: git clone https://github.com/TheHive-Project/TheHiveHooks.git
Verify /opt/TheHiveHooks was created: ls /opt
Change directories: cd /opt/TheHiveHooks
Create a virtual Python instance for TheHiveHooks (so any updates made to the global/OS instance don't break any older and required versions that might be needed later for TheHiveHooks or TheHive4Py):
Start the creation (can take 1-5 minutes): virtualenv venv
Troubleshooting: If creation appears stuck at "Installing setuptools, pip, wheel", try clearing the user profile's cache folder in a different terminal session (or CTRL+C to cancel, clear, and relaunch the attempt):
Verify the cache folder exists: ls -l ~/.cache/pip
Clear the cache folder: rm -rf ~/.cache/pip
Verify the cache folder no longer exists: ls -l ~/.cache
Verify it was created: ls venv (AKA ls /opt/TheHiveHooks/venv)
Enter the virtual environment: source /opt/TheHiveHooks/venv/bin/activate
If you use a web proxy, set the session's environmental variables (HTTP_PROXY, HTTPS_PROXY, PIP_CERT).
Verify PIP is up to date: python3.6 -m pip install --upgrade pip
Install TheHive4Py: python3.6 -m pip install thehive4py
Install TheHiveHooks' required modules: python3.6 -m pip install -r requirements.txt (AKA python3.6 -m pip install -r /opt/TheHiveHooks/requirements.txt)
Install Gunicorn: python3.6 -m pip install gunicorn
By default TheHiveHooks will use Flask, which is sufficient for dev/test, but not recommended for production. Gunicorn will fulfill Flask's role later.
Install Keyring: python3.6 -m pip install keyring
Install Keyring's crypted file storage: python3.6 -m pip install keyrings.cryptfile
Keyring and Keyring Cryptfile will be used to store the API Keys in a slightly more secure method than hardcoding them in TheHiveHooks script later. It separates the actual API Key from the script so you can backup the script without also inadvertantly storing your API Keys in plain text in a less secure location (or if you upload them to github for whatever reason). The true security of your API Keys will depend on how the OS is configured -- anyone able to access the filesystem can find the password to decode the API Keys.
There are more secure methods of doing this. I gave it a try, but it didn't work or required too many packages and too much time to untangle so if this is a concern look into secure ways of storing script credentials.
Open a Python session to configure Keyring: python
Import: from keyrings.cryptfile.cryptfile import CryptFileKeyring
Object: kr = CryptFileKeyring()
Add API Key: kr.set_password("ACCTNAME", "API", "APIKEYHERE")
The first time you add a password to keyring it will prompt you to create a password for the keyring. This password will be used in TheHiveHook script later to enable it to retrieve/use the desired API Key.
Use the 'Add API Key' syntax above as many times as desired to add as many API Keys as desired to the keyring. Make sure the ACCTNAME is unique each time.
To verify a password was added: kr.get_password("ACCTNAME", "API")
Once all passwords are added, press CTRL+D to exit the python session.
Exit the Virtual Environment: deactivate
Configure TheHiveHooks
Edit the launcher: vi /opt/TheHiveHooks/thehive_hooks/__init__.py
from flask import Flaskimport loggingfrom logging.handlers import RotatingFileHandlerimport osfrom pyee import EventEmitter# Declare the loggerapp_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')pathLog = app_dir + '/thehive-hooks.log'handler = RotatingFileHandler(pathLog, maxBytes=10000000, backupCount=1)handler.setLevel(logging.INFO)handler.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)s in %(module)s: %(message)s'))# Initialize the appapp = Flask(__name__)# Gunicornif __name__ == '__main__':# // App called directly - flask or CLIapp.logger.addHandler(handler)else:# // App called by gunicorngunicorn_logger = logging.getLogger('gunicorn.error')app.logger.handlers = gunicorn_logger.handlers# // Use logging level specified by gunicorn confapp.logger.setLevel(gunicorn_logger.level)app.url_map.strict_slashes = False## Declare the event emitteree = EventEmitter()import thehive_hooks.controllersimport thehive_hooks.handlers
Edit the script: vi /opt/TheHiveHooks/thehive_hooks/handlers.py
import jsonfrom thehive_hooks import appfrom thehive_hooks import eefrom thehive4py.api import TheHiveApifrom thehive4py.models import *from thehive4py.query import *# // For URL or API Callsimport urllib# // RegEx for TaskLogimport re# // ElasticSearch Action-Reaction requires 1 second pause between them.from time import sleep# // For Epoch to Human Time Conversionfrom datetime import datetime# // Email Sendingimport smtplibfrom email.mime.text import MIMETextfrom email.mime.multipart import MIMEMultipartfrom email.header import Headerfrom email.utils import formataddr# // Key Storefrom keyrings.cryptfile.cryptfile import CryptFileKeyringkr = CryptFileKeyring()kr.keyring_key = "KEYRINGPASSWORD"# See def: hive4ApiByOrg# ################################################## // WEBHOOK EE-FN CONNECTORdef make_handler_func(event_name):@ee.on(event_name)def _handler(event):app.logger.info('Handle {}: Event={}'.format(event_name, json.dumps(event, indent=4, sort_keys=True)))return _handler# // WEBHOOK SUPPORTED EVENTSevents = ['AlertCreation','AlertUpdate','CaseArtifactCreation', #Hive3'CaseArtifactCreate', #Hive4'CaseArtifactJobCreation','CaseArtifactJobUpdate','CaseArtifactJobUpdate','CaseArtifactUpdate','CaseCreation', #Hive3'CaseCreate', #Hive4'CaseTaskCreation', #Hive3'CaseTaskCreate', #Hive4'CaseTaskLogCreation', #Hive3'CaseTaskLogCreate', #Hive4'CaseTaskLogUpdate','CaseTaskUpdate','CaseUpdate','CaseDelete']# // WEBHOOK DEFINE SUPPORTED EE.ON FNfor e in events:make_handler_func(e)# ################################################## // GENERAL FUNCTIONSdef hive4ApiByOrg(event_organisation):global apiglobal thehive_apikeyapp.logger.info('Case Org: {}'.format(event_organisation))if event_organisation == 'ORG1NAME':thehive_apikey = kr.get_password("ORG1APIUSERNAME", "API")app.logger.info('Case API Key: ORG1NAME Used: {}'.format(thehive_apikey[0:5]))elif event_organisation == 'ORG2NAME':thehive_apikey = kr.get_password("ORG2APIUSERNAME", "API")app.logger.info('Case API Key: ORG2NAME Used: {}'.format(thehive_apikey[0:5]))elif event_organisation == 'ORG3NAME':thehive_apikey = kr.get_password("ORG3APIUSERNAME", "API")app.logger.info('Case API Key: ORG3NAME Used: {}'.format(thehive_apikey[0:5]))elif event_organisation == 'ORG4NAME':thehive_apikey = kr.get_password("ORG4APIUSERNAME", "API")app.logger.info('Case API Key: ORG4NAME Used: {}'.format(thehive_apikey[0:5]))else:app.logger.info('Case API Key: Unknown for Org {}'.format(event_organisation))api = TheHiveApi(url='http://127.0.0.1:9000', principal=thehive_apikey, version='4')# FREE EXAMPLE OF A FUNCTION YOU COULD USE WITH THEHIVEHOOKS TO AUTOMATE THINGS IN THEHIVE -- like ensuring when people add a Task Log that single line breaks appear like single line breaks. It can mess with Code Blocks and Tables, however.def taskDoubleBreak(event):if 'message' in event['details'] and '\n' in event['details']['message']:# // Prevent infinite loops by filtering out Webhook-made Updatesif not 'updatedBy' in event['object'] or ('updatedBy' in event['object'] and not str(event['object']['updatedBy']).endswith("thehive.local")):log_id = event['objectId']original_msg = event['details']['message'] + '\n\n###### _Automatically Converted Single to Double Line Break_'# // Check if an Adjustment is needed to avoid unnecessary UpdatesregexPattern = re.compile('(?<!\n)\n(?!\n)')regexResults = regexPattern.findall(original_msg)app.logger.info('Single Breaks Found: {}'.format(len(regexResults)))if len(regexResults) > 0:app.logger.info('Task Log Line Break Adjustment')adjusted_msg = re.sub(r'(?<!\n)\n(?!\n)','\n\n', original_msg)ctask_url = "http://127.0.0.1:9000/api/case/task/log/" + log_idctask_criteria = {"message":adjusted_msg}ctask_json = json.dumps(ctask_criteria).encode('utf8')ctask_auth = 'Bearer ' + thehive_apikeyctask_request = urllib.request.Request(ctask_url, data=ctask_json, headers={'Authorization':ctask_auth,'Content-Type':'application/json'}, method='PATCH')urllib.request.urlopen(ctask_request)# ################################################## TRIGGERED EVENTS THAT CALL FUNCTIONS OR PERFORM ACTIONS@ee.on('CaseTaskLogCreate')#TheHive 4 Versiondef taskLogCreationHook(event):# Dynamically changes the global 'api' variable value to include the correct API Key based on the Organization name.hive4ApiByOrg(event['organisation'])case_guid = event['rootId']if 'message' in event['details'] and '\n' in event['details']['message']:taskDoubleBreak(event)
Starting TheHiveHooks
Create TheHiveHooks' log folder: mkdir /var/log/thehivehooks
Configure Log Rotation:
Create configuration: vi /etc/logrotate.d/rotatehooklogs.conf
Copy-Paste configuration into file:
/var/log/thehivehooks/thehivehooks.access.log /var/log/thehivehooks/thehivehooks.err.log /var/log/thehivehooks/thehivehooks.out.log {size 1Mdateextrotate 10}
Configure Supervisord to Startup:
Generate the default supervisord configuration: echo_supervisord_conf > /etc/supervisord.conf
Create the Includes folder: mkdir /etc/supervisord.d
Enable Includes (external conf files): vi /etc/supervisord.conf
Find the [include] section (usually at the very bottom) and remove the semicolor in front of it and the following "files =" line.
Change the "files =" value from the default to: /etc/supervisord.d/*.conf
Create the startup script: vi /etc/rc.d/init.d/supervisord
#!/bin/sh## /etc/rc.d/init.d/supervisord## Supervisor is a client/server system that# allows its users to monitor and control a# number of processes on UNIX-like operating# systems.## chkconfig: - 64 36# description: Supervisor Server# processname: supervisord# Source init functions. /etc/rc.d/init.d/functionsprog="supervisord"prefix="/usr/local"exec_prefix="${prefix}"prog_bin="${exec_prefix}/bin/supervisord"PIDFILE="/var/run/$prog.pid"start(){echo -n $"Starting $prog: "daemon $prog_bin --pidfile $PIDFILE[ -f $PIDFILE ] && success $"$prog startup" || failure $"$prog startup"echo}stop(){echo -n $"Shutting down $prog: "[ -f $PIDFILE ] && killproc $prog || success $"$prog shutdown"echo}case "$1" instart)start;;stop)stop;;status)status $prog;;restart)stopstart;;*)echo "Usage: $0 {start|stop|restart|status}";;esacAllow the startup script to execute (function): chmod +x /etc/rc.d/init.d/supervisord
Add the startup script to startup: chkconfig --add supervisord
Enable startup script execution: chkconfig supervisord on
Apply changes: systemctl daemon-reload
Configure Supervisord to run TheHiveHooks:
Create TheHiveHooks configuration for Supervisord: vi /etc/supervisord.d/superdhook.conf
[program:thehivehooks]directory=/opt/TheHiveHookscommand=/opt/TheHiveHooks/venv/bin/gunicorn thehive_hooks:app -b 127.0.0.1:5001 --workers 8 --max-requests 1000 --error-logfile /var/log/thehivehooks/thehivehooks.err.log --access-logfile /var/log/thehivehooks/thehivehooks.access.log --log-level info --log-file /var/log/thehivehooks/thehivehooks.out.log --capture-outputautostart=trueautorestart=true#redirect_stderr=Truestderr_logfile=/var/log/thehivehooks/thehivehooks.err.logstdout_logfile=/var/log/thehivehooks/thehivehooks.out.log
Start Supervisord: service supervisord start
Check Supervisord's status: supervisorctl status
If 'thehivehooks' shows 'STARTING' for more than 3 seconds there's most likely a problem with TheHiveHooks' __init__.py or handlers.py, or with the Supervisord conf files. Check the applicable log files for error messages.
Anytime you modify your handlers.py code, you must restart supervisord to apply the code changes: supervisorctl restart -- and you should always verify it doesn't get stuck 'STARTING' because of a typo in your code change.
Enabling TheHiveHooks in TheHive
Edit TheHive's configuration to call on Gunicorn's Port (which is running TheHiveHooks): vi /etc/thehive/application.conf
Scroll to the bottom and make sure the following block exists, or add it:
notification.webhook.endpoints = [{name: localversion: 0auth: {type: "none"}includedTheHiveOrganisations: ["*"]excludedTheHiveOrganisations: []}]
Restart TheHive: systemctl restart thehive
Verify TheHive Service remains running for more than 30 Seconds: systemctl status thehive
If the service fails to start, verify the application.conf modification didn't remove anything or if there's a typo in any new configuration added.
For each organization where you want TheHiveHooks activated/functioning, you must perform the following steps to finish enabling TheHiveHooks using the API key of the org-admin account (with a username unique to that organization) that was created earlier:
Securely enter the API Key so it isn't plastered all over your command history: read -s -p 'Enter the API Key: ' thehive_apikey
Use the following command to instruct TheHive to use TheHiveHooks for the organization of the account used to run the command:
curl -XPUT -H 'Content-type: application/json' -H "Authorization: Bearer $thehive_apikey" http://127.0.0.1:9000/api/config/organisation/notification -d '{"value": [{"delegate": false,"trigger": { "name": "AnyEvent"},"notifier": { "name": "webhook", "endpoint": "local" }}]}'Verify the webhook was activated successfully: curl -H 'Content-type: application/json' -H "Authorization: Bearer $thehive_apikey" http://127.0.0.1:9000/api/config/organisation/notification
You should receive output that looks like the following:
{"path":"notification","defaultValue":[],"value":[{"delegate":false,"trigger":{"name":"AnyEvent"},"notifier":{"name":"webhook","endpoint":"local"}}]}
Exit the Sudo Su Elevation: logout
Test that your TheHiveHook code works as expected in TheHive.