Browse Source

0.2.0

master
boB Rudis 4 years ago
parent
commit
a651df92ea
No known key found for this signature in database GPG Key ID: 1D7529BE14E2BBA9
  1. 4
      DESCRIPTION
  2. 2
      NAMESPACE
  3. 60
      R/atck-cdf.R
  4. 7
      R/attck-map.R
  5. 16
      R/data-docs.R
  6. 17
      R/theme-enhance-atk.R
  7. 41
      README.md
  8. BIN
      data-raw/enterprise-attack.json.xz
  9. BIN
      data-raw/mobile-attack.json.xz
  10. BIN
      data-raw/pre-attack.json.xz
  11. BIN
      data/enterprise_attack.rda
  12. BIN
      data/mobile_attack.rda
  13. BIN
      data/pre_attack.rda
  14. BIN
      data/tidy_attack.rda
  15. BIN
      inst/extdat/more-incidents.rds
  16. BIN
      inst/extdat/sample-incidents.csv.gz
  17. 312
      inst/rmarkdown/templates/attcksummary/skeleton/skeleton.Rmd
  18. 5
      inst/rmarkdown/templates/attcksummary/template.yaml
  19. 24
      man/attck_cdf_tactic.Rd
  20. 4
      man/enterprise_attack.Rd
  21. BIN
      man/figures/README-events-1.png
  22. 4
      man/mobile_attack.Rd
  23. 4
      man/pre_attack.Rd
  24. 2
      man/tactics_f.Rd
  25. 11
      man/theme_enhance_atkmap.Rd
  26. 2
      man/tidy_attack.Rd
  27. 7
      tools/update-framework.R

4
DESCRIPTION

@ -1,8 +1,8 @@
Package: attckr Package: attckr
Type: Package Type: Package
Title: Analyze Adversary Tactics and Techniques Using the MITRE ATT&CK CTI Corpus Title: Analyze Adversary Tactics and Techniques Using the MITRE ATT&CK CTI Corpus
Version: 0.1.0 Version: 0.2.0
Date: 2019-07-28 Date: 2019-10-24
Authors@R: c( Authors@R: c(
person("Bob", "Rudis", email = "bob@rud.is", role = c("aut", "cre"), person("Bob", "Rudis", email = "bob@rud.is", role = c("aut", "cre"),
comment = c(ORCID = "0000-0001-5670-2640")) comment = c(ORCID = "0000-0001-5670-2640"))

2
NAMESPACE

@ -1,8 +1,10 @@
# Generated by roxygen2: do not edit by hand # Generated by roxygen2: do not edit by hand
export(attck_cdf_tactic)
export(attck_map) export(attck_map)
export(fct_tactic) export(fct_tactic)
export(read_events) export(read_events)
export(theme_enhance_atkmap)
export(validate_tactics) export(validate_tactics)
export(validate_technique_ids) export(validate_technique_ids)
export(validate_techniques) export(validate_techniques)

60
R/atck-cdf.R

@ -0,0 +1,60 @@
#' Product an ATT&CK Cumulative Distribution Function by Tactic
#'
#' @param xdf a data frame with `tactic`, `technique` and `value` columns.
#' If no `value` column exists, then the function will assume you
#' have passed in individual events and will perform a "count"
#' summarization before generating the heatmap.
#' @param input,output,matrix if both are not `NULL` then they should be
#' what [fct_tactic()] takes as parameters. Otherwise, the function
#' will assume that the `tactic` column is already an ordered factor.
#' @param ... passed on to [ggplot2::geom_label()]
#' @export
attck_cdf_tactic <- function(xdf, input = NULL, output = NULL, matrix = NULL, ...) {
cn <- colnames(xdf)
if (!all(c("tactic", "technique") %in% cn)) {
stop("'xdf' needs both 'tactic' and 'technique' columns.", call.=FALSE)
}
if (!("value" %in% cn)) {
xdf <- dplyr::count(xdf, tactic, technique, name = "value")
}
if (is.null(input) && is.null(output)) {
if (!is.factor(xdf$tactic)) {
stop(
"No 'input'/'output' transformation specified but 'tactic' is not a factor.",
call.=FALSE
)
}
} else {
if (sum(c(!is.null(input), !is.null(output), !is.null(matrix))) != 3) {
stop("Must specify 'input', 'output', and 'matrix' if any one of them is not NULL", call.=FALSE)
}
xdf$tactic <- fct_tactic(xdf$tactic, input = input, output = output, matrix = matrix)
}
xdf <- dplyr::count(xdf, tactic, wt=value)
xdf <- dplyr::arrange(xdf, tactic)
xdf <- dplyr::mutate(xdf, pct = n/sum(n))
xdf <- dplyr::mutate(xdf, cpct = cumsum(pct))
gg <- ggplot(xdf, aes(tactic, cpct, group=1))
gg <- gg + geom_path()
gg <- gg + geom_label(
aes(
label = sprintf("%s\n%s\n%s", scales::comma(n), scales::percent(pct), scales::percent(cpct)),
), lineheight = 0.875, ...
)
gg <- gg + scale_x_discrete(
expand = c(0, 0.5), position = "top",
breaks = levels(xdf$tactic), limits = levels(xdf$tactic)
)
gg <- gg + scale_y_continuous(
expand = c(0, 0.05), limits = c(-0.05, 1.05), label = scales::percent
)
gg <- gg + labs(x = NULL, y = NULL)
gg
}

7
R/attck-map.R

@ -61,9 +61,12 @@ attck_map <- function(xdf, input = NULL, output = NULL, matrix = NULL,
aes( aes(
label = technique, label = technique,
color = I(ifelse(value <= dark_value_threshold, dark_lab, light_lab)) color = I(ifelse(value <= dark_value_threshold, dark_lab, light_lab))
), ... ), lineheight = 0.875, ...
)
gg <- gg + scale_x_discrete(
expand = c(0, 0), position = "top",
labels = levels(xdf$tactic), limits = levels(xdf$tactic)
) )
gg <- gg + scale_x_discrete(expand = c(0, 0), position = "top")
gg <- gg + scale_y_reverse(expand = c(0, 0)) gg <- gg + scale_y_reverse(expand = c(0, 0))
gg gg

16
R/data-docs.R

@ -3,36 +3,36 @@
#' @title Enterprise Attack Taxonomy v2.0 #' @title Enterprise Attack Taxonomy v2.0
#' @name enterprise_attack #' @name enterprise_attack
#' @note Id: `bundle--24c77e72-f42e-48e5-9f6c-5ddfc02e8399` #' @note Id: `bundle--83dad14b-ae53-4473-9f95-5ae37c8eaa5d`
#' @note Last updated: 2019-07-31 #' @note Last updated: 2019-10-24
#' @references <https://github.com/mitre/cti/raw/master/enterprise-attack/enterprise-attack.json> #' @references <https://github.com/mitre/cti/raw/master/enterprise-attack/enterprise-attack.json>
#' @docType data #' @docType data
NULL NULL
#' @title Mobile Attack Taxonomy v2.0 #' @title Mobile Attack Taxonomy v2.0
#' @name mobile_attack #' @name mobile_attack
#' @note Id: `bundle--eeb1ff74-2747-4602-96fb-e7b220361101` #' @note Id: `bundle--d22f39d8-4fa0-4557-a925-1d7bbaffaa46`
#' @note Last updated: 2019-07-31 #' @note Last updated: 2019-10-24
#' @references <https://github.com/mitre/cti/raw/master/mobile-attack/mobile-attack.json> #' @references <https://github.com/mitre/cti/raw/master/mobile-attack/mobile-attack.json>
#' @docType data #' @docType data
NULL NULL
#' @title Pre-Attack Taxonomy v2.0 #' @title Pre-Attack Taxonomy v2.0
#' @name pre_attack #' @name pre_attack
#' @note Id: `bundle--0bf62d3b-a5a3-4dae-996d-e990ca6e2f4d` #' @note Id: `bundle--803f51fd-e986-493c-9ab1-0b33b42a4dec`
#' @note Last updated: 2019-07-31 #' @note Last updated: 2019-10-24
#' @references <https://github.com/mitre/cti/raw/master/pre-attack/pre-attack.json> #' @references <https://github.com/mitre/cti/raw/master/pre-attack/pre-attack.json>
#' @docType data #' @docType data
NULL NULL
#' @title Combined ATT&CK Matricies Tactics, Techniques and Technique detail #' @title Combined ATT&CK Matricies Tactics, Techniques and Technique detail
#' @name tidy_attack #' @name tidy_attack
#' @note Last updated: 2019-07-31 #' @note Last updated: 2019-10-24
#' @docType data #' @docType data
NULL NULL
#' @title Tactics factors (generally for sorting & pretty-printing) #' @title Tactics factors (generally for sorting & pretty-printing)
#' @name tactics_f #' @name tactics_f
#' @note Last updated: 2019-07-31 #' @note Last updated: 2019-10-24
#' @docType data #' @docType data
NULL NULL

17
R/theme-enhance-atk.R

@ -0,0 +1,17 @@
#' Remove cruft from ATT&CK heatmaps
#'
#' @export
theme_enhance_atkmap <- function () {
ret <- theme(panel.grid = element_blank())
ret <- ret + theme(axis.text.y = element_blank())
ret <- ret + theme(axis.title = element_blank())
ret <- ret + theme(axis.title.x = element_blank())
ret <- ret + theme(axis.title.x.top = element_blank())
ret <- ret + theme(axis.title.x.bottom = element_blank())
ret <- ret + theme(axis.title.y = element_blank())
ret <- ret + theme(axis.title.y.left = element_blank())
ret <- ret + theme(axis.title.y.right = element_blank())
ret <- ret + theme(legend.position = "bottom")
ret <- ret + theme(legend.key.width = unit(3, "lines"))
ret
}

41
README.md

@ -7,7 +7,9 @@ by](https://img.shields.io/badge/Keybase-Verified-brightgreen.svg)](https://keyb
![Signed commit ![Signed commit
%](https://img.shields.io/badge/Signed_Commits-100%25-lightgrey.svg) %](https://img.shields.io/badge/Signed_Commits-100%25-lightgrey.svg)
[![Linux build [![Linux build
Status](https://travis-ci.org/hrbrmstr/attckr.svg?branch=master)](https://travis-ci.org/hrbrmstr/attckr) Status](https://travis-ci.org/hrbrmstr/attckr.svg?branch=master)](https://travis-ci.org/hrbrmstr/attckr)
[![Coverage
Status](https://codecov.io/gh/hrbrmstr/attckr/branch/master/graph/badge.svg)](https://codecov.io/gh/hrbrmstr/attckr)
![Minimal R ![Minimal R
Version](https://img.shields.io/badge/R%3E%3D-3.2.0-blue.svg) Version](https://img.shields.io/badge/R%3E%3D-3.2.0-blue.svg)
![License](https://img.shields.io/badge/License-Apache-blue.svg) ![License](https://img.shields.io/badge/License-Apache-blue.svg)
@ -32,6 +34,8 @@ CTI Corpus.
The following functions are implemented: The following functions are implemented:
- `attck_cdf_tactic`: Product an ATT\&CK Cumulative Distribution
Function by Tactic
- `attck_map`: Generate an ATT\&CK heatmap - `attck_map`: Generate an ATT\&CK heatmap
- `enterprise_attack`: Enterprise Attack Taxonomy v2.0 - `enterprise_attack`: Enterprise Attack Taxonomy v2.0
- `fct_tactic`: Make an ordered Tactics factor with optional better - `fct_tactic`: Make an ordered Tactics factor with optional better
@ -41,6 +45,7 @@ The following functions are implemented:
- `read_events`: Read in ATT\&CK events from a file - `read_events`: Read in ATT\&CK events from a file
- `tactics_f`: Tactics factors (generally for sorting & - `tactics_f`: Tactics factors (generally for sorting &
pretty-printing) pretty-printing)
- `theme_enhance_atkmap`: Remove cruft from ATT\&CK heatmaps
- `tidy_attack`: Combined ATT\&CK Matricies Tactics, Techniques and - `tidy_attack`: Combined ATT\&CK Matricies Tactics, Techniques and
Technique detail Technique detail
- `validate_tactics`: Validate Tactics strings against MITRE - `validate_tactics`: Validate Tactics strings against MITRE
@ -87,25 +92,25 @@ library(tidyverse)
# current version # current version
packageVersion("attckr") packageVersion("attckr")
## [1] '0.1.0' ## [1] '0.2.0'
``` ```
``` r ``` r
tidy_attack tidy_attack
## # A tibble: 708 x 5 ## # A tibble: 795 x 5
## technique description id tactic matrix ## technique description id matrix tactic
## <chr> <chr> <chr> <chr> <chr> ## <chr> <chr> <chr> <chr> <chr>
## 1 .bash_profile and… "<code>~/.bash_profile</code> and <code>~/.bashrc</code> are exec… T1156 persistence mitre-at… ## 1 .bash_profile and… "<code>~/.bash_profile</code> and <code>~/.bashrc</code> are shel… T1156 mitre-at… persistence
## 2 Access Token Mani… "Windows uses access tokens to determine the ownership of a runni… T1134 defense-evas… mitre-at… ## 2 Access Token Mani… "Windows uses access tokens to determine the ownership of a runni… T1134 mitre-at… defense-evas…
## 3 Access Token Mani… "Windows uses access tokens to determine the ownership of a runni… T1134 privilege-es… mitre-at… ## 3 Access Token Mani… "Windows uses access tokens to determine the ownership of a runni… T1134 mitre-at… privilege-es…
## 4 Accessibility Fea… "Windows contains accessibility features that may be launched wit… T1015 persistence mitre-at ## 4 Access Token Mani… "Windows uses access tokens to determine the ownership of a runni… CAPEC-… mitre-at… defense-evas
## 5 Accessibility Fea… "Windows contains accessibility features that may be launched wit… T1015 privilege-es… mitre-at ## 5 Access Token Mani… "Windows uses access tokens to determine the ownership of a runni… CAPEC-… mitre-at… privilege-es
## 6 Accessibility Fea… "Windows contains accessibility features that may be launched wit… CAPEC-… persistence mitre-at… ## 6 Accessibility Fea… "Windows contains accessibility features that may be launched wit… T1015 mitre-at… persistence
## 7 Accessibility Fea… "Windows contains accessibility features that may be launched wit… CAPEC-… privilege-es… mitre-at ## 7 Accessibility Fea… "Windows contains accessibility features that may be launched wit… T1015 mitre-at… privilege-es
## 8 Account Discovery "Adversaries may attempt to get a listing of local system or doma… T1087 discovery mitre-at… ## 8 Accessibility Fea… "Windows contains accessibility features that may be launched wit… CAPEC-… mitre-at… persistence
## 9 Account Discovery "Adversaries may attempt to get a listing of local system or doma… CAPEC-… discovery mitre-at ## 9 Accessibility Fea… "Windows contains accessibility features that may be launched wit… CAPEC-… mitre-at… privilege-es
## 10 Account Manipulat… Account manipulation may aid adversaries in maintaining access to… T1098 credential-a… mitre-at… ## 10 Account Access Re… "Adversaries may interrupt availability of system and network res… T1531 mitre-at… impact
## # … with 698 more rows ## # … with 785 more rows
``` ```
``` r ``` r
@ -144,8 +149,8 @@ attck_map(
| Lang | \# Files | (%) | LoC | (%) | Blank lines | (%) | \# Lines | (%) | | Lang | \# Files | (%) | LoC | (%) | Blank lines | (%) | \# Lines | (%) |
| :--- | -------: | ---: | --: | ---: | ----------: | ---: | -------: | ---: | | :--- | -------: | ---: | --: | ---: | ----------: | ---: | -------: | ---: |
| R | 11 | 0.92 | 245 | 0.91 | 65 | 0.76 | 166 | 0.83 | | R | 13 | 0.93 | 304 | 0.93 | 72 | 0.78 | 180 | 0.84 |
| Rmd | 1 | 0.08 | 24 | 0.09 | 20 | 0.24 | 34 | 0.17 | | Rmd | 1 | 0.07 | 24 | 0.07 | 20 | 0.22 | 34 | 0.16 |
## Code of Conduct ## Code of Conduct

BIN
data-raw/enterprise-attack.json.xz

Binary file not shown.

BIN
data-raw/mobile-attack.json.xz

Binary file not shown.

BIN
data-raw/pre-attack.json.xz

Binary file not shown.

BIN
data/enterprise_attack.rda

Binary file not shown.

BIN
data/mobile_attack.rda

Binary file not shown.

BIN
data/pre_attack.rda

Binary file not shown.

BIN
data/tidy_attack.rda

Binary file not shown.

BIN
inst/extdat/more-incidents.rds

Binary file not shown.

BIN
inst/extdat/sample-incidents.csv.gz

Binary file not shown.

312
inst/rmarkdown/templates/attcksummary/skeleton/skeleton.Rmd

@ -0,0 +1,312 @@
---
title: "ATT&CK Metrics Overview"
output:
html_document:
toc: true
toc_float: true
toc_depth: 2
editor_options:
chunk_output_type: console
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(
echo = FALSE,
message = FALSE,
warning = FALSE,
fig.retina = 2,
fig.width=900/72,
fig.height = 700/72
)
```
```{r libs}
library(hrbrthemes)
library(attckr)
library(tidyverse)
```
```{r atk-data}
xdf <- readRDS(system.file("extdat/more-incidents.rds", package = "attckr"))
xdf <- mutate(xdf, quarter = sprintf("Q%d", lubridate::quarter(containment_ts)))
xdf <- mutate(xdf, month = lubridate::month(containment_ts, abbr=FALSE, label=TRUE))
```
# Dwell Time
```{r dwell-calc}
xdf %>%
mutate(delta = as.numeric(containment_ts - first_event_ts, "days")) %>%
ungroup() %>%
mutate(
delta_ord = case_when(
delta < 1 ~ "< 1 day",
delta < 2 ~ "1 day",
delta <= 7 ~ "1 week",
delta <= 14 ~ "2 weeks",
delta <= 28 ~ "1 month",
delta <= 46 ~ "2 months",
delta <= 84 ~ "3 months",
delta <= 112 ~ ">1 qtr",
is.na(delta) ~ "Unknown",
TRUE ~ "> 1 qtr"
)
) %>%
mutate(
delta_ord = factor(delta_ord, levels = c("< 1 day", "1 day", "1 week", "2 weeks", "1 month", "2 months", "3 months", ">1 qtr", "Unknown"))
) -> dwell_df
```
## Overall
```{r dwell-time-overall, fig.height = 400/72}
count(dwell_df, delta_ord) %>%
mutate(pct = n/sum(n)) %>%
ggplot(aes(delta_ord, pct)) +
geom_col(width=0.55, fill = ft_cols$blue) +
scale_y_percent(limits = c(0, 1)) +
labs(
x = NULL, y = "% Incidents",
title = "Dwell Time % (Overall)"
) +
theme_ipsum_es(grid="Y") +
theme(legend.position = "bottom")
```
## by Quarter
```{r dwell-time-quarter, fig.height = 900/72}
count(dwell_df, quarter, delta_ord) %>%
group_by(quarter) %>%
mutate(pct = n/sum(n)) %>%
ungroup() %>%
ggplot(aes(delta_ord, pct)) +
geom_col(width=0.55, fill = ft_cols$blue) +
scale_x_discrete(
breaks = c("< 1 day", "1 day", "1 week", "2 weeks", "1 month", "2 months", "3 months", ">1 qtr", "Unknown"),
limits = c("< 1 day", "1 day", "1 week", "2 weeks", "1 month", "2 months", "3 months", ">1 qtr", "Unknown")
) +
scale_y_percent(limits = c(0, 1)) +
facet_wrap(~quarter, ncol=1, scales = "free") +
labs(
x = NULL, y = "% Incidents",
title = "Dwell Time % (by Quarter)"
) +
theme_ipsum_es(grid="Y") +
theme(legend.position = "bottom")
```
```{r dwell-time-quarter-line}
count(dwell_df, quarter, delta_ord) %>%
group_by(quarter) %>%
mutate(pct = n/sum(n)) %>%
ungroup() %>%
arrange(quarter) %>%
mutate(quarter = fct_inorder(as.character(quarter)) %>% fct_rev()) %>%
complete(quarter, delta_ord) %>%
ggplot(aes(quarter, pct, group = delta_ord, color = delta_ord)) +
geom_line() +
geom_label(
aes(
label = scales::percent(pct),
), lineheight = 0.875, family = font_es, size = 4, show.legend = FALSE
) +
scale_x_discrete(position = "top") +
scale_y_percent(limits = c(-0.05, 1.05)) +
labs(
x = NULL, y = NULL, color = 'Dwell Time',
title = "Dwell Time % (by Quarter)"
) +
theme_ipsum_es(grid="Y") +
theme(legend.position = "bottom")
```
## by Month
```{r dwell-time-month}
count(dwell_df, month, delta_ord) %>%
group_by(month) %>%
mutate(pct = n/sum(n)) %>%
ungroup() %>%
arrange(month) %>%
mutate(month = fct_inorder(as.character(month)) %>% fct_rev()) %>%
complete(month, delta_ord) %>%
ggplot(aes(delta_ord, month)) +
geom_tile(aes(fill = pct), color = "white", size = 0.5) +
geom_text(
aes(
label = scales::percent(pct),
color = I(ifelse(pct > 0.1, "white", "black"))
), lineheight = 0.875, family = font_es, size = 4
) +
scale_x_discrete(position = "top") +
scale_fill_viridis_c(
option = "magma", direction = -1, trans = "identity", label = scales::percent
) +
labs(
x = NULL, y = NULL, fill = '%',
title = "Dwell Time % (by Month)"
) +
theme_ipsum_es(grid="Y") +
theme(legend.position = "bottom") +
theme(legend.key.width = unit(3, "lines"))
```
```{r dwell-time-month-line}
count(dwell_df, month, delta_ord) %>%
group_by(month) %>%
mutate(pct = n/sum(n)) %>%
ungroup() %>%
arrange(month) %>%
mutate(month = fct_inorder(as.character(month)) %>% fct_rev()) %>%
complete(month, delta_ord) %>%
ggplot(aes(month, pct, group = delta_ord, color = delta_ord)) +
geom_line() +
geom_label(
aes(
label = scales::percent(pct),
), lineheight = 0.875, family = font_es, size = 4, show.legend = FALSE
) +
scale_x_discrete(position = "top") +
scale_y_percent(limits = c(-0.05, 1.05)) +
labs(
x = NULL, y = NULL, color = 'Dwell Time',
title = "Dwell Time % (by Month)"
) +
theme_ipsum_es(grid="Y") +
theme(legend.position = "bottom")
```
# ATT&CK Heatmap
## Overall
```{r}
unnest(xdf, mitre_attack) %>%
select(tactic, technique) %>%
attck_map(
input = "pretty", output = "nl", matrix = "enterprise",
family = font_es, size = 3
) +
scale_fill_viridis_c(option = "magma") +
guides(
fill = guide_colourbar(title.position = "top")
) +
labs(
fill = "Tactics Raw Count: ",
title = "Overall ATT&CK Heatmap"
) +
theme_ipsum_es(grid="") +
theme_enhance_atkmap()
```
## by Quarter
```{r heatmap-by-quarter, fig.width = 1200/72, fig.height = 1200/72}
unnest(xdf, mitre_attack) %>%
mutate(quarter = sprintf("Q%d", lubridate::quarter(containment_ts))) %>%
count(quarter, tactic, technique) %>%
mutate(
tactic = fct_tactic(tactic, "pretty", "nl", "enterprise"),
technique = gsub("[[:space:]]+", "\n", technique),
) %>%
group_by(quarter, tactic) %>%
mutate(ids = (n():1)) -> plot_df
plot_df %>%
ggplot(aes(tactic, ids)) +
geom_tile(aes(fill = n), color = "white") +
geom_text(
aes(
label = technique,
color = I(ifelse(n > 20, "black", "white"))
),
family = font_es, size = 3, lineheight = 0.875
) +
scale_x_discrete(
breaks = levels(plot_df$tactic), limits = levels(plot_df$tactic),
position = "top"
) +
scale_y_reverse() +
scale_fill_viridis_c(option = "magma", trans = "log10", label = scales::comma) +
facet_wrap(~quarter, ncol = 1, scales = "free") +
guides(
fill = guide_colourbar(title.position = "top")
) +
labs(
fill = "Tactics Raw Count: ",
title = "Quarterly ATT&CK Heatmap"
) +
theme_ipsum_es(grid="") +
theme_enhance_atkmap() +
theme(strip.placement = "outside")
```
# Cumulative ATT&CK Tactics Distributions
## Overall
```{r attck-cdf-all}
unnest(xdf, mitre_attack) %>%
count(tactic) %>%
mutate(tactic = fct_tactic(tactic, "pretty", "nl")) %>%
arrange(tactic) %>%
mutate(pct = n/sum(n)) %>%
mutate(cpct = cumsum(pct)) -> cdf
ggplot(cdf, aes(tactic, cpct, group=1)) +
geom_path() +
geom_label(
aes(
label = sprintf("%s\n%s\n%s", scales::comma(n), scales::percent(pct), scales::percent(cpct)),
), lineheight = 0.875, family = font_es, size = 3
) +
scale_x_discrete(
expand = c(0, 0.5), position = "top",
breaks = levels(cdf$tactic), limits = levels(cdf$tactic)
) +
scale_y_continuous(
expand = c(0, 0.05), limits = c(-0.05, 1.05), label = scales::percent
) +
labs(
x = NULL, y = NULL,
title = "ATT&CK Tactics Cumulative Distribution (All Time)"
) +
theme_ipsum_es(grid="XY")
```
## by Industry
```{r attck-cdf-industry}
unnest(xdf, mitre_attack) %>%
count(tactic, industry) %>%
mutate(tactic = fct_tactic(tactic, "pretty", "nl")) %>%
arrange(tactic) %>%
group_by(industry) %>%
mutate(pct = n/sum(n)) %>%
mutate(cpct = cumsum(pct)) %>%
ungroup() -> cdf
ggplot(cdf, aes(tactic, cpct, group=industry)) +
geom_path(aes(colour = industry)) +
geom_label(
aes(
label = sprintf("%s\n%s\n%s", scales::comma(n), scales::percent(pct), scales::percent(cpct)),
color = industry,
), lineheight = 0.875, family = font_es, size = 3, show.legend = FALSE
) +
scale_x_discrete(
expand = c(0, 0.5), position = "top",
breaks = levels(cdf$tactic), limits = levels(cdf$tactic)
) +
scale_y_continuous(
expand = c(0, 0.05), limits = c(-0.05, 1.05), label = scales::percent
) +
ggthemes::scale_colour_tableau("Tableau 20") +
labs(
x = NULL, y = NULL, colour = NULL,
title = "ATT&CK Tactics Cumulative Distribution By Industry"
) +
theme_ipsum_es(grid="XY") +
theme(legend.position = "bottom")
```

5
inst/rmarkdown/templates/attcksummary/template.yaml

@ -0,0 +1,5 @@
name: ATT&CK Summary Report
description: >
Basic ATT&CK Summary Reporting (Customizable)
create_dir: false

24
man/attck_cdf_tactic.Rd

@ -0,0 +1,24 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/atck-cdf.R
\name{attck_cdf_tactic}
\alias{attck_cdf_tactic}
\title{Product an ATT&CK Cumulative Distribution Function by Tactic}
\usage{
attck_cdf_tactic(xdf, input = NULL, output = NULL, matrix = NULL,
...)
}
\arguments{
\item{xdf}{a data frame with \code{tactic}, \code{technique} and \code{value} columns.
If no \code{value} column exists, then the function will assume you
have passed in individual events and will perform a "count"
summarization before generating the heatmap.}
\item{input, output, matrix}{if both are not \code{NULL} then they should be
what \code{\link[=fct_tactic]{fct_tactic()}} takes as parameters. Otherwise, the function
will assume that the \code{tactic} column is already an ordered factor.}
\item{...}{passed on to \code{\link[ggplot2:geom_label]{ggplot2::geom_label()}}}
}
\description{
Product an ATT&CK Cumulative Distribution Function by Tactic
}

4
man/enterprise_attack.Rd

@ -8,9 +8,9 @@
Enterprise Attack Taxonomy v2.0 Enterprise Attack Taxonomy v2.0
} }
\note{ \note{
Id: \code{bundle--24c77e72-f42e-48e5-9f6c-5ddfc02e8399} Id: \code{bundle--83dad14b-ae53-4473-9f95-5ae37c8eaa5d}
Last updated: 2019-07-31 Last updated: 2019-10-24
} }
\references{ \references{
\url{https://github.com/mitre/cti/raw/master/enterprise-attack/enterprise-attack.json} \url{https://github.com/mitre/cti/raw/master/enterprise-attack/enterprise-attack.json}

BIN
man/figures/README-events-1.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 80 KiB

4
man/mobile_attack.Rd

@ -8,9 +8,9 @@
Mobile Attack Taxonomy v2.0 Mobile Attack Taxonomy v2.0
} }
\note{ \note{
Id: \code{bundle--eeb1ff74-2747-4602-96fb-e7b220361101} Id: \code{bundle--d22f39d8-4fa0-4557-a925-1d7bbaffaa46}
Last updated: 2019-07-31 Last updated: 2019-10-24
} }
\references{ \references{
\url{https://github.com/mitre/cti/raw/master/mobile-attack/mobile-attack.json} \url{https://github.com/mitre/cti/raw/master/mobile-attack/mobile-attack.json}

4
man/pre_attack.Rd

@ -8,9 +8,9 @@
Pre-Attack Taxonomy v2.0 Pre-Attack Taxonomy v2.0
} }
\note{ \note{
Id: \code{bundle--0bf62d3b-a5a3-4dae-996d-e990ca6e2f4d} Id: \code{bundle--803f51fd-e986-493c-9ab1-0b33b42a4dec}
Last updated: 2019-07-31 Last updated: 2019-10-24
} }
\references{ \references{
\url{https://github.com/mitre/cti/raw/master/pre-attack/pre-attack.json} \url{https://github.com/mitre/cti/raw/master/pre-attack/pre-attack.json}

2
man/tactics_f.Rd

@ -8,5 +8,5 @@
Tactics factors (generally for sorting & pretty-printing) Tactics factors (generally for sorting & pretty-printing)
} }
\note{ \note{
Last updated: 2019-07-31 Last updated: 2019-10-24
} }

11
man/theme_enhance_atkmap.Rd

@ -0,0 +1,11 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/theme-enhance-atk.R
\name{theme_enhance_atkmap}
\alias{theme_enhance_atkmap}
\title{Remove cruft from ATT&CK heatmaps}
\usage{
theme_enhance_atkmap()
}
\description{
Remove cruft from ATT&CK heatmaps
}

2
man/tidy_attack.Rd

@ -8,5 +8,5 @@
Combined ATT&CK Matricies Tactics, Techniques and Technique detail Combined ATT&CK Matricies Tactics, Techniques and Technique detail
} }
\note{ \note{
Last updated: 2019-07-31 Last updated: 2019-10-24
} }

7
tools/update-framework.R

@ -67,7 +67,6 @@ mobile_attack[["objects"]] <- tibble::as_tibble(mobile_attack[["objects"]])
# Make Pre matrix --------------------------------------------------------- # Make Pre matrix ---------------------------------------------------------
jsonlite::fromJSON( jsonlite::fromJSON(
here::here("data-raw/pre-attack.json.xz") here::here("data-raw/pre-attack.json.xz")
) -> pre_attack ) -> pre_attack
@ -86,7 +85,7 @@ bind_rows(
id = discard(enterprise_attack$objects$external_references[[.x]]$external_id, is.na) %||% NA_character_, id = discard(enterprise_attack$objects$external_references[[.x]]$external_id, is.na) %||% NA_character_,
phs = enterprise_attack$objects$kill_chain_phases[.x] phs = enterprise_attack$objects$kill_chain_phases[.x]
) %>% ) %>%
unnest() unnest(phs)
}), }),
map_df(1:nrow(mobile_attack$objects), ~{ map_df(1:nrow(mobile_attack$objects), ~{
if (is.na(mobile_attack$objects$name[[.x]])) return(NULL) if (is.na(mobile_attack$objects$name[[.x]])) return(NULL)
@ -97,7 +96,7 @@ bind_rows(
id = discard(mobile_attack$objects$external_references[[.x]]$external_id, is.na) %||% NA_character_, id = discard(mobile_attack$objects$external_references[[.x]]$external_id, is.na) %||% NA_character_,
phs = mobile_attack$objects$kill_chain_phases[.x] phs = mobile_attack$objects$kill_chain_phases[.x]
) %>% ) %>%
unnest() unnest(phs)
}), }),
map_df(1:nrow(pre_attack$objects), ~{ map_df(1:nrow(pre_attack$objects), ~{
if (is.na(pre_attack$objects$name[[.x]])) return(NULL) if (is.na(pre_attack$objects$name[[.x]])) return(NULL)
@ -108,7 +107,7 @@ bind_rows(
id = discard(pre_attack$objects$external_references[[.x]]$external_id, is.na) %||% NA_character_, id = discard(pre_attack$objects$external_references[[.x]]$external_id, is.na) %||% NA_character_,
phs = pre_attack$objects$kill_chain_phases[.x] phs = pre_attack$objects$kill_chain_phases[.x]
) %>% ) %>%
unnest() unnest(phs)
}) })
) %>% ) %>%
rename(tactic = phase_name, matrix = kill_chain_name) %>% rename(tactic = phase_name, matrix = kill_chain_name) %>%

Loading…
Cancel
Save