Added EEAS framework objects and STIX generator

Added framework objects:
- Added technique T0066 "Degrade adversary" to TA02
- Added technique T0067 "Plan to discredit credible sources" to TA02
- Added technique T0068 "respond to breaking news event" to TA02
- Added technique T0069  "respond to active crisis" to TA02
- Added technique T0070 "Analyze existing communities" to TA02
- Added technique T0071 "Find echo chambers" to TA13
- Added technique T0072  "Segment audiences" to TA13

Added STIX generator from repo DISARM-stix2, and added code to generate github files, databases, and STIX from the same Jupyter notebook.
This commit is contained in:
Sara-Jayne Terp 2022-02-20 15:40:34 -05:00
parent 2117dcf09b
commit c11e9d06ad
46 changed files with 2428 additions and 17533 deletions

BIN
CODE/DISARM-STIX2/.DS_Store vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,33 @@
# DISARM STIX2 Generator
## Usage
1. Clone this repository.
2. Download the latest version of the DISARM Framework xlsx [here](https://github.com/DISARMFoundation/DISARMframeworks).
3. Copy the xlsx to the root directory of this repository.
4. Run `python3 main.py` to generate STIX objects in the `output/` folder.
5. `output/DISARM.json` contains the complete STIX bundle. The folders in `output/` contain individual objects for reference.
## DISARM STIX2
The DISARM STIX2 Generator encodes the DISARM object into the corresponding STIX2 object shown in the following table.
| DISARM | STIX2 |
|-----------|-----------------------|
| Matrix | Matrix (MITRE custom) |
| Tactic | Tactic (MITRE custom) |
| Technique | AttackPattern |
## MITRE ATT&CK Navigator
DISARM STIX is compatible with the MITRE ATT&CK Navigator.
DISARM object types, such as `Matrix`, `Tatic` are prefixed with `x-mitre--` for compatibility reasons.
DISARM `AttackPattern` objects also contain `x_mitre_is_subtechnique` and `x_mitre_platforms` properties for compatability. These properties cannot be removed without upstream changes to the ATT&CK Navigator.
## OpenCTI
DISARM STIX can be imported into OpenCTI via the OpenCTI STIX Importer plugin which is installed in OpenCTI by default.
Alternatively, use the OpenCTI DISARM plugin to continuously pull the latest DISARM STIX.

Binary file not shown.

View file

@ -0,0 +1,82 @@
import json
import os
from stix2 import Bundle
import shutil
outdir = '../generated_files/DISARM_STIX/'
def write_disarm_dir(dir, outdir=outdir):
"""
Args:
dir (str): a directory name
Returns:
"""
try:
os.mkdir(outdir)
except FileExistsError:
pass
try:
os.mkdir(outdir + dir)
except FileExistsError:
pass
def clean_output_dir(outdir=outdir):
"""Recursively delete the output folder.
Returns:
"""
try:
os.mkdir(outdir)
except FileExistsError:
pass
shutil.rmtree(outdir)
def write_file(file_name, file_data):
"""Write a JSON file to outdir
Args:
file_name (str): a file name
file_data (str): the file json data
Returns:
"""
with open(file_name, 'w') as f:
# f.write(json.dumps(file_data, sort_keys=True, indent=4))
f.write(file_data.serialize(pretty=True))
f.write('\n')
def write_files(stix_objects, outdir=outdir):
"""
Args:
stix_objects:
Returns:
"""
for i in stix_objects:
write_disarm_dir(i.type)
write_file(outdir+f"{i.type}/{i.id}.json", Bundle(i, allow_custom=True))
def write_bundle(bundle, bundle_name, outdir=outdir):
"""
Args:
bundle:
bundle_name:
Returns:
"""
write_file(outdir+f"{bundle_name}.json", bundle)

View file

@ -0,0 +1,19 @@
import pandas as pd
def load_excel_data(infile):
"""Load an xlsx document.
Args:
infile (str): Path to an xlsx file.
Returns:
dict: xlsx sheets
"""
sheets = {}
xlsx = pd.ExcelFile(infile)
for sheetname in xlsx.sheet_names:
sheets[sheetname] = xlsx.parse(sheetname)
return sheets

49
CODE/DISARM-STIX2/main.py Normal file
View file

@ -0,0 +1,49 @@
# A STIX bundle generator for the DISARM Framework.
#
# Author: Roger Johnston, Twitter: @VV_X_7
# License: GPL-3
import pandas as pd
import openpyxl
from stix2 import (Bundle, AttackPattern, ThreatActor, IntrusionSet, Relationship, CustomObject, properties,
Malware, Tool, Campaign, Identity, MarkingDefinition, ExternalReference, StatementMarking,
GranularMarking, Location, MemoryStore, Filter)
from stix2.properties import (ReferenceProperty, ListProperty, StringProperty, TimestampProperty, BooleanProperty, IntegerProperty)
import helpers
from objects import tactic, technique, matrix, bundle
from helpers import xlsx, file
def generate_disarm_stix():
"""Generates a DISARM STIX bundle.
Returns:
"""
data = helpers.xlsx.load_excel_data("../DISARM_MASTER_DATA/DISARM_FRAMEWORKS_MASTER.xlsx")
tactics = tactic.make_disarm_tactics(data)
techniques = technique.make_disarm_techniques(data)
navigator_matrix = matrix.make_disarm_matrix(tactics)
stix_objects = []
stix_objects.append(tactics)
stix_objects.append(techniques)
stix_objects.append(navigator_matrix)
stix_objects = [item for sublist in stix_objects for item in sublist]
# for i in stix_objects:
# print(i)
disarm_bundle = bundle.make_stix_bundle(stix_objects)
helpers.file.clean_output_dir()
helpers.file.write_files(stix_objects)
helpers.file.write_bundle(disarm_bundle, "DISARM")
if __name__ == "__main__":
generate_disarm_stix()

View file

@ -0,0 +1,15 @@
from stix2 import Bundle
def make_stix_bundle(stix_objects):
"""Makes a STIX Bundle object.
Args:
stix_objects (list): A list of STIX objects.
Returns:
Bundle: A STIX Bundle object.
"""
bundle = Bundle(stix_objects, allow_custom=True)
return bundle

View file

@ -0,0 +1,16 @@
from stix2 import Identity
def make_disarm_identity():
"""Creates the default DISARM identity used for indicating authorship of various components in the bundle.
Returns:
identity: a STIX Identity object
"""
identity = Identity(
name="DISARM Foundation",
identity_class="organization",
description="DISARM is a framework designed for describing and understanding disinformation incidents.",
)
return identity

View file

@ -0,0 +1,11 @@
from stix2 import MarkingDefinition, StatementMarking
from objects import identity
def make_disarm_marking_definition():
marking_definition = MarkingDefinition(
definition_type="statement",
created_by_ref=identity.make_disarm_identity(),
definition=StatementMarking(statement="CC-BY-SA-4.0 DISARM Foundation")
)
return marking_definition

View file

@ -0,0 +1,51 @@
from stix2 import CustomObject, properties, ExternalReference
import objects.marking_definition
from objects import identity, marking_definition
@CustomObject('x-mitre-matrix', [
('name', properties.StringProperty(required=True)),
('description', properties.StringProperty(required=True)),
('tactic_refs', properties.ListProperty(properties.ReferenceProperty(valid_types="SDO"), required=True))
])
class Matrix(object):
def __init__(self, **kwargs):
if True:
pass
def make_disarm_matrix(tactics):
"""Creates a Matrix object.
Args:
tactics: A list of Tactic objects.
Returns:
"""
description = 'DISARM is a framework designed for describing and understanding disinformation incidents.'
external_references = [
{
"external_id": "DISARM",
"source_name": "DISARM",
"url": "https://github.com/DISARMFoundation"
}
]
name = 'DISARM Framework'
# print(tactics)
# p =[i.id for i in tactics]
# r = properties.ReferenceProperty()
# f = properties.ListProperty(r)
tactic_refs = [i.id for i in tactics]
matrix = Matrix(
name=name,
description=description,
external_references=external_references,
tactic_refs=tactic_refs,
allow_custom=True
)
return [matrix]

View file

@ -0,0 +1,21 @@
from stix2 import Relationship, properties, ExternalReference
def make_disarm_subtechnique_relationship(source, target):
"""Creates a relationship between the parent technique and sub-technique.
Args:
source (str): Subtechnique ID
target (str): Parent technique ID
Returns:
A Relationship object.
"""
relationship = Relationship(
source_ref=source,
target_ref=target,
relationship_type="subtechnique-of"
)
return relationship

View file

@ -0,0 +1,57 @@
from stix2 import CustomObject, properties, ExternalReference
import objects.marking_definition
from objects import identity, marking_definition
@CustomObject('x-mitre-tactic', [
('name', properties.StringProperty(required=True)),
('description', properties.StringProperty(required=True)),
('x_mitre_shortname', properties.StringProperty(required=True)),
('external_references', properties.ListProperty(ExternalReference))
])
class Tactic(object):
def __init__(self, x_mitre_shortname=None, **kwargs):
if x_mitre_shortname and x_mitre_shortname not in ["strategic-planning", "objective-planning",
"develop-people", "develop-persona",
"develop-networks", "microtargeting", "develop-content",
"channel-selection", "pump-priming", "exposure",
"go-physical",
"persistence", "measure-effectiveness"]:
# raise ValueError("'%s' is not a recognized DISARM Tactic." % x_mitre_shortname)
print("'%s' is not a recognized DISARM Tactic." % x_mitre_shortname)
def make_disarm_tactics(data):
"""Create all DISARM tactic objects.
Args:
data: The xlsx tactic sheet.
Returns:
A list of Tactics.
"""
tactics = []
for t in data["tactics"].values.tolist():
external_references = [
{
'external_id': f'{t[0]}',
'source_name': 'DISARM',
'url': f'https://github.com/DISARMFoundation/DISARM_framework/blob/master/tactics/{t[0]}.md'
}
]
tactic = Tactic(
name=f"{t[1]}",
description=f"{t[5]}",
x_mitre_shortname=f'{t[1].lower().replace(" ", "-")}',
external_references=external_references,
object_marking_refs=objects.marking_definition.make_disarm_marking_definition(),
created_by_ref=objects.identity.make_disarm_identity()
)
tactics.append(tactic)
return tactics

View file

@ -0,0 +1,71 @@
from stix2 import AttackPattern, properties, ExternalReference
import objects.marking_definition
import pandas as pd
from objects import identity, marking_definition
def make_disarm_techniques(data):
"""Create all DISARM Techniques objects.
Args:
data: The xlsx technique sheet.
Returns:
A list of Techniques.
"""
tacdict = pd.Series(data["tactics"].name.values, index=data["tactics"].disarm_id).to_dict()
techniques = []
for t in data["techniques"].values.tolist():
external_references = [
{
'external_id': f'{t[0]}',
'source_name': 'DISARM',
'url': f'https://github.com/DISARMFoundation/DISARM_framework/blob/master/techniques/{t[0]}.md'
}
]
kill_chain_phases = [
{
'phase_name': tacdict[t[3]].replace(' ', '-').lower(),
'kill_chain_name': 'mitre-attack'
}
]
subtechnique = t[0].split(".")
x_mitre_is_subtechnique = False
if len(subtechnique) > 1:
x_mitre_is_subtechnique = True
# MITRE ATT&CK Navigator expect techniques to have at least one of these platforms.
# Without one, the technique will not render in the Navigator.
x_mitre_platforms = 'Windows', 'Linux', 'Mac'
technique = AttackPattern(
name=f"{t[1]}",
description=f"{t[3]}",
external_references=external_references,
object_marking_refs=objects.marking_definition.make_disarm_marking_definition(),
created_by_ref=objects.identity.make_disarm_identity(),
kill_chain_phases=kill_chain_phases,
custom_properties={
'x_mitre_platforms': x_mitre_platforms,
'x_mitre_version': "1,0",
'x_mitre_is_subtechnique': x_mitre_is_subtechnique
}
)
techniques.append(technique)
return techniques
def make_subtechnique_map(techinques):
"""
Args:
techinques:
Returns:
"""
pass

View file

@ -0,0 +1,3 @@
pandas
openpyxl
stix2