2015-11-21 16:53:23 +01:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Python script parsing the MISP taxonomies expressed in Machine Tags (Triple
# Tags) to list all valid tags from a specific taxonomy.
#
2022-02-23 07:34:47 +01:00
# Copyright (c) 2015-2022 Alexandre Dulaunoy - a@foo.be
2015-11-21 16:53:23 +01:00
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
import json
import os . path
import argparse
2016-10-24 17:01:32 +02:00
import os
2022-02-23 07:34:47 +01:00
import sys
2015-11-21 16:53:23 +01:00
2022-03-25 09:34:14 +01:00
skip_list = [ ' death-possibilities ' , ' poison-taxonomy ' ]
2016-10-24 17:01:32 +02:00
taxonomies = [ ]
2017-01-20 10:35:28 +01:00
# Get our current directory from file location
thisDir = os . path . dirname ( __file__ )
2016-02-21 19:45:18 +01:00
argParser = argparse . ArgumentParser ( description = ' Dump Machine Tags (Triple Tags) from MISP taxonomies ' , epilog = ' Available taxonomies are {0} ' . format ( taxonomies ) )
2015-11-29 14:22:25 +01:00
argParser . add_argument ( ' -e ' , action = ' store_true ' , help = ' Include expanded tags ' )
2015-11-29 15:29:49 +01:00
argParser . add_argument ( ' -a ' , action = ' store_true ' , help = ' Generate asciidoctor document from MISP taxonomies ' )
2015-11-29 14:22:25 +01:00
argParser . add_argument ( ' -v ' , action = ' store_true ' , help = ' Include descriptions ' )
2016-02-21 19:45:18 +01:00
argParser . add_argument ( ' -n ' , default = False , help = ' Show only the specified namespace ' )
2022-02-23 07:34:47 +01:00
argParser . add_argument ( ' --disable-skip-list ' , default = False , action = ' store_true ' , help = ' disable default skip list ' )
2015-11-21 16:53:23 +01:00
args = argParser . parse_args ( )
2022-02-23 07:34:47 +01:00
if args . disable_skip_list :
skip_list = ' '
2022-02-23 07:50:24 +01:00
for folder in os . listdir ( os . path . join ( thisDir , ' ../ ' ) ) :
if os . path . isfile ( os . path . join ( thisDir , ' ../ ' , folder , ' machinetag.json ' ) ) :
if folder in skip_list :
continue
taxonomies . append ( folder )
taxonomies . sort ( )
2015-11-29 15:29:49 +01:00
doc = ' '
if args . a :
2017-11-04 14:09:02 +01:00
dedication = " \n [dedication] \n == Funding and Support \n The MISP project is financially and resource supported by https://www.circl.lu/[CIRCL Computer Incident Response Center Luxembourg ]. \n \n image: { images-misp}logo.png[CIRCL logo] \n \n A CEF (Connecting Europe Facility) funding under CEF-TC-2016-3 - Cyber Security has been granted from 1st September 2017 until 31th August 2019 as ***Improving MISP as building blocks for next-generation information sharing***. \n \n image: { images-misp}en_cef.png[CEF funding] \n \n If you are interested to co-fund projects around MISP, feel free to get in touch with us. \n \n "
2015-11-29 15:29:49 +01:00
doc = doc + " :toc: right \n "
2017-05-07 12:22:14 +02:00
doc = doc + " :toclevels: 1 \n "
2015-11-29 15:29:49 +01:00
doc = doc + " :icons: font \n "
2016-12-18 14:14:10 +01:00
doc = doc + " :images-cdn: https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/logos/ \n "
2017-11-04 14:09:02 +01:00
doc = doc + " :images-misp: https://www.misp-project.org/assets/images/ \n "
2015-11-29 15:29:49 +01:00
doc = doc + " = MISP taxonomies and classification as machine tags \n \n "
2017-11-04 14:09:02 +01:00
doc = doc + " = Introduction \n "
2015-11-29 15:46:13 +01:00
doc = doc + " \n image:: { images-cdn}misp-logo.png[MISP logo] \n "
2017-11-04 14:09:02 +01:00
doc = doc + " The MISP threat sharing platform is a free and open source software helping information sharing of threat intelligence including cyber security indicators, financial fraud or counter-terrorism information. The MISP project includes multiple sub-projects to support the operational requirements of analysts and improve the overall quality of information shared. \n \n "
doc = doc + " "
doc = " {} {} {} {} " . format ( doc , " \n Taxonomies that can be used in MISP (2.4) and other information sharing tool and expressed in Machine Tags (Triple Tags). " ,
2017-04-02 22:06:32 +02:00
" A machine tag is composed of a namespace (MUST), a predicate (MUST) and an (OPTIONAL) value. " ,
" Machine tags are often called triple tag due to their format. \n " )
2017-11-04 14:09:02 +01:00
doc = doc + " The following document is generated from the machine-readable JSON describing the https://github.com/MISP/misp-taxonomies[MISP taxonomies]. "
doc = doc + " \n \n "
doc = doc + " <<< \n "
doc = doc + dedication
doc = doc + " <<< \n "
doc = doc + " = MISP taxonomies \n "
2015-11-29 15:29:49 +01:00
doc = doc + " \n \n "
2016-02-21 19:45:18 +01:00
if args . n :
del taxonomies [ : ]
taxonomies . append ( args . n )
2017-04-02 22:06:32 +02:00
2018-02-18 12:37:45 +01:00
def asciidoc ( content = False , adoc = doc , t = ' title ' , toplevel = False ) :
2015-11-29 15:29:49 +01:00
if not args . a :
return False
adoc = adoc + " \n "
if t == ' title ' :
content = ' ==== ' + content
elif t == ' predicate ' :
content = ' === ' + content
elif t == ' namespace ' :
content = ' == ' + content + ' \n '
2020-09-08 11:42:38 +02:00
content = " {} \n {} {} {} {} {} {} " . format ( content , ' NOTE: ' , namespace , ' namespace available in JSON format at https://github.com/MISP/misp-taxonomies/blob/main/ ' ,
2017-04-02 22:06:32 +02:00
namespace , ' /machinetag.json[*this location*]. The JSON format can be freely reused in your application ' ,
' or automatically enabled in https://www.github.com/MISP/MISP[MISP] taxonomy. ' )
2018-02-18 12:37:45 +01:00
elif t == ' description ' and toplevel is True :
content = " \n {} \n " . format ( content )
elif t == ' description ' and toplevel is False :
2017-04-30 11:32:11 +02:00
try :
( n , value ) = content . split ( " : " , 1 )
content = " \n {} \n " . format ( value )
except :
content = " \n {} \n " . format ( content )
2017-12-01 07:55:35 +01:00
elif t == ' numerical_value ' :
( n , value ) = content . split ( " : " , 1 )
content = " \n Associated numerical value= \" {} \" \n " . format ( value )
2017-12-01 08:54:34 +01:00
elif t == ' exclusive ' :
( n , value ) = content . split ( " : " , 1 )
if n :
content = " \n IMPORTANT: Exclusive flag set which means the values or predicate below must be set exclusively. \n "
2015-11-29 15:29:49 +01:00
adoc = adoc + content
return adoc
2015-11-21 16:53:23 +01:00
2017-04-02 22:06:32 +02:00
2015-11-21 16:53:23 +01:00
def machineTag ( namespace = False , predicate = False , value = None ) :
if namespace is False or predicate is False :
return None
if value is None :
2016-02-11 14:10:58 +01:00
return ( u ' {0} : {1} ' . format ( namespace , predicate ) )
2015-11-21 16:53:23 +01:00
else :
2016-02-11 14:10:58 +01:00
return ( u ' {0} : {1} = \" {2} \" ' . format ( namespace , predicate , value ) )
2015-11-21 16:53:23 +01:00
2017-04-02 22:06:32 +02:00
2015-11-21 16:53:23 +01:00
for taxonomy in taxonomies :
2022-02-23 07:34:47 +01:00
if taxonomy in skip_list :
sys . stderr . write ( f " Skip { taxonomy } " )
continue
2017-01-20 10:35:28 +01:00
filename = os . path . join ( thisDir , " ../ " , taxonomy , " machinetag.json " )
2015-11-21 16:53:23 +01:00
with open ( filename ) as fp :
t = json . load ( fp )
namespace = t [ ' namespace ' ]
2016-01-10 17:03:44 +01:00
if t . get ( ' expanded ' ) :
expanded_namespace = t [ ' expanded ' ]
else :
expanded_namespace = namespace
2015-11-29 15:29:49 +01:00
if args . a :
2017-04-02 22:06:32 +02:00
doc = asciidoc ( content = t [ ' namespace ' ] , adoc = doc , t = ' namespace ' )
2018-02-18 12:37:45 +01:00
doc = asciidoc ( content = t [ ' description ' ] , adoc = doc , t = ' description ' , toplevel = True )
2017-12-01 08:54:34 +01:00
if t . get ( ' exclusive ' ) :
doc = asciidoc ( content = machineTag ( namespace = namespace , predicate = t [ ' exclusive ' ] ) , adoc = doc , t = ' exclusive ' )
2015-11-29 14:22:25 +01:00
if args . v :
2017-04-02 22:06:32 +02:00
print ( ' {0} ' . format ( t [ ' description ' ] ) )
2015-11-21 16:53:23 +01:00
for predicate in t [ ' predicates ' ] :
2015-11-29 15:29:49 +01:00
if args . a :
doc = asciidoc ( content = predicate [ ' value ' ] , adoc = doc , t = ' predicate ' )
2017-10-25 15:24:45 +02:00
if predicate . get ( ' description ' ) :
doc = asciidoc ( content = machineTag ( namespace = namespace , predicate = predicate [ ' description ' ] ) , adoc = doc , t = ' description ' )
2017-12-01 08:54:34 +01:00
if predicate . get ( ' exclusive ' ) :
doc = asciidoc ( content = machineTag ( namespace = namespace , predicate = predicate [ ' exclusive ' ] ) , adoc = doc , t = ' exclusive ' )
2015-12-01 17:11:43 +01:00
if t . get ( ' values ' ) is None :
2015-11-29 15:29:49 +01:00
if args . a :
doc = asciidoc ( content = machineTag ( namespace = namespace , predicate = predicate [ ' value ' ] ) , adoc = doc )
doc = asciidoc ( content = machineTag ( namespace = namespace , predicate = predicate [ ' expanded ' ] ) , adoc = doc , t = ' description ' )
2015-12-01 17:37:00 +01:00
if predicate . get ( ' description ' ) :
doc = asciidoc ( content = machineTag ( namespace = namespace , predicate = predicate [ ' description ' ] ) , adoc = doc , t = ' description ' )
2017-12-01 07:55:35 +01:00
if predicate . get ( ' numerical_value ' ) :
2018-03-16 12:01:23 +01:00
doc = asciidoc ( content = machineTag ( namespace = namespace , predicate = predicate [ ' numerical_value ' ] ) , adoc = doc , t = ' description ' )
2017-12-01 08:54:34 +01:00
if predicate . get ( ' exclusive ' ) :
doc = asciidoc ( content = machineTag ( namespace = namespace , predicate = predicate [ ' exclusive ' ] ) , adoc = adoc , t = ' exclusive ' )
2015-11-29 15:29:49 +01:00
else :
2017-04-02 22:06:32 +02:00
print ( machineTag ( namespace = namespace , predicate = predicate [ ' value ' ] ) )
2015-11-22 08:16:09 +01:00
if args . e :
2017-04-02 22:06:32 +02:00
print ( " --> " + machineTag ( namespace = expanded_namespace , predicate = predicate [ ' expanded ' ] ) )
if predicate . get ( ' description ' ) :
print ( " --> " + predicate [ ' description ' ] )
2015-11-22 08:16:09 +01:00
else :
for e in t [ ' values ' ] :
if e [ ' predicate ' ] == predicate [ ' value ' ] :
2015-11-24 09:17:16 +01:00
if ' expanded ' in predicate :
expanded = predicate [ ' expanded ' ]
2015-11-22 08:16:09 +01:00
for v in e [ ' entry ' ] :
2016-06-21 07:53:31 +02:00
if args . a and ' expanded ' in v :
2015-11-29 15:29:49 +01:00
doc = asciidoc ( content = machineTag ( namespace = namespace , predicate = e [ ' predicate ' ] , value = v [ ' value ' ] ) , adoc = doc )
doc = asciidoc ( content = machineTag ( namespace = namespace , predicate = v [ ' expanded ' ] ) , adoc = doc , t = ' description ' )
2017-10-25 15:15:05 +02:00
if ' description ' in v :
doc = asciidoc ( content = machineTag ( namespace = namespace , predicate = v [ ' description ' ] ) , adoc = doc , t = ' description ' )
2017-12-01 07:55:35 +01:00
if v . get ( ' numerical_value ' ) :
doc = asciidoc ( content = machineTag ( namespace = namespace , predicate = v [ ' numerical_value ' ] ) , adoc = doc , t = ' numerical_value ' )
2015-11-29 15:29:49 +01:00
else :
2017-04-02 22:06:32 +02:00
print ( machineTag ( namespace = namespace , predicate = e [ ' predicate ' ] , value = v [ ' value ' ] ) )
2015-11-22 08:16:09 +01:00
if args . e :
2016-06-21 07:35:55 +02:00
if ' expanded ' in v :
2017-04-02 22:06:32 +02:00
print ( " --> " + machineTag ( namespace = namespace , predicate = expanded , value = v [ ' expanded ' ] ) )
2015-11-29 15:29:49 +01:00
2017-10-24 07:49:19 +02:00
with open ( ' ../mapping/mapping.json ' ) as mapping :
m = json . load ( mapping )
output = ' \n = Mapping of taxonomies \n '
output = ' {} {} ' . format ( output , ' Analysts relying on taxonomies don \' t always know the appropriate namespace to use but know which value to use for classification. The MISP mapping taxonomy allows to map a single classification into a series of machine-tag synonyms. \n ' )
for value in sorted ( m . keys ( ) ) :
output = ' {} {} ** {} ** {} {} \n ' . format ( output , ' \n .Mapping table - ' , value , ' \n |=== \n | ' , value )
for mapped in m [ value ] [ ' values ' ] :
output = ' {} | {} \n ' . format ( output , mapped )
output = ' {} |=== \n ' . format ( output )
doc = doc + output
2015-11-29 15:29:49 +01:00
if args . a :
2017-04-02 22:06:32 +02:00
print ( doc )