mirror of
https://github.com/SecurityBrewery/catalyst.git
synced 2025-12-09 16:52:51 +01:00
Remove TheHive automation (#35)
This commit is contained in:
@@ -1,630 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import json
|
||||
from datetime import datetime
|
||||
import io
|
||||
|
||||
subprocess.check_call(
|
||||
[sys.executable, "-m", "pip", "install", "thehive4py", "requests", "minio"],
|
||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
|
||||
)
|
||||
|
||||
defaultschema = {
|
||||
"definitions": {},
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://example.com/object1618746510.json",
|
||||
"title": "Default",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"severity",
|
||||
"description",
|
||||
"summary",
|
||||
"tlp",
|
||||
"pap"
|
||||
],
|
||||
"properties": {
|
||||
"severity": {
|
||||
"$id": "#root/severity",
|
||||
"title": "Severity",
|
||||
"type": "string",
|
||||
"default": "Medium",
|
||||
"x-cols": 6,
|
||||
"x-class": "pr-2",
|
||||
"x-display": "icon",
|
||||
"x-itemIcon": "icon",
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "Unknown",
|
||||
"title": "Unknown",
|
||||
"icon": "mdi-help"
|
||||
},
|
||||
{
|
||||
"const": "Low",
|
||||
"title": "Low",
|
||||
"icon": "mdi-chevron-up"
|
||||
},
|
||||
{
|
||||
"const": "Medium",
|
||||
"title": "Medium",
|
||||
"icon": "mdi-chevron-double-up"
|
||||
},
|
||||
{
|
||||
"const": "High",
|
||||
"title": "High",
|
||||
"icon": "mdi-chevron-triple-up"
|
||||
},
|
||||
{
|
||||
"const": "Very High",
|
||||
"title": "Very High",
|
||||
"icon": "mdi-exclamation"
|
||||
}
|
||||
]
|
||||
},
|
||||
"flag": {
|
||||
"title": "Flag",
|
||||
"type": "boolean",
|
||||
"x-cols": 6,
|
||||
},
|
||||
"tlp": {
|
||||
"$id": "#root/tlp",
|
||||
"title": "TLP",
|
||||
"type": "string",
|
||||
"x-cols": 6,
|
||||
"x-class": "pr-2",
|
||||
"x-display": "icon",
|
||||
"x-itemIcon": "icon",
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "White",
|
||||
"title": "White",
|
||||
"icon": "mdi-alpha-w"
|
||||
},
|
||||
{
|
||||
"const": "Green",
|
||||
"title": "Green",
|
||||
"icon": "mdi-alpha-g"
|
||||
},
|
||||
{
|
||||
"const": "Amber",
|
||||
"title": "Amber",
|
||||
"icon": "mdi-alpha-a"
|
||||
},
|
||||
{
|
||||
"const": "Red",
|
||||
"title": "Red",
|
||||
"icon": "mdi-alpha-r"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pap": {
|
||||
"$id": "#root/pap",
|
||||
"title": "PAP",
|
||||
"type": "string",
|
||||
"x-cols": 6,
|
||||
"x-class": "pr-2",
|
||||
"x-display": "icon",
|
||||
"x-itemIcon": "icon",
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "White",
|
||||
"title": "White",
|
||||
"icon": "mdi-alpha-w"
|
||||
},
|
||||
{
|
||||
"const": "Green",
|
||||
"title": "Green",
|
||||
"icon": "mdi-alpha-g"
|
||||
},
|
||||
{
|
||||
"const": "Amber",
|
||||
"title": "Amber",
|
||||
"icon": "mdi-alpha-a"
|
||||
},
|
||||
{
|
||||
"const": "Red",
|
||||
"title": "Red",
|
||||
"icon": "mdi-alpha-r"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tags": {
|
||||
"$id": "#root/tags",
|
||||
"title": "Tags",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"description": {
|
||||
"$id": "#root/description",
|
||||
"title": "Description",
|
||||
"type": "string",
|
||||
"x-display": "textarea",
|
||||
"x-class": "pr-2"
|
||||
},
|
||||
"resolutionStatus": {
|
||||
"$id": "#root/resolutionStatus",
|
||||
"title": "Resolution Status",
|
||||
"type": "string",
|
||||
"x-cols": 6,
|
||||
"x-class": "pr-2",
|
||||
},
|
||||
"endDate": {
|
||||
"$id": "#root/endDate",
|
||||
"title": "End Data",
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"x-cols": 6,
|
||||
"x-class": "pr-2",
|
||||
},
|
||||
"summary": {
|
||||
"$id": "#root/summary",
|
||||
"title": "Summary",
|
||||
"type": "string",
|
||||
"x-display": "textarea",
|
||||
"x-class": "pr-2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defaultalertschema = {
|
||||
"definitions": {},
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://example.com/object1618746510.json",
|
||||
"title": "Default",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"severity",
|
||||
"description",
|
||||
"summary",
|
||||
"tlp",
|
||||
"pap"
|
||||
],
|
||||
"properties": {
|
||||
"severity": {
|
||||
"$id": "#root/severity",
|
||||
"title": "Severity",
|
||||
"type": "string",
|
||||
"default": "Medium",
|
||||
"x-cols": 6,
|
||||
"x-class": "pr-2",
|
||||
"x-display": "icon",
|
||||
"x-itemIcon": "icon",
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "Unknown",
|
||||
"title": "Unknown",
|
||||
"icon": "mdi-help"
|
||||
},
|
||||
{
|
||||
"const": "Low",
|
||||
"title": "Low",
|
||||
"icon": "mdi-chevron-up"
|
||||
},
|
||||
{
|
||||
"const": "Medium",
|
||||
"title": "Medium",
|
||||
"icon": "mdi-chevron-double-up"
|
||||
},
|
||||
{
|
||||
"const": "High",
|
||||
"title": "High",
|
||||
"icon": "mdi-chevron-triple-up"
|
||||
},
|
||||
{
|
||||
"const": "Very High",
|
||||
"title": "Very High",
|
||||
"icon": "mdi-exclamation"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tlp": {
|
||||
"$id": "#root/tlp",
|
||||
"title": "TLP",
|
||||
"type": "string",
|
||||
"x-cols": 6,
|
||||
"x-class": "pr-2",
|
||||
"x-display": "icon",
|
||||
"x-itemIcon": "icon",
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "White",
|
||||
"title": "White",
|
||||
"icon": "mdi-alpha-w"
|
||||
},
|
||||
{
|
||||
"const": "Green",
|
||||
"title": "Green",
|
||||
"icon": "mdi-alpha-g"
|
||||
},
|
||||
{
|
||||
"const": "Amber",
|
||||
"title": "Amber",
|
||||
"icon": "mdi-alpha-a"
|
||||
},
|
||||
{
|
||||
"const": "Red",
|
||||
"title": "Red",
|
||||
"icon": "mdi-alpha-r"
|
||||
}
|
||||
]
|
||||
},
|
||||
"source": {
|
||||
"$id": "#root/source",
|
||||
"title": "Source",
|
||||
"type": "string",
|
||||
"x-cols": 4,
|
||||
"x-class": "pr-2",
|
||||
},
|
||||
"sourceRef": {
|
||||
"$id": "#root/sourceRef",
|
||||
"title": "Source Ref",
|
||||
"type": "string",
|
||||
"x-cols": 4,
|
||||
"x-class": "pr-2",
|
||||
},
|
||||
"type": {
|
||||
"$id": "#root/type",
|
||||
"title": "Type",
|
||||
"type": "string",
|
||||
"x-cols": 4,
|
||||
"x-class": "pr-2",
|
||||
},
|
||||
"description": {
|
||||
"$id": "#root/description",
|
||||
"title": "Description",
|
||||
"type": "string",
|
||||
"x-display": "textarea",
|
||||
"x-class": "pr-2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class schema:
|
||||
def __init__(self):
|
||||
self.schema = defaultschema
|
||||
|
||||
def add_string(self, title):
|
||||
self.schema["properties"][title] = { "type": "string", "x-cols": 6, "x-class": "pr-2" }
|
||||
|
||||
def add_boolean(self, title):
|
||||
self.schema["properties"][title] = { "type": "boolean", "x-cols": 6, "x-class": "pr-2" }
|
||||
|
||||
def add_date(self, title):
|
||||
self.schema["properties"][title] = { "type": "string", "format": "date-time", "x-cols": 6, "x-class": "pr-2" }
|
||||
|
||||
def add_integer(self, title):
|
||||
self.schema["properties"][title] = { "type": "integer", "x-cols": 6, "x-class": "pr-2" }
|
||||
|
||||
def add_float(self, title):
|
||||
self.schema["properties"][title] = { "type": "number", "x-cols": 6, "x-class": "pr-2" }
|
||||
|
||||
|
||||
class alertschema:
|
||||
def __init__(self):
|
||||
self.schema = defaultalertschema
|
||||
|
||||
|
||||
def maptime(hivetime):
|
||||
if hivetime is None:
|
||||
return None
|
||||
return datetime.fromtimestamp(hivetime/1000).isoformat() + "Z"
|
||||
|
||||
|
||||
def mapstatus(hivestatus):
|
||||
if hivestatus == "Open" or hivestatus == "New":
|
||||
return "open"
|
||||
return "closed"
|
||||
|
||||
|
||||
def maptlp(hivetlp):
|
||||
if hivetlp == 0:
|
||||
return "White"
|
||||
if hivetlp == 1:
|
||||
return "Green"
|
||||
if hivetlp == 2:
|
||||
return "Amber"
|
||||
if hivetlp == 3:
|
||||
return "Red"
|
||||
return "White"
|
||||
|
||||
|
||||
def mapseverity(hiveseverity):
|
||||
if hiveseverity == 1:
|
||||
return "Low"
|
||||
if hiveseverity == 2:
|
||||
return "Medium"
|
||||
if hiveseverity == 3:
|
||||
return "High"
|
||||
if hiveseverity == 4:
|
||||
return "Very High"
|
||||
return "Unknown"
|
||||
|
||||
# {
|
||||
# "_id": "~16416",
|
||||
# "id": "~16416",
|
||||
# "createdBy": "jonas@thehive.local",
|
||||
# "updatedBy": "jonas@thehive.local",
|
||||
# "createdAt": 1638704013583,
|
||||
# "updatedAt": 1638704061151,
|
||||
# "_type": "case",
|
||||
# "caseId": 1,
|
||||
# "title": "My Test 1",
|
||||
# "description": "My Testcase",
|
||||
# "severity": 2,
|
||||
# "startDate": 1638703980000,
|
||||
# "endDate": null,
|
||||
# "impactStatus": null,
|
||||
# "resolutionStatus": null,
|
||||
# "tags": [],
|
||||
# "flag": false,
|
||||
# "tlp": 2,
|
||||
# "pap": 2,
|
||||
# "status": "Open",
|
||||
# "summary": null,
|
||||
# "owner": "jonas@thehive.local",
|
||||
# "customFields": {},
|
||||
# "stats": {},
|
||||
# "permissions": [ "manageShare", "manageAnalyse", "manageTask", "manageCaseTemplate", "manageCase", "manageUser", "manageProcedure", "managePage", "manageObservable", "manageTag", "manageConfig", "manageAlert", "accessTheHiveFS", "manageAction" ]
|
||||
# }
|
||||
def mapcase(hivecase, url, keep_ids):
|
||||
|
||||
s = schema()
|
||||
details = {}
|
||||
for name, data in hivecase["customFields"].items():
|
||||
if "string" in data and data["string"] is not None:
|
||||
s.add_string(name)
|
||||
details[name] = data["string"]
|
||||
if "boolean" in data and data["boolean"] is not None:
|
||||
s.add_boolean(name)
|
||||
details[name] = data["boolean"]
|
||||
if "date" in data and data["date"] is not None:
|
||||
s.add_date(name)
|
||||
details[name] = maptime(data["date"])
|
||||
if "integer" in data and data["integer"] is not None:
|
||||
s.add_integer(name)
|
||||
details[name] = data["integer"]
|
||||
if "float" in data and data["float"] is not None:
|
||||
s.add_float(name)
|
||||
details[name] = data["float"]
|
||||
|
||||
case = {}
|
||||
if keep_ids:
|
||||
case["id"] = hivecase["caseId"]
|
||||
|
||||
return {
|
||||
"name": hivecase["title"],
|
||||
"type": "incident",
|
||||
"status": mapstatus(hivecase["status"]),
|
||||
|
||||
"owner": hivecase["owner"],
|
||||
# "write": hivecase["write"],
|
||||
# "read": hivecase["read"],
|
||||
|
||||
"schema": json.dumps(s.schema),
|
||||
"details": {
|
||||
"tlp": maptlp(hivecase["tlp"]),
|
||||
"pap": maptlp(hivecase["pap"]),
|
||||
"severity": mapseverity(hivecase["severity"]),
|
||||
"description": hivecase["description"],
|
||||
"summary": hivecase["summary"],
|
||||
"tags": hivecase["tags"],
|
||||
"endDate": maptime(hivecase["endDate"]),
|
||||
"resolutionStatus": hivecase["resolutionStatus"],
|
||||
"flag": hivecase["flag"],
|
||||
} | details,
|
||||
"references": [
|
||||
{ "name": "TheHive #%d" % hivecase["caseId"], "href": "%s/index.html#!/case/~%s/details" % (url, hivecase["id"]) }
|
||||
],
|
||||
#
|
||||
# "playbooks": hivecase["playbooks"],
|
||||
#
|
||||
"files": [],
|
||||
"comments": [],
|
||||
# creator, created, message
|
||||
#
|
||||
"artifacts": [],
|
||||
# name, type, status, enrichment
|
||||
# name, data
|
||||
|
||||
"created": maptime(hivecase["createdAt"]),
|
||||
"modified": maptime(hivecase["updatedAt"]),
|
||||
} | case
|
||||
|
||||
# {
|
||||
# "_id": "ce2c00f17132359cb3c50dfbb1901810",
|
||||
# "_type": "alert",
|
||||
# "artifacts": [],
|
||||
# "createdAt": 1495012062014,
|
||||
# "createdBy": "myuser",
|
||||
# "date": 1495012062016,
|
||||
# "description": "N/A",
|
||||
# "follow": true,
|
||||
# "id": "ce2c00f17132359cb3c50dfbb1901810",
|
||||
# "lastSyncDate": 1495012062016,
|
||||
# "severity": 2,
|
||||
# "source": "instance1",
|
||||
# "sourceRef": "alert-ref",
|
||||
# "status": "New",
|
||||
# "title": "New Alert",
|
||||
# "tlp": 2,
|
||||
# "type": "external",
|
||||
# "user": "myuser"
|
||||
# }
|
||||
def mapalert(hivealert, url):
|
||||
s = alertschema()
|
||||
details = {}
|
||||
|
||||
return {
|
||||
"name": hivealert["title"],
|
||||
"type": "alert",
|
||||
"status": mapstatus(hivealert["status"]),
|
||||
"owner": hivealert["user"],
|
||||
"schema": json.dumps(s.schema),
|
||||
"details": {
|
||||
"tlp": maptlp(hivealert["tlp"]),
|
||||
"severity": mapseverity(hivealert["severity"]),
|
||||
"description": hivealert["description"],
|
||||
"source": hivealert["source"],
|
||||
"sourceRef": hivealert["sourceRef"],
|
||||
"type": hivealert["type"],
|
||||
} | details,
|
||||
"references": [
|
||||
{ "name": "TheHive Alerts", "href": "%s/index.html#!/alert/list" % url }
|
||||
],
|
||||
"files": [],
|
||||
"comments": [],
|
||||
"artifacts": [],
|
||||
"created": maptime(hivealert["createdAt"]),
|
||||
"modified": maptime(hivealert["lastSyncDate"]),
|
||||
}
|
||||
|
||||
# {
|
||||
# "_id": "~41152",
|
||||
# "id": "~41152",
|
||||
# "createdBy": "jonas@thehive.local",
|
||||
# "createdAt": 1638723814523,
|
||||
# "_type": "case_artifact",
|
||||
# "dataType": "ip",
|
||||
# "data": "2.2.2.2",
|
||||
# "startDate": 1638723814523,
|
||||
# "tlp": 2,
|
||||
# "tags": [],
|
||||
# "ioc": false,
|
||||
# "sighted": false,
|
||||
# "message": ".",
|
||||
# "reports": {},
|
||||
# "stats": {},
|
||||
# "ignoreSimilarity": false
|
||||
# }
|
||||
def mapobservable(hiveobservable):
|
||||
status = "unknown"
|
||||
if hiveobservable["ioc"]:
|
||||
status = "malicious"
|
||||
return {
|
||||
"name": hiveobservable["data"],
|
||||
"type": hiveobservable["dataType"],
|
||||
"status": status,
|
||||
}
|
||||
|
||||
# {
|
||||
# "id": "~12296",
|
||||
# "_id": "~12296",
|
||||
# "createdBy": "jonas@thehive.local",
|
||||
# "createdAt": 1638704029800,
|
||||
# "_type": "case_task",
|
||||
# "title": "Start",
|
||||
# "group": "MyTaskGroup1",
|
||||
# "owner": "jonas@thehive.local",
|
||||
# "status": "InProgress",
|
||||
# "flag": false,
|
||||
# "startDate": 1638704115667,
|
||||
# "order": 0
|
||||
# }
|
||||
# {
|
||||
# "_id": "~24656",
|
||||
# "id": "~24656",
|
||||
# "createdBy": "jonas@thehive.local",
|
||||
# "createdAt": 1638729992590,
|
||||
# "_type": "case_task_log",
|
||||
# "message": "asd",
|
||||
# "startDate": 1638729992590,
|
||||
# "attachment": {
|
||||
# "name": "Chemistry Vector.eps",
|
||||
# "hashes": [
|
||||
# "adf2d4cd72f4141fe7f8eb4af035596415a29c048d3039be6449008f291258e9",
|
||||
# "180f66a6d22b1f09ed198afd814f701e42440e7c",
|
||||
# "b28ae347371df003b76cbb8c6199c97e"
|
||||
# ],
|
||||
# "size": 3421842,
|
||||
# "contentType": "application/postscript",
|
||||
# "id": "adf2d4cd72f4141fe7f8eb4af035596415a29c048d3039be6449008f291258e9"
|
||||
# },
|
||||
# "status": "Ok",
|
||||
# "owner": "jonas@thehive.local"
|
||||
# }
|
||||
def maptasklog(hivetask, hivetasklog):
|
||||
message = "**" + hivetask["group"] + ": " + hivetask["title"] + "** (" + hivetask["status"] + ")\n\n"
|
||||
message += hivetasklog["message"]
|
||||
if 'attachment' in hivetasklog:
|
||||
message += "\n\n*Attachment*: " + hivetasklog['attachment']["name"]
|
||||
return {
|
||||
"creator": hivetasklog["createdBy"],
|
||||
"created": maptime(hivetasklog["createdAt"]),
|
||||
"message": message,
|
||||
}
|
||||
|
||||
|
||||
def run(msg):
|
||||
skip_files = msg["payload"]["skip_files"]
|
||||
keep_ids = msg["payload"]["keep_ids"]
|
||||
|
||||
from thehive4py.api import TheHiveApi
|
||||
import requests
|
||||
from minio import Minio
|
||||
|
||||
headers = {"PRIVATE-TOKEN": msg["secrets"]["catalyst_apikey"]}
|
||||
# minioclient = Minio("try.catalyst-soar.com:9000", access_key="minio", secret_key="password")
|
||||
if not skip_files:
|
||||
minioclient = Minio(
|
||||
msg["secrets"]["minio_host"],
|
||||
access_key=msg["secrets"]["minio_access_key"],
|
||||
secret_key=msg["secrets"]["minio_secret_key"])
|
||||
|
||||
# url = "http://localhost:9000"
|
||||
url = msg["payload"]["thehiveurl"]
|
||||
# api = TheHiveApi(url, "dtUCnzY4h291GIFHJKW/Z2I2SgjTRQqo")
|
||||
api = TheHiveApi(url, msg["payload"]["thehivekey"])
|
||||
|
||||
print("find alerts", file=sys.stderr)
|
||||
alerts = []
|
||||
resp = api.find_alerts(query={}, sort=['-createdAt'], range='all')
|
||||
resp.raise_for_status()
|
||||
for alert in resp.json():
|
||||
alerts.append(mapalert(alert, url))
|
||||
|
||||
if alerts:
|
||||
print("create %s alerts" % len(alerts), file=sys.stderr)
|
||||
response = requests.post(msg["secrets"]["catalyst_apiurl"] + "/tickets/batch", json=alerts, headers=headers)
|
||||
response.raise_for_status()
|
||||
|
||||
print("find incidents", file=sys.stderr)
|
||||
incidents = []
|
||||
resp = api.find_cases(query={}, sort=['-createdAt'], range='all')
|
||||
resp.raise_for_status()
|
||||
for case in resp.json():
|
||||
incident = mapcase(case, url, keep_ids)
|
||||
for observable in api.get_case_observables(case["id"]).json():
|
||||
incident["artifacts"].append(mapobservable(observable))
|
||||
for task in api.get_case_tasks(case["id"]).json():
|
||||
for log in api.get_task_logs(task["id"]).json():
|
||||
incident["comments"].append(maptasklog(task, log))
|
||||
if 'attachment' in log and not skip_files:
|
||||
incident["files"].append({ "key": log['attachment']["id"], "name": log['attachment']["name"] })
|
||||
|
||||
bucket_name = "catalyst-%d" % incident["id"]
|
||||
if not minioclient.bucket_exists(bucket_name):
|
||||
minioclient.make_bucket(bucket_name)
|
||||
|
||||
response = api.download_attachment(log["attachment"]["id"])
|
||||
data = io.BytesIO(response.content)
|
||||
|
||||
minioclient.put_object(bucket_name, log["attachment"]["id"], data, length=-1, part_size=10*1024*1024)
|
||||
incidents.append(incident)
|
||||
|
||||
if incidents:
|
||||
if keep_ids:
|
||||
print("delete incidents", file=sys.stderr)
|
||||
for incident in incidents:
|
||||
requests.delete(msg["secrets"]["catalyst_apiurl"] + "/tickets/%d" % incident["id"], headers=headers)
|
||||
print("create %d incidents" % len(incidents), file=sys.stderr)
|
||||
response = requests.post(msg["secrets"]["catalyst_apiurl"] + "/tickets/batch", json=incidents, headers=headers)
|
||||
response.raise_for_status()
|
||||
|
||||
return {"done": True}
|
||||
|
||||
|
||||
print(json.dumps(run(json.loads(sys.argv[1]))))
|
||||
Reference in New Issue
Block a user