summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorW. Kosior <koszko@koszko.org>2025-01-09 01:03:21 +0100
committerW. Kosior <koszko@koszko.org>2025-01-09 01:03:21 +0100
commit35d695287eef188ce5520c068ba9f27be75747f4 (patch)
tree4b86f4d5e4d8b666d334af126c112d6f509ffff2
parenta602cb0280251264b63648e9687f15040a16f4f1 (diff)
downloadAGH-threat-intel-course-35d695287eef188ce5520c068ba9f27be75747f4.tar.gz
AGH-threat-intel-course-35d695287eef188ce5520c068ba9f27be75747f4.zip
make tables of most targeted countries/sectors
-rw-r--r--Makefile28
-rw-r--r--countries_table_doc.tex30
-rwxr-xr-xsectors_countries_tables.py130
-rw-r--r--sectors_table_doc.tex38
4 files changed, 221 insertions, 5 deletions
diff --git a/Makefile b/Makefile
index a830b0d..1d9031e 100644
--- a/Makefile
+++ b/Makefile
@@ -13,8 +13,11 @@ PDFTOHTML=pdftohtml
DEFAULT_TARGETS = \
profiles_with_scraped_info.yaml \
+ blackobird_scraped_profiles.yaml \
tables.pdf \
- techniques_table_doc.pdf
+ techniques_table_doc.pdf \
+ sectors_table_doc.pdf \
+ countries_table_doc.pdf \
all: $(DEFAULT_TARGETS)
.PHONY: all
@@ -56,19 +59,34 @@ blackobird_scraped_profiles.yaml: scrape_blackobird_groups_info.py \
techniques_table.tex: techniques_table.py profiles_with_scraped_info.yaml
$(PYTHON) $^ > $@
-techniques_table_doc.pdf: techniques_table_doc.tex tlp.tex techniques_table.tex
+# hack
+sector country:
+ true
+.PHONY: sector country
+
+countries_table.tex: sectors_countries_tables.py country \
+ blackobird_scraped_profiles.yaml
+ $(PYTHON) $^ > $@
+
+sectors_table.tex: sectors_countries_tables.py sector \
+ blackobird_scraped_profiles.yaml
+ $(PYTHON) $^ > $@
+
+%_table_doc.pdf: %_table_doc.tex tlp.tex %_table.tex
$(LATEXMK) -pdf $<
th-proj-archive.tar.gz: Makefile profiles.yaml scrape_mitre_groups_info.py \
tables.md techniques_table_doc.tex techniques_table.py \
- threats_by_sector_table.py tlp.tex $(DEFAULT_TARGETS)
+ sectors_table_doc.tex countries_table_doc.tex \
+ sectors_countries_tables.py threats_by_sector_table.py tlp.tex \
+ $(DEFAULT_TARGETS)
tar --transform='s|^|th-proj-archive/|' \
--mtime=1970-01-01T00:00:00-00:00 --group=0 --owner=0 \
-czf $@ $^
clean:
- rm -rf tables.md techniques_table.tex th-proj-archive.tar.gz \
- $(DEFAULT_TARGETS)
+ rm -rf tables.md techniques_table.tex countries_table.tex \
+ sectors_table.tex th-proj-archive.tar.gz $(DEFAULT_TARGETS)
$(LATEXMK) -C
.PHONY: clean
diff --git a/countries_table_doc.tex b/countries_table_doc.tex
new file mode 100644
index 0000000..c047332
--- /dev/null
+++ b/countries_table_doc.tex
@@ -0,0 +1,30 @@
+%% SPDX-License-Identifier: CC0-1.0
+%%
+%% This LaTeX source is copyright (C) 2024, 2025 W. Kosior <koszko@koszko.org>
+
+\documentclass{article}
+
+\usepackage[a4paper, total={6in, 8in}, margin=1in]{geometry}
+\usepackage[skip=10pt plus1pt, indent=20pt]{parskip}
+\usepackage{longtable}
+\usepackage[table]{xcolor}
+\usepackage{hyperref}
+\hypersetup{
+ colorlinks,
+ urlcolor={blue!80!black}
+}
+\usepackage{textcomp}
+
+\input{tlp.tex}
+
+\title{Statistics of groups targeting particular countries}
+
+\author{Wojciech Kosior}
+
+\begin{document}
+
+\useTLPFancyHeader{CLEAR}
+
+\input{countries_table.tex}
+
+\end{document}
diff --git a/sectors_countries_tables.py b/sectors_countries_tables.py
new file mode 100755
index 0000000..1184691
--- /dev/null
+++ b/sectors_countries_tables.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python3
+
+# SPDX-License-Identifier: CC0-1.0
+#
+# Copyright (C) 2024, 2025 Wojtek Kosior <koszko@koszko.org>
+
+import yaml
+import sys
+
+origin_labels = {
+ "China": "China",
+ "Iran": "Iran",
+ "NorthKorea": "North Korea",
+ "Russia": "Russia"
+}
+
+type_keys = {
+ "country": "countries",
+ "sector": "sectors"
+}
+
+trait_label_makers = {
+ "country": (lambda country:
+ {
+ "usa": "USA",
+ "uk": "UK",
+ "southkorea": "South Korea",
+ "saudiarabia": "Saudi Arabia",
+ "uae": "UAE",
+ "hongkong": "Hong Kong",
+ "northkorea": "North Korea"
+ }.get(country, country[0].upper() + country[1:])),
+ "sector": (lambda sector:
+ {
+ "it": "IT",
+ "ngos": "NGOs",
+ "thinktanks": "think-tanks",
+ "bitcoinexchanges": "cryptocurrency",
+ "lawenforcement": "law enforcement"
+ }.get(sector, sector))
+}
+
+trait_filters = {
+ "country": (lambda country, score:
+ score >= 10 and country not in [
+ "europe", "eastasia", "others", "south", "worldwide",
+ "middleeast", "korea"
+ ]),
+ "sector": (lambda sector, score:
+ score >= 10 and sector not in [
+ "sejonginstitute", "ministryofunification",
+ "koreainstitutefordefenseanalyses",
+ "chineseinstitutionsabroad"
+ ])
+}
+trait_cutoff_score = {
+ "country": 10,
+ "sector": 0
+}
+
+def read_APT_data(yaml_path):
+ if yaml_path:
+ with open(yaml_path) as inp:
+ return yaml.safe_load(inp)
+ else:
+ return yaml.safe_load(sys.stdin)
+
+table_type = sys.argv[1] # "country" or "sector"
+
+groups_data = read_APT_data(None if len(sys.argv) < 3 else sys.argv[2])
+
+groups_by_origin = {}
+groups_by_trait_by_origin = {}
+
+for group in groups_data["groups"]:
+ if group["origin"] not in origin_labels:
+ continue
+ origin = group["origin"]
+ groups_by_origin[origin] = groups_by_origin.get(origin, []) + [group]
+
+ groups_by_trait = groups_by_trait_by_origin.get(origin, {})
+ for trait in group[type_keys[table_type]]:
+ groups_by_trait[trait] = groups_by_trait.get(trait, []) + [group]
+ groups_by_trait_by_origin[origin] = groups_by_trait
+
+def trait_percent(trait, origin):
+ return (100 * len(groups_by_trait_by_origin[origin].get(trait, [])) /
+ len(groups_by_origin[origin]))
+
+def trait_popularity_score(trait):
+ return sum(trait_percent(trait, origin)
+ for origin in groups_by_origin)
+
+all_traits_set = set().union(*groups_by_trait_by_origin.values())
+all_traits = sorted(((trait_popularity_score(trait), trait)
+ for trait in all_traits_set),
+ reverse=True)
+all_traits = [trait for score, trait in all_traits
+ if trait_filters[table_type](trait, score)]
+
+all_origins = sorted(groups_by_origin)
+all_origin_labels = [origin_labels[origin] for origin in all_origins]
+
+print("{")
+print("\\footnotesize")
+print("\\rowcolors{3}{gray!20}{white!100}")
+print("\\renewcommand*{\\arraystretch}{1.3}")
+print("""\
+\\begin{longtable}{\
+p{0.3\\textwidth} \
+p{0.65in} p{0.65in} p{0.65in} p{0.65in} \
+>{\\centering\\arraybackslash} p{0.85in} \
+}""")
+print(f"{table_type} & {' & '.join(all_origin_labels)} & total APT count \\\\")
+print("\\hline\\hline \\endhead")
+
+for trait in all_traits:
+ label = trait_label_makers[table_type](trait)
+ group_count = sum([len(groups_by_trait_by_origin[origin].get(trait, []))
+ for origin in all_origins])
+
+ group_precents_markup = ' & '.join(
+ f"{round(trait_percent(trait, origin))}\\% groups"
+ for origin in all_origins
+ )
+
+ print(f"{label} & {group_precents_markup} & {group_count} \\\\")
+
+print("\\end{longtable}")
+print("}")
diff --git a/sectors_table_doc.tex b/sectors_table_doc.tex
new file mode 100644
index 0000000..a3c87e4
--- /dev/null
+++ b/sectors_table_doc.tex
@@ -0,0 +1,38 @@
+%% SPDX-License-Identifier: CC0-1.0
+%%
+%% This LaTeX source is copyright (C) 2024, 2025 W. Kosior <koszko@koszko.org>
+
+\documentclass{article}
+
+\usepackage[a4paper, total={6in, 8in}, margin=1in]{geometry}
+\usepackage[skip=10pt plus1pt, indent=20pt]{parskip}
+\usepackage{longtable}
+\usepackage[table]{xcolor}
+\usepackage{hyperref}
+\hypersetup{
+ colorlinks,
+ urlcolor={blue!80!black}
+}
+\usepackage{textcomp}
+
+\input{tlp.tex}
+
+\title{Statistics of groups targeting particular sectors of industry}
+
+\author{Wojciech Kosior}
+
+\begin{document}
+
+\useTLPFancyHeader{CLEAR}
+
+\input{sectors_table.tex}
+
+\section*{Legal}
+
+Sector names presented above are derived from Threat Actor Encyclopedia
+Copyright {\copyright} Electronic Transactions Development Agency (Public
+Organization), 2019. Content of the Encyclopedia is covered by
+\href{https://creativecommons.org/licenses/by-nc-sa/4.0/}{Creative Commons
+ Attribution-NonCommercial-ShareAlike 4.0 International License}.
+
+\end{document}