Updating misp class and associated watcher code

This commit is contained in:
Félix Aime 2021-06-09 11:11:55 +02:00
parent 691a413bfb
commit 50baeaa9e5
2 changed files with 55 additions and 88 deletions

View File

@ -17,83 +17,34 @@ class MISP(object):
def __init__(self): def __init__(self):
return None return None
@staticmethod def add_instance(self, name, url, apikey, verify):
def add_instance(misp_name, misp_url, misp_key, misp_verifycert):
""" """
Parse and add a MISP instance to the database. Parse and add a MISP instance to the database.
:return: status of the operation in JSON :return: status of the operation in JSON
""" """
sameinstances = db.session.query(MISPInst).filter( sameinstances = db.session.query(MISPInst).filter(
MISPInst.url == misp_url, MISPInst.apikey == misp_key) MISPInst.url == url, MISPInst.apikey == apikey)
if sameinstances.count(): if sameinstances.count():
return {"status": False, return {"status": False,
"message": "This MISP instance already exists"} "message": "This MISP instance already exists"}
elif misp_name != "": if name:
if misp_url != "": if self.test_instance(url, apikey, verify):
if re.match(r"^(?:(?:http|https)://)", misp_url): added_on = int(time.time())
if misp_key != "": db.session.add(MISPInst(name, escape(url), apikey, verify, added_on))
added_on = int(time.time()) db.session.commit()
db.session.add(MISPInst(misp_name, escape( return {"status": True,
misp_url), misp_key, misp_verifycert, added_on)) "message": "MISP instance added",
db.session.commit() "name": escape(name),
return {"status": True, "url": escape(url),
"message": "MISP instance added", "apikey": escape(apikey),
"name": escape(misp_name), "verifycert": escape(verify)}
"url": escape(misp_url),
"apikey": escape(misp_key),
"verifycert": escape(misp_verifycert)}
else:
return {"status": False,
"message": "The key can't be empty"}
else:
return {"status": False,
"message": "The url must begin with http:// or https://"}
else: else:
return {"status": False, return {"status": False,
"message": "The url can't be empty"} "message": "Please verify the connection to the MISP instance"}
else: else:
return {"status": False, return {"status": False,
"message": "The MISP instance name can't be empty"} "message": "Please provide a name for your instance"}
@staticmethod
def edit_instance(misp_id, misp_name, misp_url, misp_key, misp_verifycert):
"""
Parse and edit the desired MISP instance.
:return: status of the operation in JSON
"""
misp = MISPInst.query.get(int(misp_id))
otherinstances = db.session.query(MISPInst).filter(MISPInst.id != int(
misp_id), MISPInst.url == misp_url, MISPInst.apikey == misp_key)
if misp is None:
return {"status": False,
"message": "Can't find the MISP instance"}
if otherinstances.count() > 0:
return {"status": False,
"message": "This MISP instance already exists"}
elif misp_name != "":
if misp_url != "":
if re.match(r"^(?:(?:http|https)://)", misp_url):
if misp_key != "":
misp.name = misp_name
misp.url = misp_url
misp.apikey = misp_key
misp.verifycert = misp_verifycert
db.session.commit()
return {"status": True,
"message": "MISP instance edited"}
else:
return {"status": False,
"message": "The key can't be empty"}
else:
return {"status": False,
"message": "The url must begin with http:// or https://"}
else:
return {"status": False,
"message": "The url can't be empty"}
else:
return {"status": False,
"message": "The MISP instance name can't be empty"}
@staticmethod @staticmethod
def delete_instance(misp_id): def delete_instance(misp_id):
@ -110,8 +61,7 @@ class MISP(object):
return {"status": False, return {"status": False,
"message": "MISP instance not found"} "message": "MISP instance not found"}
@staticmethod def get_instances(self):
def get_instances():
""" """
Get MISP instances from the database Get MISP instances from the database
:return: generator of the records. :return: generator of the records.
@ -122,7 +72,20 @@ class MISP(object):
"name": misp["name"], "name": misp["name"],
"url": misp["url"], "url": misp["url"],
"apikey": misp["apikey"], "apikey": misp["apikey"],
"verifycert": misp["verifycert"]} "verifycert": True if misp["verifycert"] else False,
"connected": self.test_instance(misp["url"], misp["apikey"], misp["verifycert"]) }
@staticmethod
def test_instance(url, apikey, verify):
"""
Test the connection of the MISP instance.
:return: generator of the records.
"""
try:
PyMISP(url, apikey, verify)
return True
except:
return False
@staticmethod @staticmethod
def get_iocs(misp_id): def get_iocs(misp_id):
@ -134,9 +97,13 @@ class MISP(object):
misp = MISPInst.query.get(int(misp_id)) misp = MISPInst.query.get(int(misp_id))
if misp is not None: if misp is not None:
if misp.url and misp.apikey: if misp.url and misp.apikey:
# Connect to MISP instance and get network activity attributes. try:
m = PyMISP(misp.url, misp.apikey, misp.verifycert) # Connect to MISP instance and get network activity attributes.
r = m.search("attributes", category="Network activity") m = PyMISP(misp.url, misp.apikey, misp.verifycert)
r = m.search("attributes", category="Network activity")
except:
print("Unable to connect to the MISP instance ({}/{}).".format(misp.url, misp.apikey))
return []
for attr in r["Attribute"]: for attr in r["Attribute"]:
if attr["type"] in ["ip-dst", "domain", "snort", "x509-fingerprint-sha1"]: if attr["type"] in ["ip-dst", "domain", "snort", "x509-fingerprint-sha1"]:
@ -151,6 +118,8 @@ class MISP(object):
ioc["type"] = "ip4addr" ioc["type"] = "ip4addr"
elif re.match(defs["iocs_types"][1]["regex"], attr["value"]): elif re.match(defs["iocs_types"][1]["regex"], attr["value"]):
ioc["type"] = "ip6addr" ioc["type"] = "ip6addr"
elif re.match(defs["iocs_types"][2]["regex"], attr["value"]):
ioc["type"] = "cidr"
elif re.match(defs["iocs_types"][3]["regex"], attr["value"]): elif re.match(defs["iocs_types"][3]["regex"], attr["value"]):
ioc["type"] = "domain" ioc["type"] = "domain"
elif re.match(defs["iocs_types"][4]["regex"], attr["value"]): elif re.match(defs["iocs_types"][4]["regex"], attr["value"]):
@ -162,11 +131,11 @@ class MISP(object):
if "Tag" in attr: if "Tag" in attr:
for tag in attr["Tag"]: for tag in attr["Tag"]:
# Add the TLP of the IOC. # Add a TLP to the IOC if defined in tags.
tlp = re.search(r"^(?:tlp:)(red|green|amber|white)", tag['name'].lower()) tlp = re.search(r"^(?:tlp:)(red|green|amber|white)", tag['name'].lower())
if tlp: ioc["tlp"] = tlp.group(1) if tlp: ioc["tlp"] = tlp.group(1)
# Add possible tag. # Add possible tag (need to match TinyCheck tags)
if tag["name"].lower() in [t["tag"] for t in defs["iocs_tags"]]: if tag["name"].lower() in [t["tag"] for t in defs["iocs_tags"]]:
ioc["tag"] = tag["name"].lower() ioc["tag"] = tag["name"].lower()
yield ioc yield ioc

View File

@ -41,10 +41,8 @@ def watch_iocs():
res = requests.get(w["url"], verify=False) res = requests.get(w["url"], verify=False)
if res.status_code == 200: if res.status_code == 200:
content = json.loads(res.content) content = json.loads(res.content)
iocs_list = content["iocs"] if "iocs" in content else [ iocs_list = content["iocs"] if "iocs" in content else []
] to_delete = content["to_delete"] if "to_delete" in content else []
to_delete = content["to_delete"] if "to_delete" in content else [
]
else: else:
w["status"] = False w["status"] = False
except: except:
@ -91,10 +89,8 @@ def watch_whitelists():
res = requests.get(w["url"], verify=False) res = requests.get(w["url"], verify=False)
if res.status_code == 200: if res.status_code == 200:
content = json.loads(res.content) content = json.loads(res.content)
elements = content["elements"] if "elements" in content else [ elements = content["elements"] if "elements" in content else []
] to_delete = content["to_delete"] if "to_delete" in content else []
to_delete = content["to_delete"] if "to_delete" in content else [
]
else: else:
w["status"] = False w["status"] = False
except: except:
@ -125,15 +121,17 @@ def watch_misp():
Retrieve IOCs from misp instances. Each new element is Retrieve IOCs from misp instances. Each new element is
tested added to the database. tested added to the database.
""" """
while True: iocs, misp = IOCs(), MISP()
for misp in MISP.get_instances(): instances = [i for i in misp.get_instances()]
try:
for ioc in MISP.get_iocs(misp.id):
iocs.add(ioc["type"], ioc["tag"], ioc["tlp"],
ioc["value"], "misp-{}".format(misp["name"]))
except:
continue
while instances:
for i, inst in enumerate(instances):
if inst["connected"]:
for ioc in misp.get_iocs(inst["id"]):
iocs.add(ioc["type"], ioc["tag"], ioc["tlp"],
ioc["value"], "misp-{}".format(inst["id"]))
instances.pop(i)
if instances: time.sleep(60)
p1 = Process(target=watch_iocs) p1 = Process(target=watch_iocs)
p2 = Process(target=watch_whitelists) p2 = Process(target=watch_whitelists)