Skip to content

Commit 152d1c8

Browse files
committed
Prepare code for multi indicators events
1 parent 62e3ce4 commit 152d1c8

File tree

2 files changed

+129
-16
lines changed

2 files changed

+129
-16
lines changed

Facebook2MISP.py

Lines changed: 127 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
- handle changes in status (UNKNOWN, MALICIOUS, NONMALICIOUS) (update function)
2424
- implement auto publish
2525
- control of https certificate (see https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings n)
26+
- improve mapping of type (pe. BASE10TIMESTAMP)
2627
2728
Version: 0.000000003 :)
2829
@@ -58,6 +59,8 @@
5859
# Import configuration.py with API keys
5960
import configuration
6061

62+
# Simulation mode (for debug) - don't create MISP event
63+
simulate = False # nothing will be done if set to True
6164

6265
# --------------------------------------------------------------------------- #
6366

@@ -238,6 +241,7 @@ def convertTEtoMISP(self, teevent):
238241
mispevt = MISPEvent()
239242
mispevt.info = "[Facebook ThreatExchange]"
240243
mispevt.distribution = 0
244+
241245
mispevt.sharing_group_id = self.privacy_levels[teevent["privacy_type"]]
242246

243247
# Check if event is to be kept
@@ -263,9 +267,12 @@ def convertTEtoMISP(self, teevent):
263267
# Enrich description
264268
if "description" in teevent.keys():
265269
mispevt.info = mispevt.info + " - %s" % teevent["description"]
266-
if ("owner" in teevent.keys()) and ("name" in teevent["owner"].keys()) and ("email" in teevent["owner"].keys()):
270+
if "owner" in teevent.keys() and "name" in teevent["owner"].keys():
267271
owner = teevent["owner"]["name"]
268-
email = teevent["owner"]["email"].replace("\\u0040", "@")
272+
if("email" in teevent["owner"].keys()):
273+
email = teevent["owner"]["email"].replace("\\u0040", "@")
274+
else:
275+
email = ""
269276
mispevt.info = mispevt.info + " - by %s (%s)" % (owner, email)
270277

271278
# Add sharing indicators (tags)
@@ -277,11 +284,79 @@ def convertTEtoMISP(self, teevent):
277284
if self.extra_tag is not None:
278285
mispevt.Tag.append(self.extra_tag)
279286

280-
# all done :)
281287
evtid = teevent["id"]
282288
return [evtid, mispevt]
283289

284290

291+
def convertTEtoMISPTEST(self, teevents=[]):
292+
"""
293+
Convert a ThreatExchange entry to MISP entry
294+
"""
295+
# Create empty event
296+
mispevt = MISPEvent()
297+
mispevt.info = "[Facebook ThreatExchange]"
298+
mispevt.distribution = 0
299+
mispevt.category = "Network activity"
300+
301+
share_level = "WHITE"
302+
evtids = []
303+
for teevent in teevents:
304+
305+
# Set event visiblity to VISIBLE except if stated otherwise in event
306+
if(self.privacy_levels[teevent["privacy_type"]] != self.privacy_levels["VISIBLE"]):
307+
mispevt.sharing_group_id = self.privacy_levels[teevent["privacy_type"]]
308+
else:
309+
mispevt.sharing_group_id = self.privacy_levels["VISIBLE"]
310+
311+
# Check if event is to be kept
312+
if "status" in teevent.keys() and teevent["status"] in self.score.keys() and self.score[teevent["status"]] < self.badness_threshold :
313+
print("IGNORE EVENT %s due to status (%s)" % (teevent, teevent["status"]))
314+
continue
315+
316+
# Add indicator to event
317+
if "raw_indicator" in teevent.keys():
318+
if "type" in teevent.keys():
319+
if teevent["type"] in self.type_map.keys():
320+
indicator = teevent["raw_indicator"].replace("\\", "")
321+
mispevt.add_attribute(self.type_map[teevent["type"]] , indicator) # not to brutal??
322+
else:
323+
print("WARNING: TYPE %s SHOULD BE ADDED TO MAPPING" % teevent["type"])
324+
325+
# Enrich description - last will be kept :-S
326+
if "description" in teevent.keys():
327+
mispevt.info = mispevt.info + " - %s" % teevent["description"]
328+
329+
# Ownership - last will be kept :-S
330+
if "owner" in teevent.keys() and "name" in teevent["owner"].keys():
331+
owner = teevent["owner"]["name"]
332+
if("email" in teevent["owner"].keys()):
333+
email = teevent["owner"]["email"].replace("\\u0040", "@")
334+
else:
335+
email = ""
336+
mispevt.info = mispevt.info + " - by %s (%s)" % (owner, email)
337+
338+
# Add sharing indicators (tags) - keep more strict
339+
if "share_level" in teevent.keys():
340+
if teevent["share_level"] in self.share_levels.keys(): # sharing level has to be reduced
341+
if int(self.share_levels[share_level]["id"]) > int(self.share_levels[teevent["share_level"]]["id"]):
342+
share_level = teevent["share_level"]
343+
else:
344+
print("WARNING: SHARING LEVEL %s SHOULD BE ADDED TO MAPPING" % teevent["share_level"])
345+
346+
# Add Extra Tags
347+
if self.extra_tag is not None:
348+
mispevt.Tag.append(self.extra_tag)
349+
350+
# Add ID to list of ID making this event
351+
evtids.append(teevent["id"])
352+
353+
# Set share level
354+
mispevt.Tag.append(self.share_levels[share_level])
355+
356+
# Return new MISP event ready for import
357+
return [evtids, mispevt]
358+
359+
285360
def createEvent(self, mispevent):
286361
"""
287362
Create a new event in MISP using a hash table structure describing the event
@@ -323,7 +398,6 @@ def loadMapping(self, mapfile="./mapping.json"):
323398
try:
324399
fd = open(mapfile, "r")
325400
mappings = json.load(fd)
326-
print("DEBUG MAPPINGS: %s" % mappings)
327401
if "Sharing" in mappings.keys():
328402
self.share_levels = mappings["Sharing"]
329403
if "Type" in mappings.keys():
@@ -341,14 +415,27 @@ def loadMapping(self, mapfile="./mapping.json"):
341415

342416
# --------------------------------------------------------------------------- #
343417

344-
def mergeFacebookEvents(events):
418+
def groupFacebookEventsByOwner(events):
345419
"""
346-
Merge multiple-linked events to a single MISP one
420+
Merge multiple-linked events to a single MISP one.
421+
422+
Currently, merge all events passed in the Threats structure per owner.
423+
Keep the original structure too.
347424
"""
348-
return
425+
threats = {}
426+
threats["data"] = []
427+
threats["owner"] = {}
428+
429+
# Merge events by owner (event reporter?)
430+
for event in events["data"]:
431+
if(not event["owner"]["name"] in threats["owner"].keys()):
432+
threats["owner"][event["owner"]["name"]] = []
433+
threats["owner"][event["owner"]["name"]].append(event)
434+
threats["data"].append(event)
435+
return threats
349436

350437

351-
def fromFacebookToMISP(mapfile="./mapping.json", histfile="./history.json"):
438+
def fromFacebookToMISP(mapfile="./mapping.json", histfile="./history.json", creationkey="owner"):
352439
# Open connection to MISP w/ proxy handling if required
353440
proxies = None
354441
if configuration.MISP_PROXY:
@@ -377,14 +464,39 @@ def fromFacebookToMISP(mapfile="./mapping.json", histfile="./history.json"):
377464
# Retrieve event from Facebook
378465
threats = fb.retrieveThreatDescriptorsLastNDays(1)
379466
if threats is not None:
380-
for event in threats["data"]:
381-
[teevtid, mispevt] = misp.convertTEtoMISP(event)
382-
if(teevtid not in history.keys()):
383-
mispid = misp.createEvent(mispevt)
384-
history[teevtid] = mispid
467+
threats = groupFacebookEventsByOwner(threats)
468+
469+
# set events differently based on type of structure passed
470+
events = None
471+
if(type(threats[creationkey]) == dict):
472+
events = threats[creationkey].values()
473+
else:
474+
events = threats[creationkey]
475+
476+
# Loop on events
477+
for event in events:
478+
teevids = []
479+
# if merged event, create merge events
480+
# should be a single function handling list of 1 or more events
481+
if(type(event) == list):
482+
[teevtids, mispevt] = misp.convertTEtoMISPTEST(event)
483+
# raw download, 1:1 creation in MISP
385484
else:
386-
print("EVENT: %s already in MISP under ID: %s" % (teevtid, history[teevtid]))
387-
print("DEBUG -- need to implement an update function -- TODO!!") # DEBUG /
485+
[teevtid, mispevt] = misp.convertTEtoMISP(event)
486+
teevids = [teevtid]
487+
488+
# @TODO - Improve this piece of code - really poor :(
489+
found = False
490+
for teevid in teevids:
491+
if(teevtid in history.keys()):
492+
found = True
493+
print("TODO - update event %d with new teevid (or updated teevid) %d" % (history[teevtid], teevid))
494+
else:
495+
if not simulate:
496+
mispid = misp.createEvent(mispevt)
497+
history[teevtid] = mispid
498+
else:
499+
print("SIMULATE: would have created event into MISP")
388500
else:
389501
print("INFO: NO EVENT RETRIEVE FROM FACEBOOK - EXITING")
390502
return

mapping.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"DOMAIN": "domain",
3030
"IP_ADDRESS": "ip-dst",
3131
"URI": "url",
32-
"REGISTRY_KEY" : "regkey"
32+
"REGISTRY_KEY" : "regkey",
33+
"BASE10TIMESTAMP" : "other"
3334
}
3435
}

0 commit comments

Comments
 (0)