Threat Actor profiling¶
Introduction¶
- UUID: bf0d86c4-b795-48a7-a3a9-e625620d1726
- Started from issue 26
- State: Published : demo version with output
- Purpose:
- This playbook queries MISP events associated with a specific threat actor.
- The playbook summaries the galaxies, clusters and tags from the MISP events, lists the vulnerabilities (CVE) and the actionable indicators.
- Optionally the playbook queries the MITRE TAXII server to get a list of associated techniques and software.
- The result of the playbook is a profile on a threat actor based on the MISP events.
- The results are stored in the playbook and sent to Mattermost and as an alert in TheHive.
- Tags: [ "mitre", "actor", "intrusion-set", "galaxies", "clusters", "contextualisation" ]
- External resources:
- Target audience: CTI
Playbook TOC¶
- Threat Actor profiling
- Introduction
- Preparation
- PR:1 Initialise environment
- PR:2 Set helper variables
- PR:3 MISP galaxies and clusters
- PR:4 Load galaxies and clusters
- Investigate
- IN:1 User input: Which threat actor to profile?
- IN:2 Search threat actor in galaxy / cluster
- IN:3 MISP tags to search events
- IN:4 Additional tags for event filtering
- Profile
- PO:1 Search MISP events
- PO:2 Context in other MISP events
- PO:3 Vulnerabilities exploited
- PO:4 Indicators
- PO:5 Victims, countries and incident types from galaxy/cluster
- PO:6 Information from MITRE
- Closure
- EN:1 Create the summary of the playbook
- EN:2 Send a summary to Mattermost
- EN:3 Send an alert to TheHive
- EN:4 End of the playbook
- External references
- Technical details
Preparation¶
PR:1 Initialise environment¶
This section initialises the playbook environment and loads the required Python libraries. The credentials for MISP (API key) and other services are loaded from the file keys.py
in the directory vault. A PyMISP object is created to interact with MISP and the active MISP server is displayed. By printing out the server name you know that it's possible to connect to MISP. In case of a problem PyMISP will indicate the error with PyMISPError: Unable to connect to MISP
.
The contents of the keys.py
file should contain at least :
misp_url="<MISP URL>" # The URL to our MISP server
misp_key="<MISP API KEY>" # The MISP API key
misp_verifycert=<True or False> # Indicate if PyMISP should attempt to verify the certificate or ignore errors
mattermost_playbook_user
mattermost_hook
thehive_url
thehive_key
# Initialise Python environment
import urllib3
import sys
import json
from prettytable import PrettyTable, MARKDOWN
from datetime import date
import requests
import uuid
from pymisp import *
import time
import csv
import codecs
from contextlib import closing
from IPython.display import display, Image, Markdown, display_markdown
import re
from attackcti import attack_client
import random
# Load the credentials
sys.path.insert(0, "../vault/")
from keys import *
if misp_verifycert is False:
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
print("The \033[92mPython libraries\033[90m are loaded and the \033[92mcredentials\033[90m are read from the keys file.")
# Create the PyMISP object
misp = PyMISP(misp_url, misp_key, misp_verifycert)
print("I will use the MISP server \033[92m{}\033[90m for this playbook.\n\n".format(misp_url))
The Python libraries are loaded and the credentials are read from the keys file. I will use the MISP server https://misp.demo.cudeso.be/ for this playbook.
PR:2 Set helper variables¶
This cell contains helper variables for this playbook.
# Init variables
threat_actors = {}
search_actor = ""
summary = ""
table_mispevents, table_context, table_cve, table_indicators, table_mitre_techniques, table_mitre_software = "", "", "", "", "", ""
playbook_results = {"events": [], "galaxies": [], "galaxy_clusters": [], "tags": [], "vulnerabilities": [], "indicators": {}}
search_actor_match = {"actors": [], "tags": []}
search_actor_tags = []
search_actor_names = []
actor_victims, actor_country, actor_incident_type, actor_target = [], [], [], []
PR:3 MISP galaxies and clusters¶
What are galaxies and clusters?¶
The MISP galaxies and clusters are an easy way for threat analysts to add contextual information to threat events. They allow you to refer to threat actors, tactics and techniques, malware and toolsets. They also allow you to express relationships between elements, such as threat actor synonyms, the software threat actors use or the techniques they employ.
Threat actors¶
The most popular galaxy is the one implementing the MITRE ATT&CK framework. In this framework the threat actors are listed as Intrusion Set. The most comprehensive group of threat actors is in the MISP Threat Actor galaxy. In this playbook we search in both sets, and the playbook will indicate in which set the threat actor has been found. Where possible, the link is made between the MISP Threat Actor galaxy and the MITRE ATT&CK Intrusion Set. There are other galaxies containing threat actors, such as the Microsoft Activity Group, the 360.net Threat Actors or Malpedia.
Metadata¶
The metadata of clusters contain a list of custom defined JSON key value pairs that describe additional metadata, such as victims (cfr-suspected-victims) or targets (cfr-target-category). In this playbook we use this metadata to provide additional context for your results.
Relationships¶
The MISP galaxies and clusters also contain relationships to other galaxies and clusters. Unfortunately in the current PyMISP version it's not possible to easily query these relationships. The relationships are available though via the "normal" MISP REST API. For example the below query returns the clusters (similar to the PyMISP functions get_galaxy
and get_galaxy_cluster
), but also includes a key GalaxyClusterRelation
, that you can use to list the relationships.
curl \
-d '{"id":"24769"}' \
-H "Authorization: MISP_KEY" \
-H "Accept: application/json" \
-H "Content-type: application/json" \
-X POST https://MISP_URL/galaxy_clusters/restSearch
Custom clusters¶
You're not limited to the clusters that are provided by the MISP project. It's possible to add your own private clusters, for example to label exotic flavours of malware or track threat actors specifically targeting your organisation. You can add custom clusters by going to Galaxies, select a galaxy, then click on Add cluster. For your intel work it can be useful to add relations to similar threat actor groups, malware or attack techniques. And finally, do not forget to publish (similar as with MISP events) the cluster to make it available to your users.
MISP Threat Actor Intelligence Server¶
In this playbook we use the galaxy and clusters available on your MISP server. As an alternative way of getting access to galaxies and clusters you can directly parse the JSON files that are in the GitHub repository. But there's another, less known, option: the MISP Threat Actor Intelligence Server. You can setup your own server and there's also one freely available by the MISP project. You can use the results from this TAI (Threat Actor Intelligence) server with MISP playbooks but you can also leverage the results in other tools, such as during report composition.
Execute the next cell to get a glimpse on what's available via such TAI server. This playbook is not using these results but they might give you some ideas how to use them in other use cases.
# Query the Threat Actor Intelligence server at misp-project.org.
# You can skip executing this cell, it's added for demonstrating that there is a TAI
search_actor = "APT-28"
search_actor_str = re.sub(r'[^a-zA-Z0-9]', '', search_actor.lower().strip())
intel_server_url = "https://www.misp-project.org/tai/query"
headers = {"Content-Type":"application/json"}
result = requests.post(intel_server_url, json={"name":search_actor_str}, headers=headers)
print(json.dumps(result.json(), indent=2))
[ { "description": "The Sofacy Group (also known as APT28, Pawn Storm, Fancy Bear and Sednit) is a cyber espionage group believed to have ties to the Russian government. Likely operating since 2007, the group is known to target government, military, and security organizations. It has been characterized as an advanced persistent threat.", "meta": { "attribution-confidence": "50", "cfr-suspected-state-sponsor": "Russian Federation", "cfr-suspected-victims": [ "Georgia", "France", "Jordan", "United States", "Hungary", "World Anti-Doping Agency", "Armenia", "Tajikistan", "Japan", "NATO", "Ukraine", "Belgium", "Pakistan", "Asia Pacific Economic Cooperation", "International Association of Athletics Federations", "Turkey", "Mongolia", "OSCE", "United Kingdom", "Germany", "Poland", "European Commission", "Afghanistan", "Kazakhstan", "China" ], "cfr-target-category": [ "Government", "Military" ], "cfr-type-of-incident": "Espionage", "country": "RU", "refs": [ "https://attack.mitre.org/groups/G0007/", "https://en.wikipedia.org/wiki/Fancy_Bear", "https://en.wikipedia.org/wiki/Sofacy_Group", "https://www.bbc.com/news/technology-37590375", "https://www.bbc.co.uk/news/technology-45257081", "https://www.cfr.org/interactive/cyber-operations/apt-28", "https://www.apnews.com/4d174e45ef5843a0ba82e804f080988f", "https://www.voanews.com/a/iaaf-hack-fancy-bears/3793874.html", "https://securelist.com/a-slice-of-2017-sofacy-activity/83930/", "https://www.dw.com/en/hackers-lurking-parliamentarians-told/a-19564630", "https://unit42.paloaltonetworks.com/unit42-sofacys-komplex-os-x-trojan/", "https://unit42.paloaltonetworks.com/dear-joohn-sofacy-groups-global-campaign/", "https://www.fireeye.com/blog/threat-research/2015/04/probable_apt28_useo.html", "https://www2.fireeye.com/rs/848-DID-242/images/wp-mandiant-matryoshka-mining.pdf", "https://www.eff.org/deeplinks/2015/08/new-spear-phishing-campaign-pretends-be-eff", "https://aptnotes.malwareconfig.com/web/viewer.html?file=../APTnotes/2014/apt28.pdf", "https://www.accenture.com/us-en/blogs/blogs-snakemackerel-delivers-zekapab-malware", "https://www.wired.com/story/russian-fancy-bears-hackers-release-apparent-ioc-emails/", "https://symantec-blogs.broadcom.com/blogs/election-security/apt28-espionage-military-government", "https://www.crowdstrike.com/blog/bears-midst-intrusion-democratic-national-committee/", "https://unit42.paloaltonetworks.com/unit42-sofacy-attacks-multiple-government-entities/", "https://securelist.com/sofacy-apt-hits-high-profile-targets-with-updated-toolset/72924/", "https://www.msn.com/en-nz/news/world/russian-hackers-accused-of-targeting-un-chemical-weapons-watchdog-mh17-files/ar-BBNV2ny", "https://unit42.paloaltonetworks.com/unit42-new-sofacy-attacks-against-us-government-agency/", "https://unit42.paloaltonetworks.com/unit42-let-ride-sofacy-groups-dealerschoice-attacks-continue/", "https://www.welivesecurity.com/2018/09/27/lojax-first-uefi-rootkit-found-wild-courtesy-sednit-group/", "https://unit42.paloaltonetworks.com/unit42-sofacy-continues-global-attacks-wheels-new-cannon-trojan/", "https://www.bleepingcomputer.com/news/security/apt28-uses-lojax-first-uefi-rootkit-seen-in-the-wild/", "https://blog.trendmicro.com/trendlabs-security-intelligence/pawn-storm-targets-mh17-investigation-team/", "https://researchcenter.paloaltonetworks.com/2016/06/unit42-new-sofacy-attacks-against-us-government-agency/", "https://www.trendmicro.com/cloud-content/us/pdfs/security-intelligence/white-papers/wp-operation-pawn-storm.pdf", "https://blog.trendmicro.com/trendlabs-security-intelligence/new-adobe-flash-zero-day-used-in-pawn-storm-campaign/", "https://blogs.microsoft.com/on-the-issues/2018/08/20/we-are-taking-new-steps-against-broadening-threats-to-democracy/", "https://www.lse.co.uk/AllNews.asp?code=kwdwehme&headline=Russian_Hackers_Suspected_In_Cyberattack_On_German_Parliament", "https://www.volkskrant.nl/cultuur-media/russen-faalden-bij-hackpogingen-ambtenaren-op-nederlandse-ministeries~b77ff391/", "https://www.ibtimes.co.uk/russian-hackers-fancy-bear-likely-breached-olympic-drug-testing-agency-dnc-experts-say-1577508", "https://www.bleepingcomputer.com/news/security/microsoft-disrupts-apt28-hacking-campaign-aimed-at-us-midterm-elections/", "https://www.justice.gov/opa/pr/justice-department-announces-actions-disrupt-advanced-persistent-threat-28-botnet-infected", "https://www.accenture.com/t20181129T203820Z__w__/us-en/_acnmedia/PDF-90/Accenture-snakemackerel-delivers-zekapab-malware.pdf", "https://www.reuters.com/article/us-sweden-doping/swedish-sports-body-says-anti-doping-unit-hit-by-hacking-attack-idUSKCN1IG2GN", "https://researchcenter.paloaltonetworks.com/2016/10/unit42-dealerschoice-sofacys-flash-player-exploit-platform/", "https://netzpolitik.org/2015/digital-attack-on-german-parliament-investigative-report-on-the-hack-of-the-left-party-infrastructure-in-bundestag/", "https://www.washingtonpost.com/technology/2019/02/20/microsoft-says-it-has-found-another-russian-operation-targeting-prominent-think-tanks/?utm_term=.870ff11468ae", "https://www.handelsblatt.com/today/politics/election-risks-russia-linked-hackers-target-german-political-foundations/23569188.html?ticket=ST-2696734-GRHgtQukDIEXeSOwksXO-ap1", "https://www.accenture.com/t20190213T141124Z__w__/us-en/_acnmedia/PDF-94/Accenture-SNAKEMACKEREL-Threat-Campaign-Likely-Targeting-NATO-Members-Defense-and-Military-Outlets.pdf", "https://marcoramilli.com/2019/12/05/apt28-attacks-evolution/", "https://www.microsoft.com/security/blog/2020/09/10/strontium-detecting-new-patters-credential-harvesting/", "https://www.bleepingcomputer.com/news/security/russian-hackers-use-fake-nato-training-docs-to-breach-govt-networks/", "https://quointelligence.eu/2020/09/apt28-zebrocy-malware-campaign-nato-theme/", "https://unit42.paloaltonetworks.com/atoms/fighting-ursa/", "https://blog.google/threat-analysis-group/continued-cyber-activity-in-eastern-europe-observed-by-tag" ], "synonyms": [ "APT 28", "APT28", "Pawn Storm", "PawnStorm", "FANCY BEAR", "Sednit", "SNAKEMACKEREL", "TsarTeam", "Tsar Team", "TG-4127", "Group-4127", "STRONTIUM", "TAG_0700", "Swallowtail", "IRON TWILIGHT", "Group 74", "SIG40", "Grizzly Steppe", "apt_sofacy", "G0007", "ATK5", "Fighting Ursa" ] }, "related": [ { "dest-uuid": "bef4c620-0787-42a8-a96d-b7eb6e85917c", "tags": [ "estimative-language:likelihood-probability=\"likely\"" ], "type": "similar" }, { "dest-uuid": "213cdde9-c11a-4ea9-8ce0-c868e9826fec", "tags": [ "estimative-language:likelihood-probability=\"likely\"" ], "type": "similar" } ], "uuid": "5b4ee3ea-eee3-4c8e-8323-85ae32658754", "value": "Sofacy" } ]
PR:4 Load galaxies and clusters¶
Tthe playbook first loads galaxies and clusters in the Python list threat_actors
. It uses these galaxies to have a good coverage of threat actors:
You can then use the playbook to search for threat actors via their name or their synonyms. Note that there is a PyMISP function search_galaxy_clusters that allows you to search for a value but in this playbook we want to restrict the search results to name and synoyms only.
Load the MISP Threat Actor galaxy¶
# Search in the MISP Threat Actor galaxy
galaxy_id_misp = 0
result = misp.search_galaxy("misp")
for galaxy in result:
if galaxy["Galaxy"].get("name", False) == "Threat Actor":
galaxy_id_misp = int(galaxy["Galaxy"]["id"])
if galaxy_id_misp > 0:
result = misp.get_galaxy(galaxy_id_misp)
for cluster in result.get("GalaxyCluster", []):
synonyms, victims, target, country, incident_type, mitre_group = [], [], [], [], [], []
for element in cluster.get("GalaxyElement", []):
if element["key"] == "synonyms":
if re.match("G\d{4}", element["value"]):
mitre_group.append(element["value"])
synonyms.append(element["value"])
elif element["key"] == "cfr-suspected-victims":
victims.append(element["value"])
elif element["key"] == "cfr-target-category":
target.append(element["value"])
elif element["key"] == "country":
country.append(element["value"])
elif element["key"] == "cfr-type-of-incident":
incident_type.append(element["value"])
entry = {"source": "misp", "value": cluster["value"], "uuid": cluster["uuid"], "synonyms": synonyms, "tag": cluster["tag_name"],
"mitre_group": mitre_group, "victims": victims, "target": target, "country": country, "incident_type": incident_type}
threat_actors[cluster["value"]] = entry
print("Found \033[92m{}\033[90m threat actors in MISP Threat Actor galaxy.".format(len(threat_actors)))
Found 499 threat actors in MISP Threat Actor galaxy.
Load the MITRE ATT&CK Intrusion Set¶
Next we load the threat actors (or called Intrusion Set) from the MITRE ATT&CK Intrusion Set galaxy. On most MISP systems this search matches with Intrusion Set
, Pre Attack - Intrusion Set
, Enterprise Attack - Intrusion Set
, and Mobile Attack - Intrusion Set
.
# Search in the MITRE ATT&CK Intrusion Set
start_count = len(threat_actors)
result = misp.search_galaxy("Intrusion Set")
for galaxy in result:
print("Loading from \033[92m{}\033[90m".format(galaxy["Galaxy"]["name"]))
galaxy_id = int(galaxy["Galaxy"]["id"])
result = misp.get_galaxy(galaxy_id)
for cluster in result.get("GalaxyCluster", []):
synonyms, mitre_group = [], []
for element in cluster.get("GalaxyElement", []):
if element["key"] == "synonyms":
synonyms.append(element["value"])
elif element["key"] == "external_id":
mitre_group.append(element["value"])
#Anticipate double entries
tag = list(set([cluster["tag_name"]]).union(set(threat_actors.get(cluster["value"], {}).get("tag", []))))
synonym = list(set(synonyms).union(set(threat_actors.get(cluster["value"], {}).get("synonyms", []))))
mitre_group = list(set(mitre_group).union(set(threat_actors.get(cluster["value"], {}).get("mitre_group", []))))
uuid = list(set([cluster["uuid"]]).union(set(threat_actors.get(cluster["value"], {}).get("uuid", []))))
entry = {"source": "mitre", "value": cluster["value"], "uuid": uuid, "synonyms": synonyms, "tag": tag,
"mitre_group": mitre_group}
threat_actors[cluster["value"]] = entry
print("Found \033[92m{}\033[90m threat actors in MITRE ATT&CK Intrusion Set.".format(len(threat_actors) - start_count))
Loading from Intrusion Set Loading from Pre Attack - Intrusion Set Loading from Enterprise Attack - Intrusion Set Loading from Mobile Attack - Intrusion Set Found 139 threat actors in MITRE ATT&CK Intrusion Set.
Loaded threat actors¶
The next cell gives an overview of all the loaded threat actors. You can easily spot the different sources (misp or mitre), their name and the MISP anchor tag. In a later phase the playbook uses these tags to search for events that have the corresponding tag (or in this case threat actor / cluster) attached.
Because the list of threat actors is fairly long, the output of the table is limited to 15 actors. Change limit_output
if you want to display more threat actors.
limit_output = 15 # Set to len(threat_actors) to print all rows
table = PrettyTable()
table.field_names = ["Source", "Threat actor", "MITRE", "Synonyms", "Tag"]
table.align = "l"
for result in threat_actors:
synonyms = ""
for el in threat_actors[result].get("synonyms", []):
synonyms = "{}{}\n".format(synonyms, el.strip())
table.add_row([threat_actors[result]["source"], threat_actors[result]["value"].strip(), threat_actors[result]["mitre_group"],
synonyms.strip(), threat_actors[result]["tag"]])
print(table.get_string(sortby="Threat actor", end=limit_output))
+--------+-------------------+-----------+-------------------+--------------------------------------------------------+ | Source | Threat actor | MITRE | Synonyms | Tag | +--------+-------------------+-----------+-------------------+--------------------------------------------------------+ | misp | ALLANITE | [] | Palmetto Fusion | misp-galaxy:threat-actor="ALLANITE" | | | | | Allanite | | | misp | ANDROMEDA SPIDER | [] | | misp-galaxy:threat-actor="ANDROMEDA SPIDER" | | misp | ANTHROPOID SPIDER | [] | Empire Monkey | misp-galaxy:threat-actor="ANTHROPOID SPIDER" | | | | | CobaltGoblin | | | misp | APT 16 | [] | APT16 | misp-galaxy:threat-actor="APT 16" | | | | | SVCMONDR | | | misp | APT 22 | [] | APT22 | misp-galaxy:threat-actor="APT 22" | | | | | BRONZE OLIVE | | | misp | APT 26 | [] | APT26 | misp-galaxy:threat-actor="APT 26" | | | | | Hippo Team | | | | | | JerseyMikes | | | | | | Turbine Panda | | | | | | BRONZE EXPRESS | | | misp | APT 29 | [] | Dukes | misp-galaxy:threat-actor="APT 29" | | | | | Group 100 | | | | | | Cozy Duke | | | | | | CozyDuke | | | | | | EuroAPT | | | | | | CozyBear | | | | | | CozyCar | | | | | | Cozer | | | | | | Office Monkeys | | | | | | OfficeMonkeys | | | | | | APT29 | | | | | | Cozy Bear | | | | | | The Dukes | | | | | | Minidionis | | | | | | SeaDuke | | | | | | Hammer Toss | | | | | | YTTRIUM | | | | | | Iron Hemlock | | | | | | Grizzly Steppe | | | misp | APT 30 | [] | APT30 | misp-galaxy:threat-actor="APT 30" | | misp | APT 6 | [] | 1.php Group | misp-galaxy:threat-actor="APT 6" | | | | | APT6 | | | misp | APT-C-12 | [] | Sapphire Mushroom | misp-galaxy:threat-actor="APT-C-12" | | | | | Blue Mushroom | | | | | | NuclearCrisis | | | misp | APT-C-27 | [] | GoldMouse | misp-galaxy:threat-actor="APT-C-27" | | | | | Golden RAT | | | | | | ATK80 | | | misp | APT-C-34 | [] | Golden Falcon | misp-galaxy:threat-actor="APT-C-34" | | misp | APT-C-35 | [] | DoNot Team | misp-galaxy:threat-actor="APT-C-35" | | | | | Donot Team | | | | | | APT-C-35 | | | misp | APT-C-36 | [] | Blind Eagle | misp-galaxy:threat-actor="APT-C-36" | | mitre | APT-C-36 - G0099 | ['G0099'] | APT-C-36 | ['misp-galaxy:mitre-intrusion-set="APT-C-36 - G0099"'] | | | | | Blind Eagle | | +--------+-------------------+-----------+-------------------+--------------------------------------------------------+
Investigate¶
IN:1 User input: Which threat actor to profile?¶
This cell is the primary user input for this playbook. Define the threat actor that you want to profile with this playbook in the variable search_actor
. You can only supply one threat actor as a string.
The search will look for matches in the MISP and MITRE galaxies, both in the threat actor names and synoyms. The search is case insensitive and it removes special characters such as '-'.
# Add the threat actor name or synonym
search_actor = "APT-28"
# Check that we have a valid string before we continue
if type(search_actor) == str and len(search_actor) > 0:
print("The playbook will do the query for \033[92m{}\033[90m\n".format(search_actor))
else:
print("It's \033[91mnot possible to continue\033[90m. Please provide a threat actor name.\n")
The playbook will do the query for APT-28
IN:2 Search threat actor in galaxy / cluster¶
The playbook now searches in the list of MISP galaxies and clusters for the threat actor you supplied earlier. This is done to build a list of synonyms and MISP anchor tags.
search_actor_str = re.sub(r'[^a-zA-Z0-9]', '', search_actor.lower().strip())
print("Searching for {} ...".format(search_actor_str))
for actor in threat_actors:
if search_actor_str in actor.lower():
if threat_actors[actor]["tag"] not in search_actor_match["tags"]:
print(" match found for threat actor name: \033[92m{}\033[90m in {}".format(actor, threat_actors[actor]["source"]))
search_actor_match["tags"].append(threat_actors[actor]["tag"])
search_actor_match["actors"].append(threat_actors[actor])
else:
for synonym in threat_actors[actor].get("synonyms", []):
synonym_str = synonym.lower().strip()
if search_actor_str in synonym_str:
if threat_actors[actor]["tag"] not in search_actor_match["tags"]:
print(" match found for threat actor synonym: \033[92m{}\033[90m in {}".format(actor, threat_actors[actor]["source"]))
search_actor_match["tags"].append(threat_actors[actor]["tag"])
search_actor_match["actors"].append(threat_actors[actor])
print("\n")
if len(search_actor_match) > 0:
table = PrettyTable()
table.field_names = ["Source", "Threat actor", "MITRE", "Synonyms", "Tag"]
table.align = "l"
table._max_width = {"Tag": 40}
for result in search_actor_match["actors"]:
if result["tag"] not in search_actor_tags:
search_actor_tags.append(result["tag"])
if result["value"].strip() not in search_actor_names:
search_actor_names.append(result["value"].strip())
synonyms = ""
for el in result.get("synonyms", []):
synonyms = "{}{}\n".format(synonyms, el.strip())
if el.strip() not in search_actor_names:
search_actor_names.append(el.strip())
table.add_row([result["source"], result["value"].strip(), result["mitre_group"], synonyms.strip(), result["tag"]])
print(table.get_string(sortby="Threat actor"))
table_actor_match = table
print("\n")
else:
print("Unable to find \033[91m{}\033[90m in list of threat actor names or synonyms.\n".format(search_actor))
Searching for apt28 ... match found for threat actor synonym: Sofacy in misp match found for threat actor name: APT28 in misp match found for threat actor name: APT28 - G0007 in mitre +--------+---------------+-----------+-------------------+------------------------------------------+ | Source | Threat actor | MITRE | Synonyms | Tag | +--------+---------------+-----------+-------------------+------------------------------------------+ | misp | APT28 | ['G0007'] | Pawn Storm | misp-galaxy:threat-actor="APT28" | | | | | FANCY BEAR | | | | | | Sednit | | | | | | SNAKEMACKEREL | | | | | | Tsar Team | | | | | | TG-4127 | | | | | | STRONTIUM | | | | | | Swallowtail | | | | | | IRON TWILIGHT | | | | | | Group 74 | | | | | | SIG40 | | | | | | Grizzly Steppe | | | | | | G0007 | | | | | | ATK5 | | | | | | Fighting Ursa | | | | | | ITG05 | | | | | | Blue Athena | | | | | | TA422 | | | | | | T-APT-12 | | | | | | APT-C-20 | | | | | | UAC-0028 | | | mitre | APT28 - G0007 | ['G0007'] | APT28 | ['misp-galaxy:mitre-pre-attack- | | | | | Sednit | intrusion-set="APT28 - G0007"', 'misp- | | | | | Sofacy | galaxy:mitre-intrusion-set="APT28 - | | | | | Pawn Storm | G0007"', 'misp-galaxy:mitre-enterprise- | | | | | Fancy Bear | attack-intrusion-set="APT28 - G0007"', | | | | | STRONTIUM | 'misp-galaxy:mitre-mobile-attack- | | | | | Tsar Team | intrusion-set="APT28 - G0007"'] | | | | | Threat Group-4127 | | | | | | TG-4127 | | | misp | Sofacy | [] | APT 28 | misp-galaxy:threat-actor="Sofacy" | | | | | APT28 | | | | | | Pawn Storm | | | | | | PawnStorm | | | | | | Fancy Bear | | | | | | Sednit | | | | | | SNAKEMACKEREL | | | | | | TsarTeam | | | | | | Tsar Team | | | | | | TG-4127 | | | | | | Group-4127 | | | | | | STRONTIUM | | | | | | TAG_0700 | | | | | | Swallowtail | | | | | | IRON TWILIGHT | | | | | | Group 74 | | | | | | SIG40 | | | | | | Grizzly Steppe | | | | | | apt_sofacy | | +--------+---------------+-----------+-------------------+------------------------------------------+
IN:3 MISP tags to search events¶
The search for threat actors results in a list of MISP anchor tags that are used to query the MISP threat events in the investigation phase.
if len(search_actor_tags) > 0:
search_actor_tags = [item for sublist in search_actor_tags for item in (sublist if isinstance(sublist, list) else [sublist])]
print("The investigation will use these tags to search MISP events:")
for tag in search_actor_tags:
print(" \033[92m{}\033[90m.".format(tag))
else:
print("There are \033[91mno tags\033[90m that can be used to search MISP events.\n")
print("\n")
The investigation will use these tags to search MISP events: misp-galaxy:threat-actor="Sofacy". misp-galaxy:threat-actor="APT28". misp-galaxy:mitre-pre-attack-intrusion-set="APT28 - G0007". misp-galaxy:mitre-intrusion-set="APT28 - G0007". misp-galaxy:mitre-enterprise-attack-intrusion-set="APT28 - G0007". misp-galaxy:mitre-mobile-attack-intrusion-set="APT28 - G0007".
IN:4 Additional tags for event filtering¶
You can specify additional MISP tags (as strings) to filter the events. For example supply the tags "tlp:amber"
or workflow:state="complete"
to fine-tune the search.
misp_additional_filter_tags = ["tlp:white"]
#misp_additional_filter_tags = ["tlp:amber", "workflow:state=\"complete\""]
Profile¶
This section of the playbook does the heavy lifting. It searches for the MISP events that have a cluster attached corresponding with the search tags defined earlier in search_actor_tags
.
PO:1 Search MISP events¶
The search only considers MISP events that are published (published
) and after a specific date (date_from
).
published = True
date_from = "2019-01-01"
print("Searching ...")
tag_query = misp.build_complex_query(or_parameters=search_actor_tags, and_parameters=misp_additional_filter_tags,not_parameters=None)
search_match = misp.search("events", tags=tag_query, date_from=date_from, published=published, pythonify=True)
if len(search_match) > 0:
for event in search_match:
vulnerability_string, galaxy_string, tag_string = "", "", ""
for attribute in event.Attribute:
if attribute.type == "vulnerability":
if attribute.value not in playbook_results["vulnerabilities"]:
playbook_results["vulnerabilities"].append(attribute.value)
vulnerability_string = "{}{}\n".format(vulnerability_string, attribute.value.strip())
else:
if attribute.to_ids and attribute.value not in playbook_results["indicators"].values():
entry = {"value": attribute.value, "category": attribute.category, "type": attribute.type, "comment": attribute.comment}
playbook_results["indicators"][attribute.value] = entry
for object in event.Object:
if object.name == "vulnerability":
for attribute in object.Attribute:
if attribute.object_relation == "id":
if attribute.value not in playbook_results["vulnerabilities"]:
playbook_results["vulnerabilities"].append(attribute.value)
vulnerability_string = "{}{}\n".format(vulnerability_string, attribute.value.strip())
else:
for attribute in object.Attribute:
if attribute.to_ids and attribute.value not in playbook_results["indicators"].values():
entry = {"value": attribute.value, "category": attribute.category, "type": attribute.type, "comment": attribute.comment}
playbook_results["indicators"][attribute.value] = entry
for galaxy in event.Galaxy:
for cluster in galaxy.GalaxyCluster:
if galaxy.name not in playbook_results["galaxies"]:
playbook_results["galaxies"].append(galaxy.name)
skip_entry = False
for existing_entry in playbook_results["galaxy_clusters"]:
if existing_entry["galaxy"] == galaxy.name and existing_entry["cluster"] == cluster.value:
skip_entry = True
if not skip_entry:
entry = {"galaxy": galaxy.name.strip(), "cluster": cluster.value.strip(), "synonyms": cluster.meta.get("synonyms", []), "tag": cluster.tag_name}
playbook_results["galaxy_clusters"].append(entry)
# The galaxy_string cannot have doubles, 'cause a MISP event can only have the cluster once
galaxy_string = "{}{} - {}\n".format(galaxy_string, galaxy.name.strip(), cluster.value.strip())
for tag in event.tags:
if not tag.name.startswith("misp-galaxy:"):
if tag.name not in playbook_results["tags"]:
playbook_results["tags"].append(tag.name)
tag_string = "{}{}\n".format(tag_string, tag.name)
entry = {"info": event.info.strip(), "id": event.id, "uuid": event.uuid, "org": event.Org.name, "date": event.date, "galaxy_string": galaxy_string.strip(),
"tag_string": tag_string.strip(), "vulnerability_string": vulnerability_string.strip()}
playbook_results["events"].append(entry)
print(" Found match in \033[92m{}\033[90m in \033[92m{}\033[90m".format(event.id, event.info))
else:
print("\033[93mNo MISP events\033[90m found for {}".format(search_actor_tags))
print("Finished searching in MISP events.\n\n")
Searching ... Found match in 2228 in 2019-01-21: APT28 Autoit Zebrocy Progression Found match in 2231 in 2019-01-28: APT28 XTunnel Backdoor Found match in 2865 in In the footsteps of the Fancy Bear: PowerPoint mouse-over event abused to deliver Graphite implants Finished searching in MISP events.
MISP events¶
You can now print the matching events, with their event title, date, organisation and associated galaxies/clusters and tags.
table = PrettyTable()
table.field_names = ["ID", "Title", "Organsation", "Date", "Galaxies", "Tags"]
table.align = "l"
table._max_width = {"Title":40,"Organisation":30}
for result in playbook_results["events"]:
table.add_row([result["id"], result["info"], result["org"], result["date"], result["galaxy_string"], result["tag_string"]])
print(table.get_string(sortby="Date"))
table_mispevents = table
+------+------------------------------------------+-------------+------------+--------------------------------------------------------------------------------------------+----------------------------------------------+ | ID | Title | Organsation | Date | Galaxies | Tags | +------+------------------------------------------+-------------+------------+--------------------------------------------------------------------------------------------+----------------------------------------------+ | 2228 | 2019-01-21: APT28 Autoit Zebrocy | DEMO-ORG | 2019-01-21 | Enterprise Attack - Attack Pattern - Command-Line Interface - T1059 | Actor: APT28 | | | Progression | | | Enterprise Attack - Attack Pattern - Scripting - T1064 | Autoit | | | | | | Enterprise Attack - Attack Pattern - Registry Run Keys / Start Folder - T1060 | Actor: Sofacy | | | | | | Enterprise Attack - Attack Pattern - System Information Discovery - T1082 | downloader | | | | | | Enterprise Attack - Attack Pattern - Exfiltration Over Command and Control Channel - T1041 | Malware: Zebrocy | | | | | | Enterprise Attack - Attack Pattern - Standard Application Layer Protocol - T1071 | type:OSINT | | | | | | Enterprise Attack - Attack Pattern - Windows Management Instrumentation - T1047 | osint:lifetime="perpetual" | | | | | | Threat Actor - Sofacy | osint:certainty="50" | | | | | | | tlp:white | | 2231 | 2019-01-28: APT28 XTunnel Backdoor | DEMO-ORG | 2019-01-29 | Microsoft Activity Group actor - STRONTIUM | ecsirt:intrusions="backdoor" | | | | | | Enterprise Attack - Intrusion Set - APT28 - G0007 | veris:action:malware:variety="Backdoor" | | | | | | Intrusion Set - APT28 - G0007 | ms-caro-malware:malware-type="Backdoor" | | | | | | Mobile Attack - Intrusion Set - APT28 - G0007 | ms-caro-malware-full:malware-type="Backdoor" | | | | | | Enterprise Attack - Malware - XTunnel - S0117 | type:OSINT | | | | | | Threat Actor - Sofacy | osint:lifetime="perpetual" | | | | | | | osint:certainty="50" | | | | | | | tlp:white | | | | | | | osint:source-type="microblog-post" | | 2865 | In the footsteps of the Fancy Bear: | DEMO-ORG | 2022-09-23 | Intrusion Set - APT28 - G0007 | tlp:white | | | PowerPoint mouse-over event abused to | | | | type:OSINT | | | deliver Graphite implants | | | | | +------+------------------------------------------+-------------+------------+--------------------------------------------------------------------------------------------+----------------------------------------------+
PO:2 Context in other MISP events¶
The previous cell printed the context per MISP event. You can also summarise all found galaxies, clusters and tags.
table = PrettyTable()
table.field_names = ["Event titles", "Galaxies", "Galaxies - Clusters", "Tags"]
table.align = "l"
table._max_width = {"Event titles": 40}
event_column, galaxies_column, clusters_column, tag_column = "", "", "", ""
for result in sorted(playbook_results["events"], key=lambda x: (x['info'], -x['id'])):
event_column = "{}{} ({})\n".format(event_column, result["info"], result["id"])
for result in sorted(playbook_results["galaxies"]):
galaxies_column = "{}{}\n".format(galaxies_column, result)
for result in sorted(playbook_results["galaxy_clusters"], key=lambda x: (x['galaxy'], x['cluster'])):
clusters_column = "{}{} - {}\n".format(clusters_column, result["galaxy"], result["cluster"])
for result in sorted(playbook_results["tags"]):
tag_column = "{}{}\n".format(tag_column, result)
table.add_row([event_column, galaxies_column, clusters_column, tag_column])
print(table.get_string(sortby="Galaxies - Clusters"))
table_context = table
+------------------------------------------+------------------------------------+--------------------------------------------------------------------------------------------+----------------------------------------------+ | Event titles | Galaxies | Galaxies - Clusters | Tags | +------------------------------------------+------------------------------------+--------------------------------------------------------------------------------------------+----------------------------------------------+ | 2019-01-21: APT28 Autoit Zebrocy | Enterprise Attack - Attack Pattern | Enterprise Attack - Attack Pattern - Command-Line Interface - T1059 | Actor: APT28 | | Progression (2228) | Enterprise Attack - Intrusion Set | Enterprise Attack - Attack Pattern - Exfiltration Over Command and Control Channel - T1041 | Actor: Sofacy | | 2019-01-28: APT28 XTunnel Backdoor | Enterprise Attack - Malware | Enterprise Attack - Attack Pattern - Registry Run Keys / Start Folder - T1060 | Autoit | | (2231) | Intrusion Set | Enterprise Attack - Attack Pattern - Scripting - T1064 | Malware: Zebrocy | | In the footsteps of the Fancy Bear: | Microsoft Activity Group actor | Enterprise Attack - Attack Pattern - Standard Application Layer Protocol - T1071 | downloader | | PowerPoint mouse-over event abused to | Mobile Attack - Intrusion Set | Enterprise Attack - Attack Pattern - System Information Discovery - T1082 | ecsirt:intrusions="backdoor" | | deliver Graphite implants (2865) | Threat Actor | Enterprise Attack - Attack Pattern - Windows Management Instrumentation - T1047 | ms-caro-malware-full:malware-type="Backdoor" | | | | Enterprise Attack - Intrusion Set - APT28 - G0007 | ms-caro-malware:malware-type="Backdoor" | | | | Enterprise Attack - Malware - XTunnel - S0117 | osint:certainty="50" | | | | Intrusion Set - APT28 - G0007 | osint:lifetime="perpetual" | | | | Microsoft Activity Group actor - STRONTIUM | osint:source-type="microblog-post" | | | | Mobile Attack - Intrusion Set - APT28 - G0007 | tlp:white | | | | Threat Actor - Sofacy | type:OSINT | | | | | veris:action:malware:variety="Backdoor" | | | | | | +------------------------------------------+------------------------------------+--------------------------------------------------------------------------------------------+----------------------------------------------+
PO:3 Vulnerabilities exploited¶
The playbook also extracts all vulnerabilities (either as a vulnerability attribute or as a vulnerability object).
table = PrettyTable()
table.field_names = ["ID", "Title", "CVE"]
table.align = "l"
table._max_width = {"Title": 40,"Organisation": 30}
for result in playbook_results["events"]:
table.add_row([result["id"], result["info"], result["vulnerability_string"]])
print(table.get_string(sortby="ID"))
table_cve = table
print("\n\n- Threat actor \033[92m{}\033[90m \n- CVE: \033[92m{}\033[90m.\n\n".format(search_actor_names, playbook_results["vulnerabilities"]))
+------+------------------------------------------+----------------+ | ID | Title | CVE | +------+------------------------------------------+----------------+ | 2228 | 2019-01-21: APT28 Autoit Zebrocy | CVE-2023-23397 | | | Progression | | | 2231 | 2019-01-28: APT28 XTunnel Backdoor | | | 2865 | In the footsteps of the Fancy Bear: | CVE-2021-40444 | | | PowerPoint mouse-over event abused to | | | | deliver Graphite implants | | +------+------------------------------------------+----------------+ - Threat actor ['Sofacy', 'APT 28', 'APT28', 'Pawn Storm', 'PawnStorm', 'Fancy Bear', 'Sednit', 'SNAKEMACKEREL', 'TsarTeam', 'Tsar Team', 'TG-4127', 'Group-4127', 'STRONTIUM', 'TAG_0700', 'Swallowtail', 'IRON TWILIGHT', 'Group 74', 'SIG40', 'Grizzly Steppe', 'apt_sofacy', 'FANCY BEAR', 'G0007', 'ATK5', 'Fighting Ursa', 'ITG05', 'Blue Athena', 'TA422', 'T-APT-12', 'APT-C-20', 'UAC-0028', 'APT28 - G0007', 'Threat Group-4127'] - CVE: ['CVE-2023-23397', 'CVE-2021-40444'].
PO:4 Indicators¶
The playbook also extracted the list of actionable (those with to_ids set to True) indicators.
table = PrettyTable()
table.field_names = ["Category", "Type", "Indicator"]
table.align = "l"
for result in playbook_results["indicators"]:
table.add_row([playbook_results["indicators"][result]["category"], playbook_results["indicators"][result]["type"], playbook_results["indicators"][result]["value"]])
print(table.get_string(sortby="Type"))
table_indicators = table
+-------------------+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Category | Type | Indicator | +-------------------+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Payload delivery | filename | %ALLUSERSPROFILE%\lmapi2.dll | | Payload delivery | filename | Xtunnel_Http_Method.exe | | Network activity | hostname | 9b5uja.am.files.1drv.com | | Network activity | hostname | kdmzlw.am.files.1drv.com | | Network activity | ip-dst | 109.236.93.138 | | Payload delivery | md5 | 16b6d63390340941ec0fe60b0177384f | | Payload delivery | md5 | 2ff3e6c9244ef965295aa60879d1aa6b | | Payload delivery | md5 | 311f24eb2dda26c26f572c727a25503b | | Payload delivery | md5 | 7b1974e61795e84b6aacf33571320c2a | | Payload delivery | md5 | 9a915313d02345e149e6ba566fe85c47 | | Payload delivery | md5 | c0060c0741833af67121390922c44f91 | | Payload delivery | md5 | c2e1f2cf18ca987ebb3e8f4c09a4ef7e | | Payload delivery | md5 | d6751b148461e0f863548be84020b879 | | Payload delivery | md5 | ec57bb4980ea0190f4ad05d0ea9c9447 | | Payload delivery | md5 | ef1288de782e65d6e5bd6a327157988f | | Payload delivery | sha1 | 4c813ad68f2f1da6b2c59d11ad983cfa65e1a187 | | Payload delivery | sha1 | 622eb93e34445c752eeaa623ef9ac6978e58f2fc | | Payload delivery | sha1 | 6b300486d17d07a02365d32b673cd6638bd384f3 | | Payload delivery | sha1 | 74e12fbcac14b2f1b2d83cabb057f8e059c95d68 | | Payload delivery | sha1 | 9cd7f14d85814c48be3fbf73891415978a7aa882 | | Payload delivery | sha1 | a23efb6aa5a242c61c5d50a967a8f29da164c954 | | Payload delivery | sha1 | bab1d2c668e597d19f9ee9395944c1ce0f34f279 | | Payload delivery | sha1 | c3212e1e609588cb5736b1fd9aa8581c965ffa08 | | Payload delivery | sha1 | ce3b60fbad031c9bd5a10779cc8beb185035d407 | | Payload delivery | sha1 | e757ea599a1d6f1d06d90589d7f19dd1c1bf8b7b | | Payload delivery | sha256 | 01bca6481a3a55dc5de5bfa4124bba47d37018d8ee93e5dbb80a60a14f243889 | | Payload delivery | sha256 | 121407a9bced8297fbbdfb76ae79f16fe9fa0574deee21a44dfb56d5b1deb999 | | Payload delivery | sha256 | 1aa4ad5a3f8929d61f559df656c84326d1fe0ca82a4be299fa758a26e14b1b27 | | Payload delivery | sha256 | 34aca02d3a4665f63fddb354551b5eff5a7e8877032ddda6db4f5c42452885ad | | Payload delivery | sha256 | 5b52bc196bfc207d43eedfe585df96fcfabbdead087ff79fcdcdd4d08c7806db | | Payload delivery | sha256 | be180a7c43734b7125b2d5cea7edd0174811a58113b048f5fe687db52db47fe3 | | Payload delivery | sha256 | be2e58669dbdec916f7aaaf4d7c55d866c4f38ac290812b10d680d943bb5b757 | | Payload delivery | sha256 | d1bceccf5d2b900a6b601c612346fdb3fa5bb0e2faeefcac3f9c29dc1d74838d | | Payload delivery | sha256 | e6e93c7744d20e2cac2c2b257868686c861d43c6cf3de146b8812778c8283f7d | | Payload delivery | sha256 | efa5b49bdd086125b2b7d4058d09566f1db5f183c2a6332c597322f85107667a | | External analysis | url | http://194.187.249.126 | | Network activity | url | http://185.236.203.53 | | Network activity | url | http://220.158.216.127 | | Network activity | url | http://80.255.6.5 | | Network activity | url | https://145.249.106.198/ | | Network activity | url | https://kdmzlw.am.files.1drv.com/y4mv4glUgvW9nl8z8GU71PhPw0oRtve9QpZ0pEgwJN1q_TlGY5yl5Mvkrc5rUh0Uxxknlr1qymWyCbPrkKOFgL4CARScSn9UMhq3c5hSNOQsDOamYLmOfN61lUtQO10vxtn0I7QROJdOtQ42wDsaiACGR5ZrmYwt0SmZkphGWQpT2gOFrsUxjg8_7QT01VTABiGr3T6xpWrTmFT5yu4toQ/DSC0001.jpeg?download | | Network activity | url | https://twitter.com/VK_Intel/status/1090111749284614144 | | Network activity | url | https:\\9b5uja.am.files.1drv.com/y4mpYJ245I931DUGr7BV-dwLD7SReTqFr1N7eQOKSH_ug2G18Jd6i3SRqYqgugj3FA2JQQ7JqclvWH13Br3B5Ux-F6QcqADr-FowC_9PZi1Aj7uckcK8Uix_7ja1tF6C_8-5xYgm6zwjbXsrlEcTEenAyA8BzEaGPudutl1wMDkzVr6Wmn8_qRmYejLgbNoQmPTUe3P5NKFFLRjeeU_JhvA/DSC0002.jpeg?download | +-------------------+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
PO:5 Victims, countries and incident types from galaxy/cluster¶
The metadata from the MISP galaxy and cluster provides a list of victims, targets, allegedly supporting countries and incident types.
for actor in search_actor_match["actors"]:
actor_victims = list(set(actor_victims).union(actor.get("victims", [])))
actor_country = list(set(actor_country).union(actor.get("country", [])))
actor_incident_type = list(set(actor_incident_type).union(actor.get("incident_type", [])))
actor_target = list(set(actor_target).union(actor.get("target", [])))
print("According to the metadata of the galaxies, the threat actor\n")
print(" - Targets: \033[92m{}\033[90m".format(actor_target))
print(" - With victims in: \033[92m{}\033[90m".format(actor_victims))
print(" - Incident type: \033[92m{}\033[90m".format(actor_incident_type))
print(" - Alledgely supporting countries: \033[92m{}\033[90m".format(actor_country))
According to the metadata of the galaxies, the threat actor - Targets: ['Government', 'Military'] - With victims in: ['Kazakhstan', 'Hungary', 'International Association of Athletics Federations', 'Jordan', 'Mongolia', 'China', 'OSCE', 'Pakistan', 'Georgia', 'Turkey', 'NATO', 'United States', 'Poland', 'Ukraine', 'France', 'Germany', 'Japan', 'European Commission', 'United Kingdom', 'Tajikistan', 'Armenia', 'World Anti-Doping Agency', 'Asia Pacific Economic Cooperation', 'Belgium', 'Afghanistan'] - Incident type: ['Espionage'] - Alledgely supporting countries: ['RU']
PO:6 Information from MITRE¶
The playbook now queries the TAXII server from MITRE for threat actor details, techniques and software. If the query does not return results then it can help to tune the threat actor name, or use one of the synonyms.
print("Search for \033[92m{}\033[90m at MITRE ({}).\n".format(search_actor, search_actor_names))
print("Searching ...")
lift = attack_client()
group_techniques = []
group_software = []
# For MITRE, we remove the '-' in group names (APT-28>APT28)
mitre_search_actor = re.sub(r'[^a-zA-Z0-9]', '', search_actor)
mitre_group_result = lift.get_group_by_alias(mitre_search_actor, case=False)
if len(mitre_group_result) > 0:
for group in mitre_group_result:
print(" Found match with group ID \033[92m{}\033[90m in \033[92m{}\033[90m".format(group.id, group.name))
print(" Searching for techniques")
techniques = lift.get_techniques_used_by_group(group)
if len(techniques) > 0:
group_techniques = group_techniques + techniques
print(" Found \033[92m{}\033[90m techniques".format(len(techniques)))
else:
print(" \033[93mNo techniques found\033[90m")
print(" Searching for software")
software = lift.get_software_used_by_group(group)
if len(software) > 0:
group_software = group_software + software
print(" Found \033[92m{}\033[90m software".format(len(software)))
else:
print(" \033[93mNo software found\033[90m")
else:
print("\033[93mNo MITRE group match\033[90m found for {}".format(search_actor_tags))
print("Finished searching")
Search for APT-28 at MITRE (['Sofacy', 'APT 28', 'APT28', 'Pawn Storm', 'PawnStorm', 'Fancy Bear', 'Sednit', 'SNAKEMACKEREL', 'TsarTeam', 'Tsar Team', 'TG-4127', 'Group-4127', 'STRONTIUM', 'TAG_0700', 'Swallowtail', 'IRON TWILIGHT', 'Group 74', 'SIG40', 'Grizzly Steppe', 'apt_sofacy', 'FANCY BEAR', 'G0007', 'ATK5', 'Fighting Ursa', 'ITG05', 'Blue Athena', 'TA422', 'T-APT-12', 'APT-C-20', 'UAC-0028', 'APT28 - G0007', 'Threat Group-4127']). Searching ...
[taxii2client.v20] [WARNING ] [2023-08-11 19:35:26,838] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:35:26,844] TAXII Server Response with different amount of objects! Setting per_request=150 [taxii2client.v20] [WARNING ] [2023-08-11 19:35:31,357] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:35:31,359] TAXII Server Response with different amount of objects! Setting per_request=6 [taxii2client.v20] [WARNING ] [2023-08-11 19:35:33,749] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:35:33,753] TAXII Server Response with different amount of objects! Setting per_request=15
Found match with group ID intrusion-set--bef4c620-0787-42a8-a96d-b7eb6e85917c in APT28 Searching for techniques
[taxii2client.v20] [WARNING ] [2023-08-11 19:35:40,233] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:35:43,231] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:35:46,034] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:35:47,132] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:35:50,069] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:35:50,079] TAXII Server Response with different amount of objects! Setting per_request=1300 [taxii2client.v20] [WARNING ] [2023-08-11 19:35:52,963] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:35:52,970] TAXII Server Response with different amount of objects! Setting per_request=781 [taxii2client.v20] [WARNING ] [2023-08-11 19:35:56,371] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:35:56,389] TAXII Server Response with different amount of objects! Setting per_request=750 [taxii2client.v20] [WARNING ] [2023-08-11 19:35:58,961] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:35:58,966] TAXII Server Response with different amount of objects! Setting per_request=175 [taxii2client.v20] [WARNING ] [2023-08-11 19:36:02,047] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:36:02,051] TAXII Server Response with different amount of objects! Setting per_request=93
Found 86 techniques Searching for software
[taxii2client.v20] [WARNING ] [2023-08-11 19:36:08,751] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:36:10,541] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:36:12,098] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:36:14,687] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:36:20,008] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:36:20,018] TAXII Server Response with different amount of objects! Setting per_request=1300 [taxii2client.v20] [WARNING ] [2023-08-11 19:36:22,815] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:36:22,823] TAXII Server Response with different amount of objects! Setting per_request=781 [taxii2client.v20] [WARNING ] [2023-08-11 19:36:25,588] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:36:25,592] TAXII Server Response with different amount of objects! Setting per_request=26 [taxii2client.v20] [WARNING ] [2023-08-11 19:36:29,218] TAXII Server Response did not include 'Content-Range' header - results could be incomplete. [taxii2client.v20] [WARNING ] [2023-08-11 19:36:29,221] TAXII Server Response with different amount of objects! Setting per_request=1
Found 27 software Finished searching
Techniques¶
When the threat actor has been found with MITRE ATT&CK, it also queries for the associated techniques.
table = PrettyTable()
table.field_names = ["ID", "Technique", "Platform"]
table.align = "l"
table._max_width = {"Technique": 40, "Platform": 60}
# Other useful columns: x_mitre_data_sources
for technique in group_techniques:
technique_id = ""
for ref in technique.external_references:
if ref["source_name"] == "mitre-attack":
technique_id = ref["external_id"]
table.add_row([technique_id, technique.name, technique.get("x_mitre_platforms","")])
print(table.get_string(sortby="Technique"))
table_mitre_techniques = table
+-----------+------------------------------------------+--------------------------------------------------------------+ | ID | Technique | Platform | +-----------+------------------------------------------+--------------------------------------------------------------+ | T1098.002 | Additional Email Delegate Permissions | ['Windows', 'Office 365', 'Google Workspace'] | | T1550.001 | Application Access Token | ['Office 365', 'SaaS', 'Google Workspace', 'Containers', | | | | 'IaaS', 'Azure AD'] | | T1560 | Archive Collected Data | ['Linux', 'macOS', 'Windows'] | | T1560.001 | Archive via Utility | ['Linux', 'macOS', 'Windows'] | | T1119 | Automated Collection | ['Linux', 'macOS', 'Windows', 'IaaS', 'SaaS'] | | T1102.002 | Bidirectional Communication | ['Linux', 'macOS', 'Windows'] | | T1542.003 | Bootkit | ['Linux', 'Windows'] | | T1110 | Brute Force | ['Windows', 'Azure AD', 'Office 365', 'SaaS', 'IaaS', | | | | 'Linux', 'macOS', 'Google Workspace', 'Containers', | | | | 'Network'] | | T1070.001 | Clear Windows Event Logs | ['Windows'] | | T1078.004 | Cloud Accounts | ['Azure AD', 'Office 365', 'SaaS', 'IaaS', 'Google | | | | Workspace'] | | T1092 | Communication Through Removable Media | ['Linux', 'macOS', 'Windows'] | | T1546.015 | Component Object Model Hijacking | ['Windows'] | | T1589.001 | Credentials | ['PRE'] | | T1030 | Data Transfer Size Limits | ['Linux', 'macOS', 'Windows'] | | T1213 | Data from Information Repositories | ['Linux', 'Windows', 'macOS', 'SaaS', 'Office 365', 'Google | | | | Workspace', 'IaaS'] | | T1005 | Data from Local System | ['Linux', 'macOS', 'Windows', 'Network'] | | T1039 | Data from Network Shared Drive | ['Linux', 'macOS', 'Windows'] | | T1025 | Data from Removable Media | ['Linux', 'macOS', 'Windows'] | | T1140 | Deobfuscate/Decode Files or Information | ['Windows', 'Linux', 'macOS'] | | T1583.001 | Domains | ['PRE'] | | T1189 | Drive-by Compromise | ['Windows', 'Linux', 'macOS', 'SaaS'] | | T1559.002 | Dynamic Data Exchange | ['Windows'] | | T1586.002 | Email Accounts | ['PRE'] | | T1048.002 | Exfiltration Over Asymmetric Encrypted | ['Linux', 'macOS', 'Windows'] | | | Non-C2 Protocol | | | T1567 | Exfiltration Over Web Service | ['Linux', 'macOS', 'Windows'] | | T1190 | Exploit Public-Facing Application | ['Windows', 'IaaS', 'Network', 'Linux', 'macOS', | | | | 'Containers'] | | T1203 | Exploitation for Client Execution | ['Linux', 'Windows', 'macOS'] | | T1211 | Exploitation for Defense Evasion | ['Linux', 'Windows', 'macOS'] | | T1068 | Exploitation for Privilege Escalation | ['Linux', 'macOS', 'Windows', 'Containers'] | | T1210 | Exploitation of Remote Services | ['Linux', 'Windows', 'macOS'] | | T1090.002 | External Proxy | ['Linux', 'macOS', 'Windows'] | | T1133 | External Remote Services | ['Windows', 'Linux', 'Containers', 'macOS'] | | T1070.004 | File Deletion | ['Linux', 'macOS', 'Windows'] | | T1083 | File and Directory Discovery | ['Linux', 'macOS', 'Windows', 'Network'] | | T1564.001 | Hidden Files and Directories | ['Windows', 'macOS', 'Linux'] | | T1564.003 | Hidden Window | ['macOS', 'Windows', 'Linux'] | | T1105 | Ingress Tool Transfer | ['Linux', 'macOS', 'Windows'] | | T1001.001 | Junk Data | ['Linux', 'macOS', 'Windows'] | | T1056.001 | Keylogging | ['Windows', 'macOS', 'Linux', 'Network'] | | T1003.001 | LSASS Memory | ['Windows'] | | T1074.001 | Local Data Staging | ['Linux', 'macOS', 'Windows'] | | T1037.001 | Logon Script (Windows) | ['Windows'] | | T1071.003 | Mail Protocols | ['Linux', 'macOS', 'Windows'] | | T1204.002 | Malicious File | ['Linux', 'macOS', 'Windows'] | | T1204.001 | Malicious Link | ['Linux', 'macOS', 'Windows'] | | T1036 | Masquerading | ['Linux', 'macOS', 'Windows', 'Containers'] | | T1036.005 | Match Legitimate Name or Location | ['Linux', 'macOS', 'Windows', 'Containers'] | | T1090.003 | Multi-hop Proxy | ['Linux', 'macOS', 'Windows', 'Network'] | | T1003.003 | NTDS | ['Windows'] | | T1498 | Network Denial of Service | ['Windows', 'Azure AD', 'Office 365', 'SaaS', 'IaaS', | | | | 'Linux', 'macOS', 'Google Workspace', 'Containers'] | | T1040 | Network Sniffing | ['Linux', 'macOS', 'Windows', 'Network', 'IaaS'] | | T1003 | OS Credential Dumping | ['Windows', 'Linux', 'macOS'] | | T1027 | Obfuscated Files or Information | ['Linux', 'macOS', 'Windows'] | | T1137.002 | Office Test | ['Windows', 'Office 365'] | | T1550.002 | Pass the Hash | ['Windows'] | | T1110.001 | Password Guessing | ['Windows', 'Azure AD', 'Office 365', 'SaaS', 'IaaS', | | | | 'Linux', 'macOS', 'Google Workspace', 'Containers', | | | | 'Network'] | | T1110.003 | Password Spraying | ['Windows', 'Azure AD', 'Office 365', 'SaaS', 'IaaS', | | | | 'Linux', 'macOS', 'Google Workspace', 'Containers'] | | T1120 | Peripheral Device Discovery | ['Windows', 'macOS', 'Linux'] | | T1598 | Phishing for Information | ['PRE'] | | T1059.001 | PowerShell | ['Windows'] | | T1057 | Process Discovery | ['Linux', 'macOS', 'Windows', 'Network'] | | T1547.001 | Registry Run Keys / Startup Folder | ['Windows'] | | T1074.002 | Remote Data Staging | ['Windows', 'IaaS', 'Linux', 'macOS'] | | T1114.002 | Remote Email Collection | ['Office 365', 'Windows', 'Google Workspace'] | | T1091 | Replication Through Removable Media | ['Windows'] | | T1014 | Rootkit | ['Linux', 'macOS', 'Windows'] | | T1218.011 | Rundll32 | ['Windows'] | | T1021.002 | SMB/Windows Admin Shares | ['Windows'] | | T1113 | Screen Capture | ['Linux', 'macOS', 'Windows'] | | T1213.002 | Sharepoint | ['Windows', 'Office 365'] | | T1566.001 | Spearphishing Attachment | ['macOS', 'Windows', 'Linux'] | | T1566.002 | Spearphishing Link | ['Linux', 'macOS', 'Windows', 'Office 365', 'SaaS', 'Google | | | | Workspace'] | | T1598.003 | Spearphishing Link | ['PRE'] | | T1528 | Steal Application Access Token | ['SaaS', 'Office 365', 'Azure AD', 'Google Workspace', | | | | 'Containers'] | | T1573.001 | Symmetric Cryptography | ['Linux', 'Windows', 'macOS'] | | T1221 | Template Injection | ['Windows'] | | T1070.006 | Timestomp | ['Linux', 'macOS', 'Windows'] | | T1134.001 | Token Impersonation/Theft | ['Windows'] | | T1588.002 | Tool | ['PRE'] | | T1199 | Trusted Relationship | ['Windows', 'SaaS', 'IaaS', 'Linux', 'macOS', 'Office 365'] | | T1078 | Valid Accounts | ['Windows', 'Azure AD', 'Office 365', 'SaaS', 'IaaS', | | | | 'Linux', 'macOS', 'Google Workspace', 'Containers', | | | | 'Network'] | | T1595.002 | Vulnerability Scanning | ['PRE'] | | T1071.001 | Web Protocols | ['Linux', 'macOS', 'Windows'] | | T1583.006 | Web Services | ['PRE'] | | T1505.003 | Web Shell | ['Linux', 'Windows', 'macOS', 'Network'] | | T1059.003 | Windows Command Shell | ['Windows'] | +-----------+------------------------------------------+--------------------------------------------------------------+
Software¶
Similar to techniques, the playbook also queries for the software associated with the threat actor.
table = PrettyTable()
table.field_names = ["ID", "Name", "Type", "Platforms"]
table.align = "l"
table._max_width = {"Technique": 40, "Platform": 60}
# Other useful columns: x_mitre_data_sources, x_mitre_platforms
for software in group_software:
software_id = ""
for ref in software.external_references:
if ref["source_name"] == "mitre-attack":
software_id = ref["external_id"]
table.add_row([software_id, software.name, software.type, software.get("x_mitre_platforms", "")])
print(table.get_string(sortby="Type"))
table_mitre_software = table
+-------+---------------------+---------+-------------------------------+ | ID | Name | Type | Platforms | +-------+---------------------+---------+-------------------------------+ | S0023 | CHOPSTICK | malware | ['Windows', 'Linux'] | | S0044 | JHUHUGIT | malware | ['Windows'] | | S0045 | ADVSTORESHELL | malware | ['Windows'] | | S0117 | XTunnel | malware | ['Windows'] | | S0134 | Downdelph | malware | ['Windows'] | | S0135 | HIDEDRV | malware | ['Windows'] | | S0136 | USBStealer | malware | ['Windows'] | | S0137 | CORESHELL | malware | ['Windows'] | | S0138 | OLDBAIT | malware | ['Windows'] | | S0161 | XAgentOSX | malware | ['macOS'] | | S0162 | Komplex | malware | ['macOS'] | | S0243 | DealersChoice | malware | ['Windows'] | | S0251 | Zebrocy | malware | ['Windows'] | | S0314 | X-Agent for Android | malware | | | S0351 | Cannon | malware | ['Windows'] | | S0397 | LoJax | malware | ['Windows'] | | S0410 | Fysbis | malware | ['Linux'] | | S0502 | Drovorub | malware | ['Linux'] | | S0002 | Mimikatz | tool | ['Windows'] | | S0039 | Net | tool | ['Windows'] | | S0160 | certutil | tool | ['Windows'] | | S0174 | Responder | tool | | | S0183 | Tor | tool | ['Linux', 'Windows', 'macOS'] | | S0191 | Winexe | tool | | | S0193 | Forfiles | tool | | | S0250 | Koadic | tool | ['Windows'] | | S0645 | Wevtutil | tool | ['Windows'] | +-------+---------------------+---------+-------------------------------+
Closure¶
In this closure step we create a summary of the actions performed by the playbook. The summary is printed in the playbook and also send to Mattermost.
EN:1 Create the summary of the playbook¶
The next section creates a summary and stores the output in the variable summary
in Markdown format. It also stores an intro text in the variable intro
. These variables are later used when sending information to Mattermost or TheHive.
summary = "\n"
summary += "### MISP Playbook summary\n\n"
intro = summary
summary += "### Threat actor {} ({})\n\n".format(search_actor_names[0], search_actor)
summary += "#### Names and synonyms\n\n"
summary += "The threat actor **{}** is also known as \n".format(search_actor)
for name in search_actor_names:
summary += "- {}\n".format(name)
summary += "\n\n"
table_actor_match.set_style(MARKDOWN)
summary += table_actor_match.get_string(sortby="Threat actor")
summary += "\n\n"
summary += "#### Targets, victims, incident types and alledgely supporting countries\n\n"
summary += "According to the metadata of the galaxies, the threat actor\n"
summary += " - Targets: {}\n".format(actor_target)
summary += " - With victims in: {}\n".format(actor_victims)
summary += " - Incident type: {}\n".format(actor_incident_type)
summary += " - Alledgely supporting countries: {}\n".format(actor_country)
summary += "#### MISP Tag search\n\nThe MISP events are searched for these tags (corresponding with galaxies/clusters):\n"
for tag in search_actor_tags:
summary += "- {}\n".format(tag)
summary += "\n\n"
summary += "### MISP events\n"
table_mispevents.set_style(MARKDOWN)
summary += table_mispevents.get_string()
summary += "\n\n"
summary += "#### Context from MISP events\n"
table_context.set_style(MARKDOWN)
summary += table_context.get_string()
summary += "\n\n"
summary += "#### Vulnerabilities exploited\n"
table_cve.set_style(MARKDOWN)
summary += table_cve.get_string()
summary += "\n\n"
summary += "#### Indicators\n"
table_indicators.set_style(MARKDOWN)
summary += table_indicators.get_string()
summary += "\n\n"
summary += "### MITRE information\n"
summary += "#### Techniques\n"
table_mitre_techniques.set_style(MARKDOWN)
summary += table_mitre_techniques.get_string()
summary += "\n\n"
summary += "#### Software\n"
table_mitre_software.set_style(MARKDOWN)
summary += table_mitre_software.get_string()
summary += "\n\n"
summary += "\n\n"
print("The \033[92msummary\033[90m of the playbook is available.\n")
The summary of the playbook is available.
Print the summary¶
display_markdown(summary, raw=True)
MISP Playbook summary¶
Threat actor Sofacy (APT-28)¶
Names and synonyms¶
The threat actor APT-28 is also known as
- Sofacy
- APT 28
- APT28
- Pawn Storm
- PawnStorm
- Fancy Bear
- Sednit
- SNAKEMACKEREL
- TsarTeam
- Tsar Team
- TG-4127
- Group-4127
- STRONTIUM
- TAG_0700
- Swallowtail
- IRON TWILIGHT
- Group 74
- SIG40
- Grizzly Steppe
- apt_sofacy
- FANCY BEAR
- G0007
- ATK5
- Fighting Ursa
- ITG05
- Blue Athena
- TA422
- T-APT-12
- APT-C-20
- UAC-0028
- APT28 - G0007
- Threat Group-4127
Source | Threat actor | MITRE | Synonyms | Tag |
---|---|---|---|---|
misp | APT28 | ['G0007'] | Pawn Storm | misp-galaxy:threat-actor="APT28" |
FANCY BEAR | ||||
Sednit | ||||
SNAKEMACKEREL | ||||
Tsar Team | ||||
TG-4127 | ||||
STRONTIUM | ||||
Swallowtail | ||||
IRON TWILIGHT | ||||
Group 74 | ||||
SIG40 | ||||
Grizzly Steppe | ||||
G0007 | ||||
ATK5 | ||||
Fighting Ursa | ||||
ITG05 | ||||
Blue Athena | ||||
TA422 | ||||
T-APT-12 | ||||
APT-C-20 | ||||
UAC-0028 | ||||
mitre | APT28 - G0007 | ['G0007'] | APT28 | ['misp-galaxy:mitre-pre-attack- |
Sednit | intrusion-set="APT28 - G0007"', 'misp- | |||
Sofacy | galaxy:mitre-intrusion-set="APT28 - | |||
Pawn Storm | G0007"', 'misp-galaxy:mitre-enterprise- | |||
Fancy Bear | attack-intrusion-set="APT28 - G0007"', | |||
STRONTIUM | 'misp-galaxy:mitre-mobile-attack- | |||
Tsar Team | intrusion-set="APT28 - G0007"'] | |||
Threat Group-4127 | ||||
TG-4127 | ||||
misp | Sofacy | [] | APT 28 | misp-galaxy:threat-actor="Sofacy" |
APT28 | ||||
Pawn Storm | ||||
PawnStorm | ||||
Fancy Bear | ||||
Sednit | ||||
SNAKEMACKEREL | ||||
TsarTeam | ||||
Tsar Team | ||||
TG-4127 | ||||
Group-4127 | ||||
STRONTIUM | ||||
TAG_0700 | ||||
Swallowtail | ||||
IRON TWILIGHT | ||||
Group 74 | ||||
SIG40 | ||||
Grizzly Steppe | ||||
apt_sofacy |
Targets, victims, incident types and alledgely supporting countries¶
According to the metadata of the galaxies, the threat actor
- Targets: ['Government', 'Military']
- With victims in: ['Kazakhstan', 'Hungary', 'International Association of Athletics Federations', 'Jordan', 'Mongolia', 'China', 'OSCE', 'Pakistan', 'Georgia', 'Turkey', 'NATO', 'United States', 'Poland', 'Ukraine', 'France', 'Germany', 'Japan', 'European Commission', 'United Kingdom', 'Tajikistan', 'Armenia', 'World Anti-Doping Agency', 'Asia Pacific Economic Cooperation', 'Belgium', 'Afghanistan']
- Incident type: ['Espionage']
- Alledgely supporting countries: ['RU']
MISP Tag search¶
The MISP events are searched for these tags (corresponding with galaxies/clusters):
- misp-galaxy:threat-actor="Sofacy"
- misp-galaxy:threat-actor="APT28"
- misp-galaxy:mitre-pre-attack-intrusion-set="APT28 - G0007"
- misp-galaxy:mitre-intrusion-set="APT28 - G0007"
- misp-galaxy:mitre-enterprise-attack-intrusion-set="APT28 - G0007"
- misp-galaxy:mitre-mobile-attack-intrusion-set="APT28 - G0007"
MISP events¶
ID | Title | Organsation | Date | Galaxies | Tags |
---|---|---|---|---|---|
2228 | 2019-01-21: APT28 Autoit Zebrocy | DEMO-ORG | 2019-01-21 | Enterprise Attack - Attack Pattern - Command-Line Interface - T1059 | Actor: APT28 |
Progression | Enterprise Attack - Attack Pattern - Scripting - T1064 | Autoit | |||
Enterprise Attack - Attack Pattern - Registry Run Keys / Start Folder - T1060 | Actor: Sofacy | ||||
Enterprise Attack - Attack Pattern - System Information Discovery - T1082 | downloader | ||||
Enterprise Attack - Attack Pattern - Exfiltration Over Command and Control Channel - T1041 | Malware: Zebrocy | ||||
Enterprise Attack - Attack Pattern - Standard Application Layer Protocol - T1071 | type:OSINT | ||||
Enterprise Attack - Attack Pattern - Windows Management Instrumentation - T1047 | osint:lifetime="perpetual" | ||||
Threat Actor - Sofacy | osint:certainty="50" | ||||
tlp:white | |||||
2231 | 2019-01-28: APT28 XTunnel Backdoor | DEMO-ORG | 2019-01-29 | Microsoft Activity Group actor - STRONTIUM | ecsirt:intrusions="backdoor" |
Enterprise Attack - Intrusion Set - APT28 - G0007 | veris:action:malware:variety="Backdoor" | ||||
Intrusion Set - APT28 - G0007 | ms-caro-malware:malware-type="Backdoor" | ||||
Mobile Attack - Intrusion Set - APT28 - G0007 | ms-caro-malware-full:malware-type="Backdoor" | ||||
Enterprise Attack - Malware - XTunnel - S0117 | type:OSINT | ||||
Threat Actor - Sofacy | osint:lifetime="perpetual" | ||||
osint:certainty="50" | |||||
tlp:white | |||||
osint:source-type="microblog-post" | |||||
2865 | In the footsteps of the Fancy Bear: | DEMO-ORG | 2022-09-23 | Intrusion Set - APT28 - G0007 | tlp:white |
PowerPoint mouse-over event abused to | type:OSINT | ||||
deliver Graphite implants |
Context from MISP events¶
Event titles | Galaxies | Galaxies - Clusters | Tags |
---|---|---|---|
2019-01-21: APT28 Autoit Zebrocy | Enterprise Attack - Attack Pattern | Enterprise Attack - Attack Pattern - Command-Line Interface - T1059 | Actor: APT28 |
Progression (2228) | Enterprise Attack - Intrusion Set | Enterprise Attack - Attack Pattern - Exfiltration Over Command and Control Channel - T1041 | Actor: Sofacy |
2019-01-28: APT28 XTunnel Backdoor | Enterprise Attack - Malware | Enterprise Attack - Attack Pattern - Registry Run Keys / Start Folder - T1060 | Autoit |
(2231) | Intrusion Set | Enterprise Attack - Attack Pattern - Scripting - T1064 | Malware: Zebrocy |
In the footsteps of the Fancy Bear: | Microsoft Activity Group actor | Enterprise Attack - Attack Pattern - Standard Application Layer Protocol - T1071 | downloader |
PowerPoint mouse-over event abused to | Mobile Attack - Intrusion Set | Enterprise Attack - Attack Pattern - System Information Discovery - T1082 | ecsirt:intrusions="backdoor" |
deliver Graphite implants (2865) | Threat Actor | Enterprise Attack - Attack Pattern - Windows Management Instrumentation - T1047 | ms-caro-malware-full:malware-type="Backdoor" |
Enterprise Attack - Intrusion Set - APT28 - G0007 | ms-caro-malware:malware-type="Backdoor" | ||
Enterprise Attack - Malware - XTunnel - S0117 | osint:certainty="50" | ||
Intrusion Set - APT28 - G0007 | osint:lifetime="perpetual" | ||
Microsoft Activity Group actor - STRONTIUM | osint:source-type="microblog-post" | ||
Mobile Attack - Intrusion Set - APT28 - G0007 | tlp:white | ||
Threat Actor - Sofacy | type:OSINT | ||
veris:action:malware:variety="Backdoor" | |||
Vulnerabilities exploited¶
ID | Title | CVE |
---|---|---|
2228 | 2019-01-21: APT28 Autoit Zebrocy | CVE-2023-23397 |
Progression | ||
2231 | 2019-01-28: APT28 XTunnel Backdoor | |
2865 | In the footsteps of the Fancy Bear: | CVE-2021-40444 |
PowerPoint mouse-over event abused to | ||
deliver Graphite implants |
Indicators¶
Category | Type | Indicator |
---|---|---|
Payload delivery | md5 | d6751b148461e0f863548be84020b879 |
External analysis | url | http://194.187.249.126 |
Payload delivery | md5 | 311f24eb2dda26c26f572c727a25503b |
Payload delivery | md5 | 7b1974e61795e84b6aacf33571320c2a |
Payload delivery | md5 | c2e1f2cf18ca987ebb3e8f4c09a4ef7e |
Network activity | url | http://80.255.6.5 |
Network activity | url | http://220.158.216.127 |
Network activity | url | https://145.249.106.198/ |
Payload delivery | md5 | ec57bb4980ea0190f4ad05d0ea9c9447 |
Network activity | url | http://185.236.203.53 |
Payload delivery | sha1 | bab1d2c668e597d19f9ee9395944c1ce0f34f279 |
Payload delivery | sha256 | 1aa4ad5a3f8929d61f559df656c84326d1fe0ca82a4be299fa758a26e14b1b27 |
Payload delivery | sha1 | e757ea599a1d6f1d06d90589d7f19dd1c1bf8b7b |
Payload delivery | sha256 | 5b52bc196bfc207d43eedfe585df96fcfabbdead087ff79fcdcdd4d08c7806db |
Payload delivery | sha1 | 6b300486d17d07a02365d32b673cd6638bd384f3 |
Payload delivery | sha256 | e6e93c7744d20e2cac2c2b257868686c861d43c6cf3de146b8812778c8283f7d |
Payload delivery | sha1 | 74e12fbcac14b2f1b2d83cabb057f8e059c95d68 |
Payload delivery | sha256 | 01bca6481a3a55dc5de5bfa4124bba47d37018d8ee93e5dbb80a60a14f243889 |
Payload delivery | sha1 | ce3b60fbad031c9bd5a10779cc8beb185035d407 |
Payload delivery | sha256 | 121407a9bced8297fbbdfb76ae79f16fe9fa0574deee21a44dfb56d5b1deb999 |
Network activity | ip-dst | 109.236.93.138 |
Network activity | url | https://twitter.com/VK_Intel/status/1090111749284614144 |
Payload delivery | filename | Xtunnel_Http_Method.exe |
Payload delivery | md5 | 16b6d63390340941ec0fe60b0177384f |
Payload delivery | sha1 | c3212e1e609588cb5736b1fd9aa8581c965ffa08 |
Payload delivery | sha256 | be2e58669dbdec916f7aaaf4d7c55d866c4f38ac290812b10d680d943bb5b757 |
Payload delivery | md5 | c0060c0741833af67121390922c44f91 |
Payload delivery | sha1 | 622eb93e34445c752eeaa623ef9ac6978e58f2fc |
Payload delivery | sha256 | d1bceccf5d2b900a6b601c612346fdb3fa5bb0e2faeefcac3f9c29dc1d74838d |
Payload delivery | md5 | ef1288de782e65d6e5bd6a327157988f |
Payload delivery | sha1 | a23efb6aa5a242c61c5d50a967a8f29da164c954 |
Payload delivery | sha256 | be180a7c43734b7125b2d5cea7edd0174811a58113b048f5fe687db52db47fe3 |
Payload delivery | md5 | 2ff3e6c9244ef965295aa60879d1aa6b |
Payload delivery | sha1 | 4c813ad68f2f1da6b2c59d11ad983cfa65e1a187 |
Payload delivery | sha256 | efa5b49bdd086125b2b7d4058d09566f1db5f183c2a6332c597322f85107667a |
Payload delivery | md5 | 9a915313d02345e149e6ba566fe85c47 |
Payload delivery | sha1 | 9cd7f14d85814c48be3fbf73891415978a7aa882 |
Payload delivery | sha256 | 34aca02d3a4665f63fddb354551b5eff5a7e8877032ddda6db4f5c42452885ad |
Network activity | hostname | 9b5uja.am.files.1drv.com |
Network activity | hostname | kdmzlw.am.files.1drv.com |
Network activity | url | https://kdmzlw.am.files.1drv.com/y4mv4glUgvW9nl8z8GU71PhPw0oRtve9QpZ0pEgwJN1q_TlGY5yl5Mvkrc5rUh0Uxxknlr1qymWyCbPrkKOFgL4CARScSn9UMhq3c5hSNOQsDOamYLmOfN61lUtQO10vxtn0I7QROJdOtQ42wDsaiACGR5ZrmYwt0SmZkphGWQpT2gOFrsUxjg8_7QT01VTABiGr3T6xpWrTmFT5yu4toQ/DSC0001.jpeg?download |
Network activity | url | https:\9b5uja.am.files.1drv.com/y4mpYJ245I931DUGr7BV-dwLD7SReTqFr1N7eQOKSH_ug2G18Jd6i3SRqYqgugj3FA2JQQ7JqclvWH13Br3B5Ux-F6QcqADr-FowC_9PZi1Aj7uckcK8Uix_7ja1tF6C_8-5xYgm6zwjbXsrlEcTEenAyA8BzEaGPudutl1wMDkzVr6Wmn8_qRmYejLgbNoQmPTUe3P5NKFFLRjeeU_JhvA/DSC0002.jpeg?download |
Payload delivery | filename | %ALLUSERSPROFILE%\lmapi2.dll |
MITRE information¶
Techniques¶
ID | Technique | Platform |
---|---|---|
T1598.003 | Spearphishing Link | ['PRE'] |
T1598 | Phishing for Information | ['PRE'] |
T1595.002 | Vulnerability Scanning | ['PRE'] |
T1589.001 | Credentials | ['PRE'] |
T1588.002 | Tool | ['PRE'] |
T1586.002 | Email Accounts | ['PRE'] |
T1583.006 | Web Services | ['PRE'] |
T1583.001 | Domains | ['PRE'] |
T1573.001 | Symmetric Cryptography | ['Linux', 'Windows', 'macOS'] |
T1546.015 | Component Object Model Hijacking | ['Windows'] |
T1071.003 | Mail Protocols | ['Linux', 'macOS', 'Windows'] |
T1071.001 | Web Protocols | ['Linux', 'macOS', 'Windows'] |
T1048.002 | Exfiltration Over Asymmetric Encrypted | ['Linux', 'macOS', 'Windows'] |
Non-C2 Protocol | ||
T1001.001 | Junk Data | ['Linux', 'macOS', 'Windows'] |
T1090.003 | Multi-hop Proxy | ['Linux', 'macOS', 'Windows', 'Network'] |
T1090.002 | External Proxy | ['Linux', 'macOS', 'Windows'] |
T1102.002 | Bidirectional Communication | ['Linux', 'macOS', 'Windows'] |
T1074.002 | Remote Data Staging | ['Windows', 'IaaS', 'Linux', 'macOS'] |
T1074.001 | Local Data Staging | ['Linux', 'macOS', 'Windows'] |
T1078.004 | Cloud Accounts | ['Azure AD', 'Office 365', 'SaaS', 'IaaS', 'Google |
Workspace'] | ||
T1564.003 | Hidden Window | ['macOS', 'Windows', 'Linux'] |
T1204.002 | Malicious File | ['Linux', 'macOS', 'Windows'] |
T1204.001 | Malicious Link | ['Linux', 'macOS', 'Windows'] |
T1059.003 | Windows Command Shell | ['Windows'] |
T1059.001 | PowerShell | ['Windows'] |
T1567 | Exfiltration Over Web Service | ['Linux', 'macOS', 'Windows'] |
T1566.002 | Spearphishing Link | ['Linux', 'macOS', 'Windows', 'Office 365', 'SaaS', 'Google |
Workspace'] | ||
T1566.001 | Spearphishing Attachment | ['macOS', 'Windows', 'Linux'] |
T1564.001 | Hidden Files and Directories | ['Windows', 'macOS', 'Linux'] |
T1560.001 | Archive via Utility | ['Linux', 'macOS', 'Windows'] |
T1560 | Archive Collected Data | ['Linux', 'macOS', 'Windows'] |
T1114.002 | Remote Email Collection | ['Office 365', 'Windows', 'Google Workspace'] |
T1134.001 | Token Impersonation/Theft | ['Windows'] |
T1213.002 | Sharepoint | ['Windows', 'Office 365'] |
T1559.002 | Dynamic Data Exchange | ['Windows'] |
T1056.001 | Keylogging | ['Windows', 'macOS', 'Linux', 'Network'] |
T1003.003 | NTDS | ['Windows'] |
T1003.001 | LSASS Memory | ['Windows'] |
T1110.003 | Password Spraying | ['Windows', 'Azure AD', 'Office 365', 'SaaS', 'IaaS', |
'Linux', 'macOS', 'Google Workspace', 'Containers'] | ||
T1110.001 | Password Guessing | ['Windows', 'Azure AD', 'Office 365', 'SaaS', 'IaaS', |
'Linux', 'macOS', 'Google Workspace', 'Containers', | ||
'Network'] | ||
T1021.002 | SMB/Windows Admin Shares | ['Windows'] |
T1036.005 | Match Legitimate Name or Location | ['Linux', 'macOS', 'Windows', 'Containers'] |
T1070.006 | Timestomp | ['Linux', 'macOS', 'Windows'] |
T1070.004 | File Deletion | ['Linux', 'macOS', 'Windows'] |
T1550.001 | Application Access Token | ['Office 365', 'SaaS', 'Google Workspace', 'Containers', |
'IaaS', 'Azure AD'] | ||
T1550.002 | Pass the Hash | ['Windows'] |
T1070.001 | Clear Windows Event Logs | ['Windows'] |
T1547.001 | Registry Run Keys / Startup Folder | ['Windows'] |
T1218.011 | Rundll32 | ['Windows'] |
T1098.002 | Additional Email Delegate Permissions | ['Windows', 'Office 365', 'Google Workspace'] |
T1037.001 | Logon Script (Windows) | ['Windows'] |
T1542.003 | Bootkit | ['Linux', 'Windows'] |
T1505.003 | Web Shell | ['Linux', 'Windows', 'macOS', 'Network'] |
T1137.002 | Office Test | ['Windows', 'Office 365'] |
T1528 | Steal Application Access Token | ['SaaS', 'Office 365', 'Azure AD', 'Google Workspace', |
'Containers'] | ||
T1498 | Network Denial of Service | ['Windows', 'Azure AD', 'Office 365', 'SaaS', 'IaaS', |
'Linux', 'macOS', 'Google Workspace', 'Containers'] | ||
T1221 | Template Injection | ['Windows'] |
T1211 | Exploitation for Defense Evasion | ['Linux', 'Windows', 'macOS'] |
T1190 | Exploit Public-Facing Application | ['Windows', 'IaaS', 'Network', 'Linux', 'macOS', |
'Containers'] | ||
T1210 | Exploitation of Remote Services | ['Linux', 'Windows', 'macOS'] |
T1189 | Drive-by Compromise | ['Windows', 'Linux', 'macOS', 'SaaS'] |
T1199 | Trusted Relationship | ['Windows', 'SaaS', 'IaaS', 'Linux', 'macOS', 'Office 365'] |
T1213 | Data from Information Repositories | ['Linux', 'Windows', 'macOS', 'SaaS', 'Office 365', 'Google |
Workspace', 'IaaS'] | ||
T1203 | Exploitation for Client Execution | ['Linux', 'Windows', 'macOS'] |
T1140 | Deobfuscate/Decode Files or Information | ['Windows', 'Linux', 'macOS'] |
T1133 | External Remote Services | ['Windows', 'Linux', 'Containers', 'macOS'] |
T1120 | Peripheral Device Discovery | ['Windows', 'macOS', 'Linux'] |
T1119 | Automated Collection | ['Linux', 'macOS', 'Windows', 'IaaS', 'SaaS'] |
T1113 | Screen Capture | ['Linux', 'macOS', 'Windows'] |
T1110 | Brute Force | ['Windows', 'Azure AD', 'Office 365', 'SaaS', 'IaaS', |
'Linux', 'macOS', 'Google Workspace', 'Containers', | ||
'Network'] | ||
T1105 | Ingress Tool Transfer | ['Linux', 'macOS', 'Windows'] |
T1092 | Communication Through Removable Media | ['Linux', 'macOS', 'Windows'] |
T1091 | Replication Through Removable Media | ['Windows'] |
T1083 | File and Directory Discovery | ['Linux', 'macOS', 'Windows', 'Network'] |
T1078 | Valid Accounts | ['Windows', 'Azure AD', 'Office 365', 'SaaS', 'IaaS', |
'Linux', 'macOS', 'Google Workspace', 'Containers', | ||
'Network'] | ||
T1068 | Exploitation for Privilege Escalation | ['Linux', 'macOS', 'Windows', 'Containers'] |
T1057 | Process Discovery | ['Linux', 'macOS', 'Windows', 'Network'] |
T1040 | Network Sniffing | ['Linux', 'macOS', 'Windows', 'Network', 'IaaS'] |
T1039 | Data from Network Shared Drive | ['Linux', 'macOS', 'Windows'] |
T1036 | Masquerading | ['Linux', 'macOS', 'Windows', 'Containers'] |
T1030 | Data Transfer Size Limits | ['Linux', 'macOS', 'Windows'] |
T1027 | Obfuscated Files or Information | ['Linux', 'macOS', 'Windows'] |
T1025 | Data from Removable Media | ['Linux', 'macOS', 'Windows'] |
T1014 | Rootkit | ['Linux', 'macOS', 'Windows'] |
T1005 | Data from Local System | ['Linux', 'macOS', 'Windows', 'Network'] |
T1003 | OS Credential Dumping | ['Windows', 'Linux', 'macOS'] |
Software¶
ID | Name | Type | Platforms |
---|---|---|---|
S0645 | Wevtutil | tool | ['Windows'] |
S0502 | Drovorub | malware | ['Linux'] |
S0410 | Fysbis | malware | ['Linux'] |
S0397 | LoJax | malware | ['Windows'] |
S0351 | Cannon | malware | ['Windows'] |
S0243 | DealersChoice | malware | ['Windows'] |
S0250 | Koadic | tool | ['Windows'] |
S0251 | Zebrocy | malware | ['Windows'] |
S0191 | Winexe | tool | |
S0193 | Forfiles | tool | |
S0174 | Responder | tool | |
S0183 | Tor | tool | ['Linux', 'Windows', 'macOS'] |
S0161 | XAgentOSX | malware | ['macOS'] |
S0162 | Komplex | malware | ['macOS'] |
S0160 | certutil | tool | ['Windows'] |
S0138 | OLDBAIT | malware | ['Windows'] |
S0137 | CORESHELL | malware | ['Windows'] |
S0136 | USBStealer | malware | ['Windows'] |
S0135 | HIDEDRV | malware | ['Windows'] |
S0134 | Downdelph | malware | ['Windows'] |
S0117 | XTunnel | malware | ['Windows'] |
S0045 | ADVSTORESHELL | malware | ['Windows'] |
S0044 | JHUHUGIT | malware | ['Windows'] |
S0039 | Net | tool | ['Windows'] |
S0023 | CHOPSTICK | malware | ['Windows', 'Linux'] |
S0002 | Mimikatz | tool | ['Windows'] |
S0314 | X-Agent for Android | malware |
EN:2 Send a summary to Mattermost¶
Now you can send the summary to Mattermost. You can send the summary in two ways by selecting one of the options for the variable send_to_mattermost_option
in the next cell.
- The default option where the entire summary is in the chat, or
- a short intro and the summary in a card
For this playbook we rely on a webhook in Mattermost. You can add a webhook by choosing the gear icon in Mattermost, then choose Integrations and then Incoming Webhooks. Set a channel for the webhook and lock the webhook to this channel with "Lock to this channel".
send_to_mattermost_option = "via a chat message"
#send_to_mattermost_option = "via a chat message with card"
message = False
if send_to_mattermost_option == "via a chat message":
message = {"username": mattermost_playbook_user, "text": summary}
elif send_to_mattermost_option == "via a chat message with card":
message = {"username": mattermost_playbook_user, "text": intro, "props": {"card": summary}}
if message:
r = requests.post(mattermost_hook, data=json.dumps(message))
r.raise_for_status()
if message and r.status_code == 200:
print("Summary is \033[92msent to Mattermost.\n")
else:
print("\033[91mFailed to sent summary\033[90m to Mattermost.\n")
Summary is sent to Mattermost.
EN:3 Send an alert to TheHive¶
Next to informing your colleagues via Mattermost you can also send an alert to TheHive. The alert contains the summary, and a list of indicators as 'observables'.
You can change the alert title with thehive_alert_title
and provide a reference type with thehive_alert_reference
. Note that this reference needs to be unique in TheHive.
# The title of the TheHive alert
thehive_alert_title = "MISP Playbook Summary - MISP Threat Actor Profiling - {} - {}".format(search_actor_names[0], search_actor)
# A unique reference for the TheHive (we include the MISP event UUID)
thehive_alert_reference = "MISP Threat Actor Profiling - {} - {} - {}".format(search_actor_names[0], search_actor, random.random())
# Alert type in TheHive
thehive_alert_type = "MISP Playbook alert"
# TLP:Amber for TheHive
thehive_tlp = 2
# PAP:GREEN for TheHive
thehive_pap = 1
# Code block to send an alert to TheHive
# We use the Python requests library
thehive_headers = {'Content-Type': 'application/json', 'Authorization': f'Bearer {thehive_key}'}
thehive_url_create = "{}/api/v1/alert".format(thehive_url)
thehive_observables = []
for entry in playbook_results["indicators"]:
indicator = playbook_results["indicators"][entry]
dataType = False
if indicator["type"] == "ip-src" or indicator["type"] == "ip-dst":
dataType = "ip"
elif indicator["type"] == "url":
dataType = "url"
elif indicator["type"] == "hostname":
dataType = "hostname"
else:
dataType = "other"
if dataType:
thehive_observables.append({"dataType": dataType, "data": indicator["value"], "pap": thehive_pap, "tlp": thehive_tlp})
thehive_alert = {"title": thehive_alert_title,
"description": intro,
"summary": summary[0:1048576],
"type": thehive_alert_type,
"source": "playbook",
"sourceRef": thehive_alert_reference,
"tlp": thehive_tlp, "pap": thehive_pap,
"observables": thehive_observables}
result = requests.post(thehive_url_create, headers=thehive_headers, data=json.dumps(thehive_alert))
if result.json()['status'] == 'New':
thehive_alert_id = result.json()['_id']
print('The TheHive \033[92malert {} is added'.format(thehive_alert_id))
else:
print('\033[91mFailed\033[90m to add TheHive alert')
print(result.text)
The TheHive alert ~499856 is added
EN:4 End of the playbook¶
print("\033[92m End of the playbook")
End of the playbook
External references¶
Technical details¶
Documentation¶
This playbook requires these Python libraries to exist in the environment where the playbook is executed. You can install them with pip install <library>
.
pyfaup
chardet
PrettyTable
ipywidgets
attackcti
You need to have network access to
- your MISP server (HTTP or HTTPS)
- to your Mattermostand TheHive server
You need
- an API key with MISP
- Under Global Actions, My Profile. Add an extra authentication key.
- Add the API key (
misp_key
) and the MISP URL (misp_url
) tokeys.py
- Add the API key (
- If you use a self-signed certificate set
misp_verifycert
to False
- If you use a self-signed certificate set
- an incoming webhook in your Mattermost server
- Set this up under Integrations, Incoming Webhooks. Set as default channel your SOC/CSIRT team channel. For additional protection, lock the webhook so that the incoming webhook can post only to the selected channel.
- Add the webhook to
mattermost_hook
. It is displayed under 'integrations/incoming_webhooks' and set a username undermattermost_playbook_user
- Add the webhook to
- an API key with your TheHive server
- Click on your username (upper right corner), Settings and then API key
- Make sure that your user has 'manageAlert/create' privileges
- Add the API key (
thehive_key
) tokeys.py
and add the URL to TheHive (thehive_url
)
- Add the API key (
Colour codes¶
The output from Python displays some text in different colours. These are the colour codes
Red = '\033[91m'
Green = '\033[92m'
Blue = '\033[94m'
Cyan = '\033[96m'
White = '\033[97m'
Yellow = '\033[93m'
Magenta = '\033[95m'
Grey = '\033[90m'
Black = '\033[90m'
Default = '\033[99m'