23
23
- handle changes in status (UNKNOWN, MALICIOUS, NONMALICIOUS) (update function)
24
24
- implement auto publish
25
25
- control of https certificate (see https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings n)
26
+ - improve mapping of type (pe. BASE10TIMESTAMP)
26
27
27
28
Version: 0.000000003 :)
28
29
58
59
# Import configuration.py with API keys
59
60
import configuration
60
61
62
+ # Simulation mode (for debug) - don't create MISP event
63
+ simulate = False # nothing will be done if set to True
61
64
62
65
# --------------------------------------------------------------------------- #
63
66
@@ -238,6 +241,7 @@ def convertTEtoMISP(self, teevent):
238
241
mispevt = MISPEvent ()
239
242
mispevt .info = "[Facebook ThreatExchange]"
240
243
mispevt .distribution = 0
244
+
241
245
mispevt .sharing_group_id = self .privacy_levels [teevent ["privacy_type" ]]
242
246
243
247
# Check if event is to be kept
@@ -263,9 +267,12 @@ def convertTEtoMISP(self, teevent):
263
267
# Enrich description
264
268
if "description" in teevent .keys ():
265
269
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 ():
267
271
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 = ""
269
276
mispevt .info = mispevt .info + " - by %s (%s)" % (owner , email )
270
277
271
278
# Add sharing indicators (tags)
@@ -277,11 +284,79 @@ def convertTEtoMISP(self, teevent):
277
284
if self .extra_tag is not None :
278
285
mispevt .Tag .append (self .extra_tag )
279
286
280
- # all done :)
281
287
evtid = teevent ["id" ]
282
288
return [evtid , mispevt ]
283
289
284
290
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
+
285
360
def createEvent (self , mispevent ):
286
361
"""
287
362
Create a new event in MISP using a hash table structure describing the event
@@ -323,7 +398,6 @@ def loadMapping(self, mapfile="./mapping.json"):
323
398
try :
324
399
fd = open (mapfile , "r" )
325
400
mappings = json .load (fd )
326
- print ("DEBUG MAPPINGS: %s" % mappings )
327
401
if "Sharing" in mappings .keys ():
328
402
self .share_levels = mappings ["Sharing" ]
329
403
if "Type" in mappings .keys ():
@@ -341,14 +415,27 @@ def loadMapping(self, mapfile="./mapping.json"):
341
415
342
416
# --------------------------------------------------------------------------- #
343
417
344
- def mergeFacebookEvents (events ):
418
+ def groupFacebookEventsByOwner (events ):
345
419
"""
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.
347
424
"""
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
349
436
350
437
351
- def fromFacebookToMISP (mapfile = "./mapping.json" , histfile = "./history.json" ):
438
+ def fromFacebookToMISP (mapfile = "./mapping.json" , histfile = "./history.json" , creationkey = "owner" ):
352
439
# Open connection to MISP w/ proxy handling if required
353
440
proxies = None
354
441
if configuration .MISP_PROXY :
@@ -377,14 +464,39 @@ def fromFacebookToMISP(mapfile="./mapping.json", histfile="./history.json"):
377
464
# Retrieve event from Facebook
378
465
threats = fb .retrieveThreatDescriptorsLastNDays (1 )
379
466
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
385
484
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" )
388
500
else :
389
501
print ("INFO: NO EVENT RETRIEVE FROM FACEBOOK - EXITING" )
390
502
return
0 commit comments