diff options
author | W. Kosior <koszko@koszko.org> | 2025-01-09 01:03:21 +0100 |
---|---|---|
committer | W. Kosior <koszko@koszko.org> | 2025-01-09 01:03:21 +0100 |
commit | 35d695287eef188ce5520c068ba9f27be75747f4 (patch) | |
tree | 4b86f4d5e4d8b666d334af126c112d6f509ffff2 | |
parent | a602cb0280251264b63648e9687f15040a16f4f1 (diff) | |
download | AGH-threat-intel-course-35d695287eef188ce5520c068ba9f27be75747f4.tar.gz AGH-threat-intel-course-35d695287eef188ce5520c068ba9f27be75747f4.zip |
make tables of most targeted countries/sectors
-rw-r--r-- | Makefile | 28 | ||||
-rw-r--r-- | countries_table_doc.tex | 30 | ||||
-rwxr-xr-x | sectors_countries_tables.py | 130 | ||||
-rw-r--r-- | sectors_table_doc.tex | 38 |
4 files changed, 221 insertions, 5 deletions
@@ -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} |