├── vignettes ├── .gitignore └── Introduction.Rmd ├── R ├── sysdata.rda ├── data.R └── mitre.R ├── data ├── cpe.nist.rda ├── cve.nist.rda ├── car.model.rda ├── cwe.views.rda ├── attck.groups.rda ├── attck.tactics.rda ├── capec.views.rda ├── car.analytics.rda ├── car.coverage.rda ├── car.relations.rda ├── car.sensors.rda ├── attck.relations.rda ├── attck.software.rda ├── capec.patterns.rda ├── capec.relations.rda ├── cwe.categories.rda ├── cwe.weaknesses.rda ├── shield.tactics.rda ├── attck.mitigations.rda ├── attck.techniques.rda ├── capec.categories.rda ├── shield.procedures.rda ├── shield.relations.rda ├── shield.techniques.rda ├── shield.use_cases.rda ├── car.implementations.rda └── shield.opportunities.rda ├── tests ├── testthat.R └── testthat │ └── test_internaldata.R ├── NAMESPACE ├── man ├── figures │ └── README-example2-1.png ├── cwe.views.Rd ├── car.model.Rd ├── capec.views.Rd ├── car.sensors.Rd ├── car.coverage.Rd ├── attck.groups.Rd ├── car.relations.Rd ├── attck.tactics.Rd ├── car.analytics.Rd ├── cwe.categories.Rd ├── shield.tactics.Rd ├── attck.software.Rd ├── capec.patterns.Rd ├── capec.relations.Rd ├── cwe.weaknesses.Rd ├── attck.relations.Rd ├── capec.categories.Rd ├── shield.relations.Rd ├── shield.use_cases.Rd ├── attck.techniques.Rd ├── shield.procedures.Rd ├── shield.techniques.Rd ├── attck.mitigations.Rd ├── car.implementations.Rd ├── shield.opportunities.Rd ├── cpe.nist.Rd ├── cve.nist.Rd ├── build_network.Rd ├── build_edges.Rd ├── newEdge.Rd ├── newNode.Rd └── build_nodes.Rd ├── .travis.yml ├── .Rbuildignore ├── cran-comments.md ├── mitre.Rproj ├── .gitignore ├── DESCRIPTION ├── data-raw ├── build_data.R ├── nist-cpe.R ├── nist-cve.R ├── mitre-shield.R ├── mitre-attck.R ├── mitre-car.R ├── mitre-capec.R └── mitre-cwe.R ├── NEWS.md ├── README.Rmd ├── README.md └── LICENSE.md /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.R 2 | *.html 3 | -------------------------------------------------------------------------------- /R/sysdata.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/R/sysdata.rda -------------------------------------------------------------------------------- /data/cpe.nist.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/cpe.nist.rda -------------------------------------------------------------------------------- /data/cve.nist.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/cve.nist.rda -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(mitre) 3 | 4 | test_check("mitre") 5 | -------------------------------------------------------------------------------- /data/car.model.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/car.model.rda -------------------------------------------------------------------------------- /data/cwe.views.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/cwe.views.rda -------------------------------------------------------------------------------- /data/attck.groups.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/attck.groups.rda -------------------------------------------------------------------------------- /data/attck.tactics.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/attck.tactics.rda -------------------------------------------------------------------------------- /data/capec.views.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/capec.views.rda -------------------------------------------------------------------------------- /data/car.analytics.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/car.analytics.rda -------------------------------------------------------------------------------- /data/car.coverage.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/car.coverage.rda -------------------------------------------------------------------------------- /data/car.relations.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/car.relations.rda -------------------------------------------------------------------------------- /data/car.sensors.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/car.sensors.rda -------------------------------------------------------------------------------- /data/attck.relations.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/attck.relations.rda -------------------------------------------------------------------------------- /data/attck.software.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/attck.software.rda -------------------------------------------------------------------------------- /data/capec.patterns.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/capec.patterns.rda -------------------------------------------------------------------------------- /data/capec.relations.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/capec.relations.rda -------------------------------------------------------------------------------- /data/cwe.categories.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/cwe.categories.rda -------------------------------------------------------------------------------- /data/cwe.weaknesses.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/cwe.weaknesses.rda -------------------------------------------------------------------------------- /data/shield.tactics.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/shield.tactics.rda -------------------------------------------------------------------------------- /data/attck.mitigations.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/attck.mitigations.rda -------------------------------------------------------------------------------- /data/attck.techniques.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/attck.techniques.rda -------------------------------------------------------------------------------- /data/capec.categories.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/capec.categories.rda -------------------------------------------------------------------------------- /data/shield.procedures.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/shield.procedures.rda -------------------------------------------------------------------------------- /data/shield.relations.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/shield.relations.rda -------------------------------------------------------------------------------- /data/shield.techniques.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/shield.techniques.rda -------------------------------------------------------------------------------- /data/shield.use_cases.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/shield.use_cases.rda -------------------------------------------------------------------------------- /data/car.implementations.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/car.implementations.rda -------------------------------------------------------------------------------- /data/shield.opportunities.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/data/shield.opportunities.rda -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(build_network) 4 | importFrom(rlang,.data) 5 | -------------------------------------------------------------------------------- /man/figures/README-example2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motherhack3r/mitre/HEAD/man/figures/README-example2-1.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | 3 | language: R 4 | cache: packages 5 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^LICENSE\.md$ 4 | ^README\.Rmd$ 5 | ^\.travis\.yml$ 6 | cran-comments.md 7 | ^CRAN-RELEASE$ 8 | ^data-raw$ 9 | ^data$ 10 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Test environments 2 | * local win10 install, R 4.1.0 3 | * Ubuntu 16.04.6 LTS (on travis-ci), R 4.0.2 4 | * Ubuntu Linux 20.04.1 LTS, R-release, GCC, R version 4.0.5 (RHub) 5 | * Fedora Linux, R-devel, clang, gfortran (RHub) 6 | 7 | ## R CMD check results 8 | There were no ERRORs or WARNINGs. 9 | -------------------------------------------------------------------------------- /man/cwe.views.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{cwe.views} 5 | \alias{cwe.views} 6 | \title{CWE views Objects.} 7 | \format{ 8 | A data frame with 7 variables. 9 | } 10 | \usage{ 11 | cwe.views 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/car.model.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{car.model} 5 | \alias{car.model} 6 | \title{CAR data model Objects.} 7 | \format{ 8 | A data frame with 8 variables. 9 | } 10 | \usage{ 11 | car.model 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/capec.views.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{capec.views} 5 | \alias{capec.views} 6 | \title{CAPEC views Objects.} 7 | \format{ 8 | A data frame with 5 variables. 9 | } 10 | \usage{ 11 | capec.views 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/car.sensors.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{car.sensors} 5 | \alias{car.sensors} 6 | \title{CAR sensors Objects.} 7 | \format{ 8 | A data frame with 5 variables. 9 | } 10 | \usage{ 11 | car.sensors 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/car.coverage.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{car.coverage} 5 | \alias{car.coverage} 6 | \title{CAR coverage Objects.} 7 | \format{ 8 | A data frame with 4 variables. 9 | } 10 | \usage{ 11 | car.coverage 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/attck.groups.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{attck.groups} 5 | \alias{attck.groups} 6 | \title{ATT&CK Groups Objects.} 7 | \format{ 8 | A data frame with 11 variables. 9 | } 10 | \usage{ 11 | attck.groups 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/car.relations.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{car.relations} 5 | \alias{car.relations} 6 | \title{CAR relations Objects.} 7 | \format{ 8 | A data frame with 2 variables. 9 | } 10 | \usage{ 11 | car.relations 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/attck.tactics.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{attck.tactics} 5 | \alias{attck.tactics} 6 | \title{ATT&CK tactics Objects.} 7 | \format{ 8 | A data frame with 11 variables. 9 | } 10 | \usage{ 11 | attck.tactics 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/car.analytics.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{car.analytics} 5 | \alias{car.analytics} 6 | \title{CAR analytics Objects.} 7 | \format{ 8 | A data frame with 17 variables. 9 | } 10 | \usage{ 11 | car.analytics 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/cwe.categories.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{cwe.categories} 5 | \alias{cwe.categories} 6 | \title{CWE categories Objects.} 7 | \format{ 8 | A data frame with 7 variables. 9 | } 10 | \usage{ 11 | cwe.categories 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/shield.tactics.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{shield.tactics} 5 | \alias{shield.tactics} 6 | \title{SHIELD tactics Objects.} 7 | \format{ 8 | A data frame with 4 variables. 9 | } 10 | \usage{ 11 | shield.tactics 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/attck.software.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{attck.software} 5 | \alias{attck.software} 6 | \title{ATT&CK software Objects.} 7 | \format{ 8 | A data frame with 12 variables. 9 | } 10 | \usage{ 11 | attck.software 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/capec.patterns.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{capec.patterns} 5 | \alias{capec.patterns} 6 | \title{CAPEC patterns Objects.} 7 | \format{ 8 | A data frame with 16 variables. 9 | } 10 | \usage{ 11 | capec.patterns 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/capec.relations.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{capec.relations} 5 | \alias{capec.relations} 6 | \title{CAPEC relations Objects.} 7 | \format{ 8 | A data frame with 4 variables. 9 | } 10 | \usage{ 11 | capec.relations 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/cwe.weaknesses.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{cwe.weaknesses} 5 | \alias{cwe.weaknesses} 6 | \title{CWE Weaknesses Objects.} 7 | \format{ 8 | A data frame with 24 variables. 9 | } 10 | \usage{ 11 | cwe.weaknesses 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/attck.relations.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{attck.relations} 5 | \alias{attck.relations} 6 | \title{ATT&CK relations Objects.} 7 | \format{ 8 | A data frame with 13 variables. 9 | } 10 | \usage{ 11 | attck.relations 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/capec.categories.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{capec.categories} 5 | \alias{capec.categories} 6 | \title{CAPEC categories Objects.} 7 | \format{ 8 | A data frame with 4 variables. 9 | } 10 | \usage{ 11 | capec.categories 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/shield.relations.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{shield.relations} 5 | \alias{shield.relations} 6 | \title{SHIELD relations Objects.} 7 | \format{ 8 | A data frame with 3 variables. 9 | } 10 | \usage{ 11 | shield.relations 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/shield.use_cases.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{shield.use_cases} 5 | \alias{shield.use_cases} 6 | \title{SHIELD use cases Objects.} 7 | \format{ 8 | A data frame with 2 variables. 9 | } 10 | \usage{ 11 | shield.use_cases 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/attck.techniques.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{attck.techniques} 5 | \alias{attck.techniques} 6 | \title{ATT&CK techniques Objects.} 7 | \format{ 8 | A data frame with 15 variables. 9 | } 10 | \usage{ 11 | attck.techniques 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/shield.procedures.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{shield.procedures} 5 | \alias{shield.procedures} 6 | \title{SHIELD procedures Objects.} 7 | \format{ 8 | A data frame with 2 variables. 9 | } 10 | \usage{ 11 | shield.procedures 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/shield.techniques.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{shield.techniques} 5 | \alias{shield.techniques} 6 | \title{SHIELD techniques Objects.} 7 | \format{ 8 | A data frame with 4 variables. 9 | } 10 | \usage{ 11 | shield.techniques 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/attck.mitigations.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{attck.mitigations} 5 | \alias{attck.mitigations} 6 | \title{ATT&CK Mitigation Objects.} 7 | \format{ 8 | A data frame with 12 variables. 9 | } 10 | \usage{ 11 | attck.mitigations 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/car.implementations.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{car.implementations} 5 | \alias{car.implementations} 6 | \title{CAR implementations Objects.} 7 | \format{ 8 | A data frame with 7 variables. 9 | } 10 | \usage{ 11 | car.implementations 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/shield.opportunities.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{shield.opportunities} 5 | \alias{shield.opportunities} 6 | \title{SHIELD opportunities Objects.} 7 | \format{ 8 | A data frame with 2 variables. 9 | } 10 | \usage{ 11 | shield.opportunities 12 | } 13 | \description{ 14 | Full data set provided by MITRE 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/cpe.nist.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{cpe.nist} 5 | \alias{cpe.nist} 6 | \title{Common Platform Enumeration.} 7 | \format{ 8 | A data frame with 16 variables: \code{title}, \code{cpe.22}, 9 | \code{cpe.23}, and all separated values. 10 | } 11 | \usage{ 12 | cpe.nist 13 | } 14 | \description{ 15 | Full data set provided by NIST. 16 | } 17 | \keyword{datasets} 18 | -------------------------------------------------------------------------------- /mitre.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: knitr 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageCheckArgs: --as-cran 22 | PackageRoxygenize: rd,collate,namespace,vignette 23 | -------------------------------------------------------------------------------- /man/cve.nist.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{cve.nist} 5 | \alias{cve.nist} 6 | \title{Common Vulnerability Enumeration.} 7 | \format{ 8 | A data frame with 34 variables: \code{cve.id}, \code{problem.type} which is related to CWE, 9 | \code{description}, \code{vulnerable.configuration} which is related to CPE, 10 | \code{references}, \code{cvss3}, \code{cvss2} and all separated values. 11 | } 12 | \usage{ 13 | cve.nist 14 | } 15 | \description{ 16 | Full data set provided by NIST. 17 | } 18 | \keyword{datasets} 19 | -------------------------------------------------------------------------------- /tests/testthat/test_internaldata.R: -------------------------------------------------------------------------------- 1 | test_that("Check data sets", { 2 | # ATTCK 3 | expect_true(is.data.frame(attck.groups)) 4 | expect_true(is.data.frame(attck.mitigations)) 5 | expect_true(is.data.frame(attck.relations)) 6 | expect_true(is.data.frame(attck.software)) 7 | expect_true(is.data.frame(attck.tactics)) 8 | expect_true(is.data.frame(attck.techniques)) 9 | # SHIELD 10 | expect_true(is.data.frame(shield.opportunities)) 11 | expect_true(is.data.frame(shield.procedures)) 12 | expect_true(is.data.frame(shield.relations)) 13 | expect_true(is.data.frame(shield.tactics)) 14 | expect_true(is.data.frame(shield.techniques)) 15 | expect_true(is.data.frame(shield.use_cases)) 16 | }) 17 | #> Test passed 😸 18 | -------------------------------------------------------------------------------- /man/build_network.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mitre.R 3 | \name{build_network} 4 | \alias{build_network} 5 | \title{Create a list of nodes and edges related to all standards in data folder.} 6 | \usage{ 7 | build_network(verbose = FALSE, as_igraph = TRUE) 8 | } 9 | \arguments{ 10 | \item{verbose}{logical, FALSE by default. Change it to see the process messages.} 11 | 12 | \item{as_igraph}{logical, TRUE by default. Change it to get list of nodes and edges.} 13 | } 14 | \value{ 15 | list, containing nodes and edges as data frames 16 | } 17 | \description{ 18 | Create a list of nodes and edges related to all standards in data folder. 19 | } 20 | \examples{ 21 | mitrenet <- mitre::build_network(as_igraph = FALSE) 22 | } 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # History files 2 | .Rhistory 3 | .Rapp.history 4 | 5 | # Session Data files 6 | .RData 7 | inst/scripts/ 8 | 9 | # User-specific files 10 | .Ruserdata 11 | 12 | # Example code in package build process 13 | *-Ex.R 14 | 15 | # Output files from R CMD build 16 | /*.tar.gz 17 | 18 | # Output files from R CMD check 19 | /*.Rcheck/ 20 | 21 | # RStudio files 22 | .Rproj.user/ 23 | *.Rproj 24 | 25 | # produced vignettes 26 | vignettes/*.html 27 | 28 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 29 | .httr-oauth 30 | 31 | # knitr and R markdown default cache directories 32 | *_cache/ 33 | /cache/ 34 | 35 | # Temporary files created by R markdown 36 | *.utf8.md 37 | *.knit.md 38 | 39 | # R Environment Variables 40 | .Renviron 41 | inst/temp 42 | 43 | # CRAN-RELEASE 131d5d7 44 | CRAN-RELEASE 45 | 46 | # Raw files 47 | data-raw/*.json 48 | data-raw/*.xml 49 | data-raw/*.gz 50 | data-raw/*.zip 51 | inst/doc 52 | -------------------------------------------------------------------------------- /vignettes/Introduction.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Introduction" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Introduction} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | ```{r setup} 18 | # library(mitre) 19 | ``` 20 | 21 | # Cyber security data sets 22 | 23 | ## Explore cybersecurity standards 24 | 25 | This is a basic example which shows you how to view shield tactics ids and names: 26 | 27 | ```{r example} 28 | # shield.tactics[, c("id", "name")] 29 | ``` 30 | 31 | This example shows the distribution of vulnerability risk: 32 | 33 | ```{r example2} 34 | # hist(cve.nist$cvss3.score, 35 | # main = "CVE risk distribution", xlab = "cvss3") 36 | ``` 37 | 38 | 39 | ## Standards network 40 | 41 | This code shows you the type of nodes for each standard: 42 | 43 | ```{r example3} 44 | # mitrenet <- build_network(as_igraph = FALSE) 45 | # table(mitrenet$nodes$type, mitrenet$nodes$group) 46 | ``` 47 | 48 | And the type of relationships: 49 | ```{r example4} 50 | # table(mitrenet$edges$label) 51 | ``` 52 | -------------------------------------------------------------------------------- /man/build_edges.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mitre.R 3 | \name{build_edges} 4 | \alias{build_edges} 5 | \title{Extract relationships between standards as edges in a data frame.} 6 | \usage{ 7 | build_edges(verbose = FALSE) 8 | } 9 | \arguments{ 10 | \item{verbose}{logical, FALSE by default. Change it to see the process messages.} 11 | } 12 | \value{ 13 | data.frame 14 | } 15 | \description{ 16 | \code{from} : node id of edge start 17 | \code{to} : node id of edge end 18 | \code{from_std} : standard id of edge start 19 | \code{to_std} : standard id of edge end 20 | \code{value} : When a value is set, the nodes will be scaled using the options in the scaling object defined above. 21 | \code{title} : The title is shown in a pop-up when the mouse moves over the edge. 22 | \code{arrows} : To draw an arrow with default settings a string can be supplied. For example: 'to, from,middle' or 'to;from', any combination with any separating symbol is fine. If you want to control the size of the arrowheads, you can supply an object. 23 | \code{dashes} : When true, the edge will be drawn as a dashed line. 24 | \code{color} : Color for the node. 25 | \code{hidden} : When true, the node will not be shown. It will still be part of the physics simulation though! 26 | } 27 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: mitre 2 | Type: Package 3 | Title: Cybersecurity MITRE Standards Data and Digraphs 4 | Version: 1.0.0 5 | Authors@R: person("Humbert", "Costas", email = "humbert.costas@gmail.com", 6 | role = c("aut", "cre")) 7 | Maintainer: Humbert Costas 8 | Description: Extract, transform and load MITRE standards. 9 | This package gives you an approach to cybersecurity data sets. 10 | All data sets are build on runtime downloading raw data from MITRE public services. 11 | MITRE is a government-funded research organization 12 | based in Bedford and McLean. Current version includes most used standards as 13 | data frames. It also provide a list of nodes and edges with all relationships. 14 | License: CC0 15 | URL: https://github.com/motherhack3r/mitre 16 | BugReports: https://github.com/motherhack3r/mitre/issues 17 | Encoding: UTF-8 18 | LazyData: true 19 | LazyDataCompression: xz 20 | Imports: 21 | rlang, 22 | plyr, 23 | dplyr, 24 | igraph, 25 | stringr, 26 | jsonlite, 27 | RJSONIO, 28 | tidyr 29 | RoxygenNote: 7.1.1 30 | Suggests: 31 | rmarkdown, 32 | knitr, 33 | testthat (>= 3.0.0) 34 | VignetteBuilder: knitr 35 | Depends: 36 | R (>= 2.10) 37 | Config/testthat/edition: 3 38 | -------------------------------------------------------------------------------- /man/newEdge.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mitre.R 3 | \name{newEdge} 4 | \alias{newEdge} 5 | \title{Create an empty node} 6 | \usage{ 7 | newEdge() 8 | } 9 | \value{ 10 | data.frame 11 | } 12 | \description{ 13 | \code{from} : node id of edge start 14 | \code{to} : node id of edge end 15 | \code{from_std} : standard id of edge start 16 | \code{to_std} : standard id of edge end 17 | \code{title} : The title is shown in a pop-up when the mouse moves over the edge. 18 | \code{value} : When a value is set, the nodes will be scaled using the options in the scaling object defined above. 19 | \code{label} : The label of the edge. HTML does not work in here because the network uses HTML5 Canvas. 20 | \code{arrows} : To draw an arrow with default settings a string can be supplied. For example: 'to, from,middle' or 'to;from', any combination with any separating symbol is fine. If you want to control the size of the arrowheads, you can supply an object. 21 | \code{dashes} : When true, the edge will be drawn as a dashed line. 22 | \code{hidden} : When true, the node will not be shown. It will still be part of the physics simulation though! 23 | \code{color} : Color for the node. 24 | \code{hidden} : When true, the node will not be shown. It will still be part of the physics simulation though! 25 | } 26 | -------------------------------------------------------------------------------- /man/newNode.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mitre.R 3 | \name{newNode} 4 | \alias{newNode} 5 | \title{Create an empty node} 6 | \usage{ 7 | newNode() 8 | } 9 | \value{ 10 | data.frame 11 | } 12 | \description{ 13 | \code{id} : The id of the node unique value for all standard elements. 14 | \code{label} : The label is the piece of text shown in or under the node, depending on the shape. 15 | \code{group} : When not undefined, the group of node(s) 16 | \code{type} : Used as subgroup to classify different object from 17 | \code{value} : When a value is set, the nodes will be scaled using the options in the scaling object defined above. 18 | \code{title} : Title to be displayed when the user hovers over the node. The title can be an HTML element or a string containing plain text or HTML. 19 | \code{standard} : The id of the standard 20 | \code{shape} : The shape defines what the node looks like. The types with the label inside of it are: ellipse, circle, database, box, text. The ones with the label outside of it are: image, circularImage, diamond, dot, star, triangle, triangleDown, square and icon. 21 | \code{color} : Color for the node. 22 | \code{hidden} : When true, the node will not be shown. It will still be part of the physics simulation though! 23 | \code{mass} : Default to 1. The "barnesHut" physics model (which is enabled by default) is based on an inverted gravity model. By increasing the mass of a node, you increase it's repulsion. Values lower than 1 are not recommended. 24 | \code{description} : Description could include extra information or nested data which include other columns from original data frame observation. 25 | } 26 | -------------------------------------------------------------------------------- /data-raw/build_data.R: -------------------------------------------------------------------------------- 1 | # for(f in list.files(path = "data", pattern = "*.rda", full.names = T)) load(f) 2 | # rm(f) 3 | 4 | source("data-raw/mitre-cwe.R") 5 | source("data-raw/mitre-attck.R") 6 | source("data-raw/mitre-capec.R") 7 | source("data-raw/mitre-car.R") 8 | source("data-raw/mitre-shield.R") 9 | source("data-raw/nist-cpe.R") 10 | source("data-raw/nist-cve.R") 11 | 12 | # Build sample data sets 13 | # set.seed(42) 14 | # cpe.nist <- dplyr::sample_frac(cpe.nist, 0.0002) 15 | # cve.nist <- dplyr::sample_frac(cve.nist, 0.005) 16 | # cwe.weaknesses <- cwe.weaknesses[cwe.weaknesses$Status != "Deprecated", ] 17 | # cwe.weaknesses <- dplyr::sample_frac(cwe.weaknesses, 0.6) 18 | # cwe.categories <- cwe.weaknesses[cwe.categories$Status != "Deprecated", ] 19 | # cwe.categories <- dplyr::sample_frac(cwe.categories, 0.6) 20 | # capec.patterns <- dplyr::sample_frac(capec.patterns, 0.6) 21 | # attck.relations <- dplyr::sample_frac(attck.relations, 0.6) 22 | # attck.techniques <- dplyr::sample_frac(attck.techniques, 0.6) 23 | # attck.software <- dplyr::sample_frac(attck.software, 0.6) 24 | # car.analytics <- dplyr::sample_frac(car.analytics, 0.6) 25 | # car.model <- dplyr::sample_frac(car.model, 0.6) 26 | 27 | usethis::use_data(cve.nist, cpe.nist, cwe.views, cwe.categories, cwe.weaknesses, 28 | capec.views, capec.categories, capec.patterns, capec.relations, 29 | car.analytics, car.model, car.sensors, car.implementations, 30 | car.coverage, car.relations, shield.tactics, shield.techniques, 31 | shield.procedures, shield.use_cases, shield.opportunities, 32 | shield.relations, attck.tactics, attck.techniques, attck.mitigations, 33 | attck.groups, attck.software, attck.relations, 34 | compress = "xz", overwrite = TRUE, internal = TRUE) 35 | -------------------------------------------------------------------------------- /man/build_nodes.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mitre.R 3 | \name{build_nodes} 4 | \alias{build_nodes} 5 | \title{Transform all standards as nodes in a data frame.} 6 | \usage{ 7 | build_nodes(verbose = FALSE) 8 | } 9 | \arguments{ 10 | \item{verbose}{logical, FALSE by default. Change it to see the process messages.} 11 | } 12 | \value{ 13 | data.frame 14 | } 15 | \description{ 16 | \code{id} : The id of the node unique value for all standard elements. 17 | \code{label} : The label is the piece of text shown in or under the node, depending on the shape. 18 | \code{group} : When not undefined, the group of node(s) 19 | \code{type} : Used as subgroup to classify different object from 20 | \code{value} : When a value is set, the nodes will be scaled using the options in the scaling object defined above. 21 | \code{title} : Title to be displayed when the user hovers over the node. The title can be an HTML element or a string containing plain text or HTML. 22 | \code{standard} : The id of the standard 23 | \code{shape} : The shape defines what the node looks like. The types with the label inside of it are: ellipse, circle, database, box, text. The ones with the label outside of it are: image, circularImage, diamond, dot, star, triangle, triangleDown, square and icon. 24 | \code{color} : Color for the node. 25 | \code{hidden} : When true, the node will not be shown. It will still be part of the physics simulation though! 26 | \code{mass} : Default to 1. The barnesHut physics model (which is enabled by default) is based on an inverted gravity model. By increasing the mass of a node, you increase it's repulsion. Values lower than 1 are not recommended. 27 | \code{description} : Description could include extra information or nested data which include other columns from original data frame observation. 28 | } 29 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # mitre 1.0.0 2 | * Provide sample data sets pre-parsed using data-raw scripts 3 | * Included standards: CPE, CVE, CWE, CAPEC, CAR, ATT&CK and SHIELD 4 | * Public function to build a graph 5 | 6 | # mitre 0.6.0 7 | * Removed deprecated nodes in mitre network, kept in standards data frames 8 | * Raw data is downloaded from github repo to avoid official servers rate limitations 9 | * CPE source changed to JSON. It include more references to CVE. 10 | 11 | # mitre 0.5.2 12 | * New function as_igraph that transform mitre list of nodes and edges to igraph 13 | * Rscript to easy automate building latest data sets 14 | * CWE updated to parse v4.4 15 | * Added some unit tests for parsed data sets 16 | 17 | # mitre 0.5.1 18 | * Added network relations schema 19 | * Include CAR in network 20 | * Multiple network cleansing 21 | * Solved minor issues 22 | 23 | # mitre 0.5.0 24 | * Update documentation 25 | * Added vignettes 26 | 27 | # mitre 0.4.0 28 | * Removed missing columns 29 | * Filled missing values 30 | * Normalized network colors and groups 31 | 32 | # mitre 0.3.5 33 | * Network improvements in nodes populating missing data and some enrichment. 34 | 35 | # mitre 0.3.4 36 | * Code style 37 | * Update documentation for CRAN 38 | 39 | # mitre 0.3.3 40 | * New ATT&CK parser from latest definitions from official CTI repositories 41 | * Normalized network adding all standards 42 | * Improved nodes and edges details 43 | * Network include deprecated observations with shadow and dashes 44 | 45 | # mitre 0.3.2 46 | 47 | * Developing functions to explore MITRE network 48 | 49 | # mitre 0.3.1 50 | 51 | * Normalized network nodes and edges. 52 | * Added function to download latest tidy data sets. 53 | 54 | # mitre 0.3.0 55 | 56 | * Added CAR 57 | 58 | # mitre 0.2.0 59 | 60 | * Added ATT&CK, CVE, CPE, CWE and CAPEC 61 | 62 | # mitre 0.1.1 63 | 64 | * Added a `NEWS.md` file to track changes to the package. 65 | -------------------------------------------------------------------------------- /data-raw/nist-cpe.R: -------------------------------------------------------------------------------- 1 | if(any(grepl("package:RJSONIO", search()))) detach("package:RJSONIO") 2 | library(jsonlite) 3 | library(stringr) 4 | library(usethis) 5 | library(tidyr, warn.conflicts = FALSE) 6 | library(dplyr, warn.conflicts = FALSE) 7 | library(xml2) 8 | 9 | if (!dir.exists("data")) dir.create("data") 10 | 11 | # Download 12 | if (!file.exists("data-raw/nist-cpe.xml.zip")) 13 | download.file(url = "https://nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.3.xml.zip", 14 | destfile = "data-raw/cpe-nist.xml.zip") 15 | 16 | 17 | doc <- xml2::read_xml("data-raw/cpe-nist.xml.zip") 18 | 19 | cpes <- data.frame(title = xml2::xml_text(xml2::xml_find_all(doc, "//*[cpe-23:cpe23-item]/*[@xml:lang='en-US'][1]")), 20 | cpe.22 = xml2::xml_text(xml2::xml_find_all(doc, "//*[cpe-23:cpe23-item]/@name")), 21 | cpe.23 = xml2::xml_text(xml2::xml_find_all(doc, "//cpe-23:cpe23-item/@name")), 22 | stringsAsFactors = F) 23 | nodes <- xml2::xml_find_all(doc, ".//cpe-23:cpe23-item") 24 | 25 | cpes$refs <- unlist(lapply(xml2::xml_find_first(nodes, ".//ancestor::d1:cpe-item/d1:references"), 26 | function(x) { 27 | z <- lapply(xml2::as_list(x), function(y) as.character(attributes(y))) 28 | names(z) <- as.character(sapply(xml2::as_list(x), as.character)) 29 | jsonlite::toJSON(z, pretty = T) 30 | })) 31 | 32 | cpes$deprecated <- !is.na(as.logical(xml2::xml_attr(xml2::xml_find_first(nodes, 33 | ".//ancestor::d1:cpe-item"), 34 | "deprecated"))) 35 | 36 | new.cols <- c("std", "std.v", "part", "vendor", "product", 37 | "version", "update", "edition", "language", "sw_edition", 38 | "target_sw", "target_hw", "other") 39 | cpes$cpe.23 <- stringr::str_replace_all(cpes$cpe.23, "\\\\:", ";") 40 | cpes <- tidyr::separate(data = cpes, col = "cpe.23", into = new.cols, sep = ":", remove = F) 41 | cpes <- dplyr::select(.data = cpes, -"std", -"std.v") 42 | 43 | cpe.nist <- cpes 44 | 45 | usethis::use_data(cpe.nist, compress = "xz", overwrite = TRUE) 46 | 47 | rm(cpes, new.cols, doc, nodes) 48 | 49 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "man/figures/README-", 12 | out.width = "100%" 13 | ) 14 | ``` 15 | 16 | # mitre 17 | 18 | 19 | [![Travis build status](https://www.travis-ci.com/motherhack3r/mitre.svg?branch=master)](https://www.travis-ci.com/motherhack3r/mitre) 20 | [![CRAN status](https://www.r-pkg.org/badges/version/mitre)](https://cran.r-project.org/package=mitre) 21 | [![](https://cranlogs.r-pkg.org/badges/grand-total/mitre)](https://cran.r-project.org/package=mitre) 22 | [![](https://www.rdocumentation.org/badges/version/mitre)](https://www.rdocumentation.org/packages/mitre) 23 | 24 | 25 | mitre package is designed to provide easy access to cybersecurity data standards. 26 | You can expect sample data frames for every standard object. 27 | It provide a directed graph with all relationships for deep exploratory analysis. 28 | Using scripts in data-raw folder you can build the data sets using the latest 29 | public source files. 30 | 31 | ## Installation 32 | 33 | You can install the released version of mitre from [CRAN](https://CRAN.R-project.org) with: 34 | 35 | ``` r 36 | install.packages("mitre") 37 | ``` 38 | 39 | And the development version from [GitHub](https://github.com/) with: 40 | 41 | ``` r 42 | # install.packages("devtools") 43 | devtools::install_github("motherhack3r/mitre") 44 | ``` 45 | ## Explore cybersecurity standards 46 | 47 | This is a basic example which shows you how to view shield tactics ids and names: 48 | 49 | ```{r example} 50 | library(mitre) 51 | shield <- mitre::shield.tactics 52 | shield[, c("id", "name")] 53 | ``` 54 | 55 | This example shows the distribution of vulnerability risk: 56 | 57 | ```{r example2} 58 | hist(mitre::cve.nist$cvss3.score, 59 | main = "CVE risk distribution", xlab = "cvss3") 60 | ``` 61 | 62 | 63 | ## Standards network 64 | 65 | This code shows you the type of nodes for each standard: 66 | 67 | ```{r example3} 68 | mitrenet <- mitre::build_network(as_igraph = FALSE) 69 | table(mitrenet$nodes$type, mitrenet$nodes$group) 70 | ``` 71 | 72 | And the type of relationships: 73 | ```{r example4} 74 | table(mitrenet$edges$label) 75 | ``` 76 | 77 | 78 | ## Code of conduct 79 | 80 | Please note that this project is released with a [Contributor Code of Conduct](https://pkgdown.r-lib.org/CODE_OF_CONDUCT.html). By participating in this project you agree to abide by its terms. 81 | -------------------------------------------------------------------------------- /data-raw/nist-cve.R: -------------------------------------------------------------------------------- 1 | if(any(grepl("package:RJSONIO", search()))) detach("package:RJSONIO") 2 | library(jsonlite) 3 | library(usethis) 4 | library(dplyr, warn.conflicts = FALSE) 5 | 6 | if (!dir.exists("data")) dir.create("data") 7 | 8 | from_year <- 2002 9 | 10 | # Download Raw 11 | if (!as.logical(length(list.files(path = "data-raw", pattern = "^cve-\\d+\\.json.gz$")))) { 12 | for (year in 2002:strftime(Sys.Date(), "%Y")) { 13 | utils::download.file(url = paste0("https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-", year,".json.gz"), 14 | destfile = paste0("data-raw/cve-", year,".json.gz"), quiet = T) 15 | } 16 | } 17 | 18 | 19 | ##### 20 | # PARSER FUNCTIONS 21 | GetNISTvulnsByYear <- function(year = 2020, verbose = FALSE) { 22 | if (verbose) print(paste0("[PARSE][CVE] Parsing year ", year)) 23 | raw.cves <- jsonlite::fromJSON(paste0("data-raw/cve-", year,".json.gz")) 24 | 25 | raw.cves <- raw.cves$CVE_Items 26 | cves <- data.frame(cve.id = raw.cves$cve$CVE_data_meta$ID, 27 | stringsAsFactors = F) 28 | cves$description <- unlist(lapply(raw.cves$cve$description$description_data, 29 | function(x) x[["value"]][1])) 30 | cves$problem.type <- unlist(lapply(raw.cves$cve$problemtype$problemtype_data, 31 | function(x) 32 | jsonlite::toJSON(x[[1]][[1]]$value))) 33 | cves$vulnerable.configuration <- unlist(lapply(raw.cves$configurations$nodes, 34 | function(x) 35 | jsonlite::toJSON(x))) 36 | cves$references <- unlist(lapply(raw.cves$cve$references$reference_data, 37 | function(x) 38 | jsonlite::toJSON(x))) 39 | 40 | cves$cvss3.vector <- raw.cves$impact$baseMetricV3$cvssV3$vectorString 41 | cves$cvss3.score <- raw.cves$impact$baseMetricV3$cvssV3$baseScore 42 | cves$cvss3.severity <- raw.cves$impact$baseMetricV3$cvssV3$baseSeverity 43 | cves$cvss2.vector <- raw.cves$impact$baseMetricV2$cvssV2$vectorString 44 | cves$cvss2.score <- raw.cves$impact$baseMetricV2$cvssV2$baseScore 45 | cves$published.date <- raw.cves$publishedDate 46 | cves$last.modified <- raw.cves$lastModifiedDate 47 | 48 | if (verbose) print(paste0("[PARSE][CVE] ", nrow(cves)," vulnerabilities from year ", year)) 49 | return(cves) 50 | } 51 | 52 | NewNISTEntry <- function() { 53 | return(data.frame(cve.id = character(), 54 | # affects = character(), 55 | problem.type = character(), 56 | references = character(), 57 | description = character(), 58 | vulnerable.configuration = character(), 59 | cvss3.vector = character(), 60 | cvss3.score = numeric(), 61 | cvss3.severity = character(), 62 | cvss2.vector = character(), 63 | cvss2.score = numeric(), 64 | published.date = character(), 65 | last.modified = character(), 66 | stringsAsFactors = FALSE) 67 | ) 68 | } 69 | 70 | cves <- NewNISTEntry() 71 | for (year in from_year:strftime(Sys.Date(), "%Y")) { 72 | cves <- dplyr::bind_rows(cves, GetNISTvulnsByYear(year, T)) 73 | } 74 | cves$cvss3.severity <- as.factor(cves$cvss3.severity) 75 | cves$published.date <- as.POSIXct.POSIXlt(strptime(cves$published.date, "%Y-%m-%dT%H:%MZ")) 76 | cves$last.modified <- as.POSIXct.POSIXlt(strptime(cves$last.modified, "%Y-%m-%dT%H:%MZ")) 77 | 78 | cve.nist <- cves 79 | 80 | usethis::use_data(cve.nist, compress = "xz", overwrite = TRUE) 81 | 82 | rm(cves, year, from_year, GetNISTvulnsByYear, NewNISTEntry) 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # mitre 5 | 6 | 7 | 8 | [![Travis build 9 | status](https://www.travis-ci.com/motherhack3r/mitre.svg?branch=master)](https://www.travis-ci.com/motherhack3r/mitre) 10 | [![CRAN 11 | status](https://www.r-pkg.org/badges/version/mitre)](https://cran.r-project.org/package=mitre) 12 | [![](https://cranlogs.r-pkg.org/badges/grand-total/mitre)](https://cran.r-project.org/package=mitre) 13 | [![](https://www.rdocumentation.org/badges/version/mitre)](https://www.rdocumentation.org/packages/mitre) 14 | 15 | 16 | mitre package is designed to provide easy access to cybersecurity data 17 | standards. You can expect sample data frames for every standard object. 18 | It provide a directed graph with all relationships for deep exploratory 19 | analysis. Using scripts in data-raw folder you can build the data sets 20 | using the latest public source files. 21 | 22 | ## Installation 23 | 24 | You can install the released version of mitre from 25 | [CRAN](https://CRAN.R-project.org) with: 26 | 27 | ``` r 28 | install.packages("mitre") 29 | ``` 30 | 31 | And the development version from [GitHub](https://github.com/) with: 32 | 33 | ``` r 34 | # install.packages("devtools") 35 | devtools::install_github("motherhack3r/mitre") 36 | ``` 37 | 38 | ## Explore cybersecurity standards 39 | 40 | This is a basic example which shows you how to view shield tactics ids 41 | and names: 42 | 43 | ``` r 44 | library(mitre) 45 | shield <- mitre::shield.tactics 46 | shield[, c("id", "name")] 47 | #> id name 48 | #> 1 DTA0001 Channel 49 | #> 2 DTA0002 Collect 50 | #> 3 DTA0003 Contain 51 | #> 4 DTA0004 Detect 52 | #> 5 DTA0005 Disrupt 53 | #> 6 DTA0006 Facilitate 54 | #> 7 DTA0007 Legitimize 55 | #> 8 DTA0008 Test 56 | ``` 57 | 58 | This example shows the distribution of vulnerability risk: 59 | 60 | ``` r 61 | hist(mitre::cve.nist$cvss3.score, 62 | main = "CVE risk distribution", xlab = "cvss3") 63 | ``` 64 | 65 | 66 | 67 | ## Standards network 68 | 69 | This code shows you the type of nodes for each standard: 70 | 71 | ``` r 72 | mitrenet <- mitre::build_network(as_igraph = FALSE) 73 | table(mitrenet$nodes$type, mitrenet$nodes$group) 74 | #> 75 | #> attck capec car cpe cve cwe shield 76 | #> analytic 0 0 84 0 0 0 0 77 | #> category 0 1 0 0 0 319 0 78 | #> cpe 0 0 0 1369 0 0 0 79 | #> cve 0 0 0 0 4059 0 0 80 | #> data_model 0 0 33 0 0 0 0 81 | #> group 120 0 0 0 0 0 0 82 | #> mitigation 42 0 0 0 0 0 0 83 | #> opportunity 0 0 0 0 0 0 81 84 | #> pattern 0 525 0 0 0 0 0 85 | #> procedure 0 0 0 0 0 0 65 86 | #> software-malware 423 0 0 0 0 0 0 87 | #> software-tool 70 0 0 0 0 0 0 88 | #> tactic 14 0 0 0 0 0 8 89 | #> technique 552 0 0 0 0 0 33 90 | #> use_case 0 0 0 0 0 0 197 91 | #> view 0 0 0 0 0 28 0 92 | #> weakness 0 0 0 0 0 918 0 93 | ``` 94 | 95 | And the type of relationships: 96 | 97 | ``` r 98 | table(mitrenet$edges$label) 99 | #> 100 | #> ATTACK CanAlsoBe CanPrecede ChildOf 101 | #> 155 3 101 497 102 | #> cover defend has implement 103 | #> 528 258 108 219 104 | #> include is_vulnerable leverage mitigates 105 | #> 4817 1984 1245 1026 106 | #> PeerOf problem_type subtechnique-of take advantage of 107 | #> 10 3916 367 1178 108 | #> use uses 109 | #> 202 8758 110 | ``` 111 | 112 | ## Code of conduct 113 | 114 | Please note that this project is released with a [Contributor Code of 115 | Conduct](https://pkgdown.r-lib.org/CODE_OF_CONDUCT.html). By 116 | participating in this project you agree to abide by its terms. 117 | -------------------------------------------------------------------------------- /R/data.R: -------------------------------------------------------------------------------- 1 | NULL 2 | 3 | #' ATT&CK Groups Objects. 4 | #' 5 | #' Full data set provided by MITRE 6 | #' 7 | #' @format A data frame with 11 variables. 8 | "attck.groups" 9 | 10 | #' ATT&CK Mitigation Objects. 11 | #' 12 | #' Full data set provided by MITRE 13 | #' 14 | #' @format A data frame with 12 variables. 15 | "attck.mitigations" 16 | 17 | #' ATT&CK relations Objects. 18 | #' 19 | #' Full data set provided by MITRE 20 | #' 21 | #' @format A data frame with 13 variables. 22 | "attck.relations" 23 | 24 | #' ATT&CK software Objects. 25 | #' 26 | #' Full data set provided by MITRE 27 | #' 28 | #' @format A data frame with 12 variables. 29 | "attck.software" 30 | 31 | #' ATT&CK tactics Objects. 32 | #' 33 | #' Full data set provided by MITRE 34 | #' 35 | #' @format A data frame with 11 variables. 36 | "attck.tactics" 37 | 38 | #' ATT&CK techniques Objects. 39 | #' 40 | #' Full data set provided by MITRE 41 | #' 42 | #' @format A data frame with 15 variables. 43 | "attck.techniques" 44 | 45 | #' CAPEC categories Objects. 46 | #' 47 | #' Full data set provided by MITRE 48 | #' 49 | #' @format A data frame with 4 variables. 50 | "capec.categories" 51 | 52 | #' CAPEC views Objects. 53 | #' 54 | #' Full data set provided by MITRE 55 | #' 56 | #' @format A data frame with 5 variables. 57 | "capec.views" 58 | 59 | #' CAPEC patterns Objects. 60 | #' 61 | #' Full data set provided by MITRE 62 | #' 63 | #' @format A data frame with 16 variables. 64 | "capec.patterns" 65 | 66 | #' CAPEC relations Objects. 67 | #' 68 | #' Full data set provided by MITRE 69 | #' 70 | #' @format A data frame with 4 variables. 71 | "capec.relations" 72 | 73 | #' CAR analytics Objects. 74 | #' 75 | #' Full data set provided by MITRE 76 | #' 77 | #' @format A data frame with 17 variables. 78 | "car.analytics" 79 | 80 | #' CAR coverage Objects. 81 | #' 82 | #' Full data set provided by MITRE 83 | #' 84 | #' @format A data frame with 4 variables. 85 | "car.coverage" 86 | 87 | #' CAR implementations Objects. 88 | #' 89 | #' Full data set provided by MITRE 90 | #' 91 | #' @format A data frame with 7 variables. 92 | "car.implementations" 93 | 94 | #' CAR data model Objects. 95 | #' 96 | #' Full data set provided by MITRE 97 | #' 98 | #' @format A data frame with 8 variables. 99 | "car.model" 100 | 101 | #' CAR relations Objects. 102 | #' 103 | #' Full data set provided by MITRE 104 | #' 105 | #' @format A data frame with 2 variables. 106 | "car.relations" 107 | 108 | #' CAR sensors Objects. 109 | #' 110 | #' Full data set provided by MITRE 111 | #' 112 | #' @format A data frame with 5 variables. 113 | "car.sensors" 114 | 115 | #' Common Platform Enumeration. 116 | #' 117 | #' Full data set provided by NIST. 118 | #' 119 | #' @format A data frame with 16 variables: \code{title}, \code{cpe.22}, 120 | #' \code{cpe.23}, and all separated values. 121 | "cpe.nist" 122 | 123 | #' Common Vulnerability Enumeration. 124 | #' 125 | #' Full data set provided by NIST. 126 | #' 127 | #' @format A data frame with 34 variables: \code{cve.id}, \code{problem.type} which is related to CWE, 128 | #' \code{description}, \code{vulnerable.configuration} which is related to CPE, 129 | #' \code{references}, \code{cvss3}, \code{cvss2} and all separated values. 130 | "cve.nist" 131 | 132 | #' CWE categories Objects. 133 | #' 134 | #' Full data set provided by MITRE 135 | #' 136 | #' @format A data frame with 7 variables. 137 | "cwe.categories" 138 | 139 | #' CWE views Objects. 140 | #' 141 | #' Full data set provided by MITRE 142 | #' 143 | #' @format A data frame with 7 variables. 144 | "cwe.views" 145 | 146 | #' CWE Weaknesses Objects. 147 | #' 148 | #' Full data set provided by MITRE 149 | #' 150 | #' @format A data frame with 24 variables. 151 | "cwe.weaknesses" 152 | 153 | #' SHIELD tactics Objects. 154 | #' 155 | #' Full data set provided by MITRE 156 | #' 157 | #' @format A data frame with 4 variables. 158 | "shield.tactics" 159 | 160 | #' SHIELD techniques Objects. 161 | #' 162 | #' Full data set provided by MITRE 163 | #' 164 | #' @format A data frame with 4 variables. 165 | "shield.techniques" 166 | 167 | #' SHIELD opportunities Objects. 168 | #' 169 | #' Full data set provided by MITRE 170 | #' 171 | #' @format A data frame with 2 variables. 172 | "shield.opportunities" 173 | 174 | #' SHIELD procedures Objects. 175 | #' 176 | #' Full data set provided by MITRE 177 | #' 178 | #' @format A data frame with 2 variables. 179 | "shield.procedures" 180 | 181 | #' SHIELD relations Objects. 182 | #' 183 | #' Full data set provided by MITRE 184 | #' 185 | #' @format A data frame with 3 variables. 186 | "shield.relations" 187 | 188 | #' SHIELD use cases Objects. 189 | #' 190 | #' Full data set provided by MITRE 191 | #' 192 | #' @format A data frame with 2 variables. 193 | "shield.use_cases" 194 | 195 | 196 | -------------------------------------------------------------------------------- /data-raw/mitre-shield.R: -------------------------------------------------------------------------------- 1 | if(any(grepl("package:RJSONIO", search()))) detach("package:RJSONIO") else message("RJSONIO not loaded") 2 | library(jsonlite) 3 | library(usethis) 4 | if(any(grepl("package:dplyr", search()))) detach("package:dplyr") else message("dplyr not loaded") 5 | library(plyr, warn.conflicts = FALSE) 6 | library(dplyr, warn.conflicts = FALSE) 7 | 8 | if (!dir.exists("data")) dir.create("data") 9 | 10 | # Tactics 11 | if (!file.exists("data-raw/shield-tactics.json")) { 12 | download.file(url = "https://raw.githubusercontent.com/MITRECND/mitrecnd.github.io/master/_data/tactics.json", 13 | destfile = "data-raw/shield-tactics.json") 14 | } 15 | shield.tactics <- fromJSON("data-raw/shield-tactics.json") 16 | 17 | # Techniques 18 | if (!file.exists("data-raw/shield-techniques.json")) { 19 | download.file(url = "https://raw.githubusercontent.com/MITRECND/mitrecnd.github.io/master/_data/techniques.json", 20 | destfile = "data-raw/shield-techniques.json") 21 | } 22 | shield.techniques <- fromJSON("data-raw/shield-techniques.json") 23 | 24 | # Procedures 25 | if (!file.exists("data-raw/shield-procedures.json")) { 26 | download.file(url = "https://raw.githubusercontent.com/MITRECND/mitrecnd.github.io/master/_data/procedures.json", 27 | destfile = "data-raw/shield-procedures.json") 28 | } 29 | shield.procedures <- fromJSON("data-raw/shield-procedures.json") 30 | 31 | # Use Cases 32 | if (!file.exists("data-raw/shield-use_cases.json")) { 33 | download.file(url = "https://raw.githubusercontent.com/MITRECND/mitrecnd.github.io/master/_data/use_cases.json", 34 | destfile = "data-raw/shield-use_cases.json") 35 | } 36 | 37 | shield.use_cases <- fromJSON("data-raw/shield-use_cases.json") 38 | 39 | # Opportunities 40 | if (!file.exists("data-raw/shield-opportunities.json")) { 41 | download.file(url = "https://raw.githubusercontent.com/MITRECND/mitrecnd.github.io/master/_data/opportunities.json", 42 | destfile = "data-raw/shield-opportunities.json") 43 | } 44 | shield.opportunities <- fromJSON("data-raw/shield-opportunities.json") 45 | 46 | # Relations 47 | if (!file.exists("data-raw/shield-tactic_details.json")) { 48 | download.file(url = "https://raw.githubusercontent.com/MITRECND/mitrecnd.github.io/master/_data/tactic_details.json", 49 | destfile = "data-raw/shield-tactic_details.json") 50 | } 51 | 52 | if (!file.exists("data-raw/shield-technique_details.json")) { 53 | download.file(url = "https://raw.githubusercontent.com/MITRECND/mitrecnd.github.io/master/_data/technique_details.json", 54 | destfile = "data-raw/shield-technique_details.json") 55 | } 56 | 57 | 58 | tact_det <- fromJSON("data-raw/shield-tactic_details.json") 59 | tact_det <- ldply(tact_det, function(x) x[["techniques"]]) 60 | names(tact_det)[1:2] <- c("tact_id", "tech_id") 61 | tech_det <- fromJSON("data-raw/shield-technique_details.json") 62 | 63 | ## Shield Tactic --> Shield Technique 64 | relations <- tact_det %>% select(tact_id, tech_id) 65 | names(relations) <- c("from", "to") 66 | relations$name <- rep("leverage", nrow(relations)) 67 | 68 | ## Shield Technique --> ATT&CK Tactic 69 | df <- ldply(tech_det, function(x) data.frame(to = x[["attack_tactics"]][["id"]])) 70 | names(df) <- c("from", "to") 71 | df$name <- rep("cover", nrow(df)) 72 | relations <- bind_rows(relations, df) 73 | 74 | ## Shield Technique --> ATT&CK Techniques 75 | df <- ldply(tech_det, function(x) data.frame(to = x[["attack_techniques"]][["id"]])) 76 | names(df) <- c("from", "to") 77 | df$name <- rep("defend", nrow(df)) 78 | relations <- bind_rows(relations, df) 79 | 80 | ## Shield Technique --> Use Cases 81 | df <- ldply(tech_det, function(x) data.frame(to = x[["use_cases"]][["id"]])) 82 | names(df) <- c("from", "to") 83 | df$name <- rep("use", nrow(df)) 84 | relations <- bind_rows(relations, df) 85 | 86 | ## Shield Technique --> Opportunities 87 | df <- ldply(tech_det, function(x) data.frame(to = x[["opportunities"]][["id"]])) 88 | names(df) <- c("from", "to") 89 | df$name <- rep("has", nrow(df)) 90 | relations <- bind_rows(relations, df) 91 | 92 | ## Shield Technique --> Procedures 93 | df <- ldply(tech_det, function(x) data.frame(to = x[["procedures"]][["id"]])) 94 | names(df) <- c("from", "to") 95 | df$name <- rep("implement", nrow(df)) 96 | shield.relations <- bind_rows(relations, df) 97 | 98 | # Save raw files and data sets 99 | usethis::use_data(shield.tactics, compress = "xz", overwrite = TRUE) 100 | usethis::use_data(shield.techniques, compress = "xz", overwrite = TRUE) 101 | usethis::use_data(shield.procedures, compress = "xz", overwrite = TRUE) 102 | usethis::use_data(shield.use_cases, compress = "xz", overwrite = T) 103 | usethis::use_data(shield.opportunities, compress = "xz", overwrite = TRUE) 104 | usethis::use_data(shield.relations, compress = "xz", overwrite = TRUE) 105 | 106 | rm(df, relations, tact_det, tech_det) 107 | -------------------------------------------------------------------------------- /data-raw/mitre-attck.R: -------------------------------------------------------------------------------- 1 | if(any(grepl("package:RJSONIO", search()))) detach("package:RJSONIO") 2 | library(jsonlite) 3 | library(usethis) 4 | library(tidyr, warn.conflicts = FALSE) 5 | library(dplyr, warn.conflicts = FALSE) 6 | 7 | if (!dir.exists("data")) dir.create("data") 8 | 9 | # ATTACK ENTERPRISE 10 | # Ref: https://github.com/mitre/cti/blob/master/USAGE.md#the-attck-data-model 11 | 12 | # Tactics 13 | if (!file.exists("data-raw/attack-enterprise.json")) { 14 | download.file(url = "https://github.com/mitre/cti/raw/master/enterprise-attack/enterprise-attack.json", 15 | destfile = "data-raw/attack-enterprise.json") 16 | } 17 | attck.ent <- fromJSON("data-raw/attack-enterprise.json") 18 | 19 | 20 | ## Tactics (x-mitre-tactic) 21 | tact <- attck.ent$objects[attck.ent$objects$type == "x-mitre-tactic", ] 22 | tact <- tact[, apply(tact, 2, function(x) !all(is.na(x)))] 23 | tact <- tact[, apply(tact, 2, function(x) !is.null(unlist(x)))] 24 | attck.tactics <- bind_cols(bind_rows(tact$external_references), 25 | tact %>% select(-object_marking_refs, -external_references)) 26 | 27 | ## Techniques (attack-pattern) 28 | tech <- attck.ent$objects[attck.ent$objects$type == "attack-pattern", ] 29 | tech <- tech[, apply(tech, 2, function(x) !all(is.na(x)))] 30 | tech <- tech[, apply(tech, 2, function(x) !is.null(unlist(x)))] 31 | tech <- bind_cols(bind_rows(tech$external_references) %>% 32 | filter(source_name == "mitre-attack") %>% 33 | select(-description), 34 | tech %>% 35 | select(-kill_chain_phases, -x_mitre_platforms, 36 | -x_mitre_data_sources, 37 | -x_mitre_permissions_required, 38 | -x_mitre_effective_permissions, 39 | -x_mitre_defense_bypassed, -x_mitre_impact_type, 40 | -object_marking_refs, -external_references, 41 | -x_mitre_system_requirements, 42 | -x_mitre_contributors)) 43 | 44 | tech$revoked[is.na(tech$revoked)] <- FALSE 45 | tech$x_mitre_deprecated[is.na(tech$x_mitre_deprecated)] <- FALSE 46 | 47 | attck.techniques <- tech %>% 48 | filter(!revoked, !x_mitre_deprecated) %>% 49 | select(-revoked, -x_mitre_deprecated) 50 | 51 | ## Mitigation (course-of-action) 52 | miti <- attck.ent$objects[attck.ent$objects$type == "course-of-action", ] 53 | miti <- miti[, apply(miti, 2, function(x) !all(is.na(x)))] 54 | miti <- miti[, apply(miti, 2, function(x) !is.null(unlist(x)))] 55 | miti$x_mitre_deprecated[is.na(miti$x_mitre_deprecated)] <- FALSE 56 | miti <- miti %>% filter(!x_mitre_deprecated) %>% select(-x_mitre_deprecated) 57 | 58 | attck.mitigations <- bind_cols(bind_rows(miti$external_references), 59 | miti %>% select(-object_marking_refs, -external_references)) 60 | 61 | ## Group (intrusion-set) 62 | grup <- attck.ent$objects[attck.ent$objects$type == "intrusion-set", ] 63 | grup <- grup[, apply(grup, 2, function(x) !all(is.na(x)))] 64 | grup <- grup[, apply(grup, 2, function(x) !is.null(unlist(x)))] 65 | grup$revoked[is.na(grup$revoked)] <- FALSE 66 | grup <- grup %>% filter(!revoked) %>% select(-revoked) 67 | 68 | attck.groups <- bind_cols(bind_rows(grup$external_references) %>% 69 | filter(source_name == "mitre-attack") %>% 70 | select(-description), 71 | grup %>% select(-object_marking_refs, -external_references, 72 | -x_mitre_contributors, -aliases)) 73 | 74 | 75 | ## Software (malware, tool) 76 | soft <- attck.ent$objects[attck.ent$objects$type %in% c("malware", "tool"), ] 77 | soft <- soft[, apply(soft, 2, function(x) !all(is.na(x)))] 78 | soft <- soft[, apply(soft, 2, function(x) !is.null(unlist(x)))] 79 | soft$revoked[is.na(soft$revoked)] <- FALSE 80 | soft <- soft %>% filter(!revoked) %>% select(-revoked) 81 | soft$labels <- unlist(soft$labels) 82 | 83 | attck.software <- bind_cols(bind_rows(soft$external_references) %>% 84 | filter(source_name == "mitre-attack") %>% 85 | select(-description), 86 | soft %>% select(-x_mitre_platforms, -x_mitre_contributors, 87 | -object_marking_refs, -x_mitre_aliases, 88 | -external_references)) 89 | 90 | 91 | ## Relationship (relationship) 92 | rels <- attck.ent$objects[attck.ent$objects$type == "relationship", ] 93 | rels <- rels[, apply(rels, 2, function(x) !all(is.na(x)))] 94 | rels <- rels[, apply(rels, 2, function(x) !is.null(unlist(x)))] 95 | rels <- rels %>% 96 | separate(source_ref, c("source_type", "source_uuid"), "--", remove = F) %>% 97 | separate(target_ref, c("target_type", "target_uuid"), "--", remove = F) %>% 98 | select(-object_marking_refs, -external_references) %>% 99 | filter(relationship_type != "revoked-by") 100 | 101 | df <- bind_rows(attck.tactics %>% select(external_id, id), 102 | attck.techniques %>% select(external_id, id), 103 | attck.mitigations %>% select(external_id, id), 104 | attck.software %>% select(external_id, id), 105 | attck.groups %>% select(external_id, id)) 106 | 107 | rels <- dplyr::rename(left_join(rels, df, 108 | by = c("source_ref" = "id"), keep = F) , 109 | from = external_id) 110 | rels <- dplyr::rename(left_join(rels, df, 111 | by = c("target_ref" = "id"), keep = F) , 112 | to = external_id) 113 | 114 | attck.relations <- rels %>% 115 | filter(!is.na(from) & !is.na(to)) %>% 116 | select(-source_uuid, -target_uuid) 117 | 118 | 119 | usethis::use_data(attck.tactics, compress = "xz", overwrite = TRUE) 120 | usethis::use_data(attck.techniques, compress = "xz", overwrite = TRUE) 121 | usethis::use_data(attck.mitigations, compress = "xz", overwrite = TRUE) 122 | usethis::use_data(attck.groups, compress = "xz", overwrite = TRUE) 123 | usethis::use_data(attck.software, compress = "xz", overwrite = TRUE) 124 | usethis::use_data(attck.relations, compress = "xz", overwrite = TRUE) 125 | 126 | rm(attck.ent, grup, miti, rels, tact, tech, soft, df) 127 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ## creative commons 2 | 3 | # CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER. 6 | 7 | ### Statement of Purpose 8 | 9 | The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). 10 | 11 | Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. 12 | 13 | For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 14 | 15 | 1. __Copyright and Related Rights.__ A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: 16 | 17 | i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; 18 | 19 | ii. moral rights retained by the original author(s) and/or performer(s); 20 | 21 | iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; 22 | 23 | iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; 24 | 25 | v. rights protecting the extraction, dissemination, use and reuse of data in a Work; 26 | 27 | vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and 28 | 29 | vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 30 | 31 | 2. __Waiver.__ To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 32 | 33 | 3. __Public License Fallback.__ Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 34 | 35 | 4. __Limitations and Disclaimers.__ 36 | 37 | a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. 38 | 39 | b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. 40 | 41 | c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. 42 | 43 | d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. 44 | -------------------------------------------------------------------------------- /data-raw/mitre-car.R: -------------------------------------------------------------------------------- 1 | library(yaml) 2 | library(httr) 3 | library(usethis) 4 | if(any(grepl("package:dplyr", search()))) detach("package:dplyr") else message("dplyr not loaded") 5 | library(plyr, warn.conflicts = FALSE) 6 | library(tidyr, warn.conflicts = FALSE) 7 | library(dplyr, warn.conflicts = FALSE) 8 | 9 | if (!dir.exists("data")) dir.create("data") 10 | 11 | # Download 12 | if (length(list.files(path = "data-raw", pattern = "^car-.*\\.yaml$")) != 3) { 13 | req <- httr::GET("https://api.github.com/repos/mitre-attack/car/git/trees/master?recursive=1") 14 | httr::stop_for_status(req) 15 | filelist <- unlist(lapply(httr::content(req)$tree, "[", "path"), use.names = F) 16 | rm(req) 17 | 18 | raw.analytics <- suppressWarnings(lapply(paste0("https://raw.githubusercontent.com/mitre-attack/car/master/", 19 | grep("analytics/CAR.*yaml", filelist, 20 | value = TRUE, perl = TRUE)), 21 | yaml::read_yaml)) 22 | raw.model <- suppressWarnings(lapply(paste0("https://raw.githubusercontent.com/mitre-attack/car/master/", 23 | grep("data_model/.*yaml", filelist, 24 | value = TRUE, perl = TRUE)), 25 | yaml::read_yaml)) 26 | raw.sensors <- suppressWarnings(lapply(paste0("https://raw.githubusercontent.com/mitre-attack/car/master/", 27 | grep("^sensors/.*yaml$", filelist, 28 | value = TRUE, perl = TRUE)), 29 | yaml::read_yaml)) 30 | 31 | } 32 | 33 | ##### 34 | ## Analytics, Implementations and Coverage 35 | analytics <- lapply(raw.analytics, 36 | function(x) { 37 | x[["implementations"]] <- jsonlite::toJSON(x[["implementations"]]) 38 | x[["platforms"]] <- jsonlite::toJSON(x[["platforms"]]) 39 | x[["subtypes"]] <- jsonlite::toJSON(x[["subtypes"]]) 40 | x[["contributors"]] <- jsonlite::toJSON(x[["contributors"]]) 41 | x[["analytic_types"]] <- jsonlite::toJSON(x[["analytic_types"]]) 42 | x[["unit_tests"]] <- jsonlite::toJSON(x[["unit_tests"]]) 43 | x[["coverage"]] <- NULL 44 | x[["Coverage"]] <- NULL 45 | x[["references"]] <- jsonlite::toJSON(x[["references"]]) 46 | x[["true_positives"]] <- jsonlite::toJSON(x[["true_positives"]]) 47 | x[["data_model_references"]] <- NULL 48 | x 49 | }) 50 | analytics <- dplyr::bind_rows(analytics) 51 | analytics$submission_date <- as.Date(analytics$submission_date) 52 | analytics$subtypes <- as.character(analytics$subtypes) 53 | analytics$contributors <- as.character(analytics$contributors) 54 | analytics$unit_tests <- as.character(analytics$unit_tests) 55 | 56 | # Issue: https://github.com/mitre-attack/car/pull/120 57 | analytics$information_domain[analytics$id == "CAR-2013-07-005"] <- "Host" 58 | analytics$platforms[analytics$id == "CAR-2013-07-005"] <- '["Windows", "Linux", "macOS"]' 59 | 60 | # Remove near empty columns or nested 61 | analytics$references <- NULL 62 | analytics$true_positives <- NULL 63 | 64 | # uniq.infodom <- unique(stringr::str_trim(unlist(strsplit(analytics$information_domain, ",")))) 65 | analytics$domain_analytic <- grepl("Analytic", analytics$information_domain) 66 | analytics$domain_host <- grepl("Host", analytics$information_domain) 67 | analytics$domain_network <- grepl("Network", analytics$information_domain) 68 | analytics$information_domain <- NULL 69 | 70 | # uniq.platforms <- unique(unlist(sapply(analytics$platforms, function(x) jsonlite::fromJSON(x)))) 71 | analytics$platform_windows <- grepl("Windows", analytics$platforms) 72 | analytics$platform_linux <- grepl("Linux", analytics$platforms) 73 | analytics$platform_macos <- grepl("macOS", analytics$platforms) 74 | analytics$platforms <- NULL 75 | 76 | # uniq.types <- unique(unlist(sapply(analytics$analytic_types, function(x) jsonlite::fromJSON(x)))) 77 | analytics$type_ttp <- grepl("TTP", analytics$analytic_types) 78 | analytics$type_detection <- grepl("Detection", analytics$analytic_types) 79 | analytics$type_anomaly <- grepl("Anomaly", analytics$analytic_types) 80 | analytics$type_awareness <- grepl("Situational Awareness", analytics$analytic_types) 81 | analytics$analytic_types <- NULL 82 | 83 | uniq.subtypes <- unique(unlist(sapply(analytics$subtypes, function(x) jsonlite::fromJSON(x)))) 84 | 85 | # Analytics Implementations 86 | implementations <- lapply(analytics$implementations, function(x) jsonlite::fromJSON(x)) 87 | for (ca in which(sapply(implementations, length) == 0)) implementations[[ca]] <- data.frame(stringsAsFactors = F) 88 | names(implementations) <- analytics$id 89 | implementations <- dplyr::bind_rows(implementations, .id = "column_label") 90 | rm(ca) 91 | 92 | implementations$description[sapply(implementations$description, is.null)] <- "" 93 | implementations$code[sapply(implementations$code, is.null)] <- "" 94 | implementations$type[sapply(implementations$type, is.null)] <- "" 95 | implementations$data_model[sapply(implementations$data_model, is.null)] <- "" 96 | implementations$name[sapply(implementations$name, is.null)] <- "" 97 | implementations$data_mode[sapply(implementations$data_mode, is.null)] <- "" 98 | 99 | implementations$description <- unlist(implementations$description) 100 | implementations$code <- unlist(implementations$code) 101 | implementations$type <- unlist(implementations$type) 102 | implementations$data_model <- unlist(implementations$data_model) 103 | implementations$name <- unlist(implementations$name) 104 | implementations$data_mode <- unlist(implementations$data_mode) 105 | 106 | implementations <- dplyr::mutate(implementations, data_model = paste0(data_model, data_mode)) 107 | implementations$data_mode <- NULL 108 | implementations$id <- sapply(sample(100:999, nrow(implementations), replace=TRUE), 109 | function(x) paste0("CAR-IMPL-", x)) 110 | analytics$implementations <- NULL 111 | 112 | # Coverage relations 113 | coverage <- lapply(raw.analytics, function(x) x[["coverage"]]) 114 | names(coverage) <- analytics$id 115 | # Issue: https://github.com/mitre-attack/car/pull/119 116 | # coverage2 <- lapply(raw.analytics, function(x) x[["Coverage"]]) 117 | # names(coverage2) <- analytics$id 118 | 119 | covnet <- data.frame(from = character(), to = character(), coverage = character(), 120 | force = integer(), stringsAsFactors = F) 121 | for (i in 1:length(coverage)) { 122 | cx <- coverage[[i]] 123 | cx.id <- names(coverage)[i] 124 | if (is.null(cx)) next 125 | 126 | kk <- plyr::ldply(cx, function(y) { 127 | z <- data.frame(to = character(), coverage = character(), stringsAsFactors = F) 128 | if ("tactics" %in% names(y)) { 129 | k <- crossing(y[["tactics"]], y$coverage) 130 | names(k) <- c("to", "coverage") 131 | z <- z %>% bind_rows(z, k) 132 | } 133 | if ("technique" %in% names(y)) { 134 | k <- crossing(y[["technique"]], y$coverage) 135 | names(k) <- c("to", "coverage") 136 | z <- z %>% bind_rows(z, k) 137 | } 138 | if ("subtechniques" %in% names(y)) { 139 | k <- crossing(y[["subtechniques"]], y$coverage) 140 | names(k) <- c("to", "coverage") 141 | z <- z %>% bind_rows(z, k) 142 | } 143 | z 144 | }) 145 | kk$from <- rep(cx.id, nrow(kk)) 146 | kk <- kk %>% group_by(to, from, coverage) %>% summarise(.groups = "keep", force = n()) 147 | covnet <- dplyr::bind_rows(covnet, as.data.frame(kk)) 148 | rm(kk, cx, cx.id) 149 | } 150 | coverage <- covnet 151 | rm(covnet, i) 152 | 153 | ##### 154 | ## Data Model 155 | model <- plyr::ldply(raw.model, 156 | function(x) { 157 | actions <- plyr::ldply(x$actions, as.data.frame) 158 | fields <- plyr::ldply(x$fields, function(x) as.data.frame(x)) 159 | x$actions <- NULL 160 | x$fields <- NULL 161 | x <- dplyr::full_join(as.data.frame(x), actions, by = character()) 162 | x <- dplyr::full_join(x, fields, by = character()) 163 | names(x) <- c("name", "description", "action.name", 164 | "action.description", "field.name", 165 | "field.description", "field.example") 166 | x 167 | }) 168 | model$model.id <- apply(model, 1, function(x) paste0(x["name"], "/", x["action.name"], "/", x["field.name"])) 169 | model$model.id <- tolower(model$model.id) 170 | 171 | modelnet <- lapply(raw.analytics, function(x) x[["data_model_references"]]) 172 | names(modelnet) <- analytics$id 173 | 174 | modelnet <- plyr::ldply(modelnet, as.data.frame) 175 | names(modelnet) <- c("from", "to") 176 | 177 | ##### 178 | ## Sensors 179 | sensors <- plyr::ldply(raw.sensors, 180 | function(x) { 181 | x$mappings <- NULL 182 | x$other_coverage <- NULL 183 | as.data.frame(x) 184 | }) 185 | 186 | sensnet <- lapply(raw.sensors, function(x) x[["mappings"]]) 187 | names(sensnet) <- sensors$sensor_name 188 | 189 | sensnet <- plyr::ldply(sensnet, 190 | function(x) { 191 | mappings <- plyr::ldply(x, as.data.frame) 192 | mappings$notes <- NULL 193 | mappings$model.id <- apply(mappings, 1, 194 | function(x) 195 | paste0(x["object"], "/", x["action"], "/", x["fields"])) 196 | mappings$object <- NULL 197 | mappings$action <- NULL 198 | mappings$fields <- NULL 199 | mappings 200 | }) 201 | names(sensnet) <- c("to", "from") 202 | 203 | relations <- dplyr::bind_rows(modelnet, sensnet) 204 | 205 | ##### 206 | ## Save data sets 207 | car.analytics <- analytics 208 | car.model <- model 209 | car.sensors <- sensors 210 | car.implementations <- implementations 211 | car.coverage <- coverage 212 | car.relations <- relations 213 | 214 | usethis::use_data(car.analytics, compress = "xz", overwrite = TRUE) 215 | usethis::use_data(car.model, compress = "xz", overwrite = TRUE) 216 | usethis::use_data(car.sensors, compress = "xz", overwrite = TRUE) 217 | usethis::use_data(car.implementations, compress = "xz", overwrite = TRUE) 218 | usethis::use_data(car.coverage, compress = "xz", overwrite = TRUE) 219 | usethis::use_data(car.relations, compress = "xz", overwrite = TRUE) 220 | 221 | rm(modelnet, sensnet, model, sensors, analytics, relations, implementations, 222 | raw.analytics, raw.model, raw.sensors, filelist, coverage, uniq.subtypes) 223 | -------------------------------------------------------------------------------- /data-raw/mitre-capec.R: -------------------------------------------------------------------------------- 1 | library(xml2) 2 | library(rvest) 3 | library(stringr) 4 | library(dplyr, warn.conflicts = FALSE) 5 | 6 | # CAPEC 7 | # Ref: https://capec.mitre.org/data/index.html 8 | 9 | if (!file.exists("data-raw/capec_latest.zip")) 10 | download.file(url = "https://capec.mitre.org/data/archive/capec_latest.zip", 11 | destfile = "data-raw/capec_latest.xml.zip") 12 | doc <- read_xml("data-raw/capec_latest.xml.zip") 13 | 14 | # CAPEC VIEWs 15 | views <- 16 | data.frame(id = doc %>% html_elements(xpath = "//capec:View/@ID") %>% html_text(), 17 | name = doc %>% html_elements(xpath = "//capec:View/@Name") %>% html_text(), 18 | type = doc %>% html_elements(xpath = "//capec:View/@Type") %>% html_text(), 19 | status = doc %>% html_elements(xpath = "//capec:View/@Status") %>% html_text(), 20 | description = doc %>% html_elements(xpath = "//capec:View/capec:Objective") %>% html_text(), 21 | stringsAsFactors = FALSE) 22 | 23 | views$id <- paste0("CAPEC-", views$id) 24 | 25 | # CAPEC CATEGORIES 26 | categories <- 27 | data.frame(id = doc %>% html_elements(xpath = "//capec:Category/@ID") %>% html_text(), 28 | name = doc %>% html_elements(xpath = "//capec:Category/@Name") %>% html_text(), 29 | status = doc %>% html_elements(xpath = "//capec:Category/@Status") %>% html_text(), 30 | description = doc %>% html_elements(xpath = "//capec:Category/capec:Summary") %>% html_text(), 31 | stringsAsFactors = FALSE) 32 | categories$id <- paste0("CAPEC-", categories$id) 33 | 34 | 35 | df <- rvest::html_elements(doc, xpath = "//capec:Category") 36 | df <- lapply(df, 37 | function(x) { 38 | kl <- rvest::html_elements(x, xpath = "capec:Taxonomy_Mappings/capec:Taxonomy_Mapping") 39 | k<-lapply(kl, 40 | function(y) { 41 | eids <- xml2::xml_text(rvest::html_elements(y, xpath="capec:Entry_ID")) 42 | enam <- xml2::xml_text(rvest::html_elements(y,xpath="capec:Entry_Name")) 43 | data.frame(taxonomy_id=ifelse(identical(eids, character(0)), NA, eids), 44 | taxonomy_name=ifelse(identical(enam, character(0)), NA, enam), 45 | stringsAsFactors = FALSE) 46 | }) 47 | names(k) <- xml2::xml_attr(kl, "Taxonomy_Name") 48 | c2t <- dplyr::bind_rows(k, .id = "taxonomy") 49 | c2t 50 | }) 51 | names(df) <- categories$id 52 | df <- dplyr::bind_rows(df, .id = "from") 53 | selected <- which(df$taxonomy == "ATTACK") 54 | df$taxonomy_id[selected] <- paste0("T", df$taxonomy_id[selected]) 55 | selected <- which(df$taxonomy == "WASC") 56 | df$taxonomy_id[selected] <- paste0("WASC-", df$taxonomy_id[selected]) 57 | selected <- which(df$taxonomy == "OWASP Attacks") 58 | df$taxonomy_id[selected] <- paste0("OWASP-", df$taxonomy_name[selected]) 59 | names(df) <- c("from", "name", "to", "title") 60 | capec.relations <- df 61 | 62 | # CAPEC ATTACK PATTERNs 63 | capec.atcks <- rvest::html_elements(doc, xpath = "//capec:Attack_Pattern") 64 | att.id <- paste0("CAPEC-", sapply(capec.atcks, 65 | function(x) 66 | rvest::html_text(rvest::html_element(x, xpath="./@ID")))) 67 | att.name <- sapply(capec.atcks, 68 | function(x) 69 | rvest::html_text(rvest::html_element(x, xpath="./@Name"))) 70 | att.status <- sapply(capec.atcks, 71 | function(x) 72 | rvest::html_text(rvest::html_element(x, xpath="./@Status"))) 73 | att.abstraction <- sapply(capec.atcks, 74 | function(x) 75 | rvest::html_text(rvest::html_element(x, xpath="./@Abstraction"))) 76 | att.descr <- sapply(capec.atcks, 77 | function(x) 78 | rvest::html_text(rvest::html_elements(x, xpath = "capec:Description"))) 79 | 80 | df <- lapply(capec.atcks, 81 | function(x) { 82 | data.frame(id = rvest::html_text(rvest::html_elements(x, xpath=".//capec:Related_Attack_Pattern/@CAPEC_ID")), 83 | nature = rvest::html_text(rvest::html_elements(x, xpath=".//capec:Related_Attack_Pattern/@Nature")), 84 | stringsAsFactors = F) 85 | }) 86 | names(df) <- att.id 87 | df <- dplyr::bind_rows(df, .id = "from") 88 | names(df) <- c("from", "to", "name") 89 | df$to <- paste0("CAPEC-", df$to) 90 | df$title <- df$name 91 | 92 | capec.relations <- dplyr::bind_rows(capec.relations, df) 93 | 94 | att.prerequisites <- sapply(capec.atcks, 95 | function(x) 96 | jsonlite::toJSON(rvest::html_text(rvest::html_elements(x, xpath = "capec:Prerequisites/capec:Prerequisite")))) 97 | 98 | att.alernate_terms <- sapply(capec.atcks, 99 | function(x) 100 | jsonlite::toJSON(rvest::html_text(rvest::html_elements(x, xpath = "capec:Alternate_Terms/capec:Alternate_Term/capec:Term")))) 101 | 102 | 103 | att.severity <- sapply(capec.atcks, 104 | function(x) { 105 | ifelse(test = identical(rvest::html_text(rvest::html_nodes(x, xpath = "capec:Typical_Severity")), character(0)), 106 | yes = "Unknown", 107 | no = rvest::html_text(rvest::html_nodes(x, xpath = "capec:Typical_Severity")))}) 108 | 109 | att.likelihoodatt <- sapply(capec.atcks, 110 | function(x) { 111 | ifelse(test = identical(rvest::html_text(rvest::html_nodes(x, xpath = "capec:Likelihood_Of_Attack")), character(0)), 112 | yes = "Unknown", 113 | no = rvest::html_text(rvest::html_nodes(x, xpath = "capec:Likelihood_Of_Attack")))}) 114 | 115 | att.flow <- sapply(capec.atcks, 116 | function(x) { 117 | k <- rvest::html_nodes(x, xpath = "capec:Execution_Flow") 118 | k <- lapply(xml2::xml_children(k), xml2::as_list) 119 | jsonlite::toJSON(k, pretty = T) 120 | }) 121 | 122 | att.skills <- sapply(capec.atcks, 123 | function(x) { 124 | jsonlite::toJSON(data.frame( 125 | skilled = sapply(rvest::html_nodes(x, xpath = "capec:Skills_Required/capec:Skill/@Level"), 126 | xml2::xml_text), 127 | skill = sapply(rvest::html_nodes(x, xpath = "capec:Skills_Required/capec:Skill"), 128 | xml2::xml_text), stringsAsFactors = FALSE)) 129 | }) 130 | 131 | att.reqsrcs <- sapply(capec.atcks, 132 | function(x) 133 | jsonlite::toJSON(rvest::html_text(rvest::html_elements(x, xpath = "capec:Resources_Required/capec:Resource")))) 134 | 135 | att.indicators <- sapply(capec.atcks, 136 | function(x) 137 | jsonlite::toJSON(rvest::html_text(rvest::html_elements(x, xpath = "capec:Indicators/capec:Indicator")))) 138 | 139 | att.consequences <- sapply(capec.atcks, 140 | function(x) { 141 | cons <- rvest::html_nodes(x, xpath = "capec:Consequences/capec:Consequence") 142 | csq <- lapply(cons, function(y) { 143 | data.frame(name = sapply(xml2::xml_children(y), xml2::xml_name), 144 | value = sapply(xml2::xml_children(y), xml2::xml_text), 145 | stringsAsFactors = FALSE) 146 | }) 147 | names(csq) <- sapply(cons, xml2::xml_name) 148 | jsonlite::toJSON(csq, pretty = T) 149 | }) 150 | 151 | att.mitigations <- sapply(capec.atcks, 152 | function(x) 153 | jsonlite::toJSON(rvest::html_text(rvest::html_elements(x, xpath = "capec:Mitigations/capec:Mitigation")))) 154 | 155 | att.examples <- sapply(capec.atcks, 156 | function(x) 157 | jsonlite::toJSON(rvest::html_text(rvest::html_elements(x, xpath = "capec:Example_Instances/capec:Example")))) 158 | 159 | df <- lapply(att.examples, 160 | function(x) 161 | data.frame(to = stringr::str_extract_all(x, "CVE-\\d+-\\d+")[[1]], 162 | stringsAsFactors = FALSE)) 163 | names(df) <- att.id 164 | df <- dplyr::bind_rows(df, .id = "from") 165 | df$name <- rep("example", nrow(df)) 166 | df$title <- df$name 167 | capec.relations <- rbind(capec.relations, df) 168 | 169 | df <- lapply(capec.atcks, 170 | function(x) 171 | # XXX: Sometimes xml is empty 172 | data.frame(to = paste0("CWE-", xml2::xml_text(rvest::html_elements(x, xpath = "capec:Related_Weaknesses/capec:Related_Weakness/@CWE_ID"))), 173 | stringsAsFactors = FALSE)) 174 | names(df) <- att.id 175 | df <- dplyr::bind_rows(df, .id = "from") 176 | df$name <- rep("take advantage of", nrow(df)) 177 | df$title <- df$name 178 | capec.relations <- rbind(capec.relations, df) 179 | 180 | 181 | df <- lapply(capec.atcks, 182 | function(x) { 183 | kl <- rvest::html_elements(x, xpath = "capec:Taxonomy_Mappings/capec:Taxonomy_Mapping") 184 | k<-lapply(kl, 185 | function(y) { 186 | eids <- xml2::xml_text(rvest::html_elements(y, xpath="capec:Entry_ID")) 187 | enam <- xml2::xml_text(rvest::html_elements(y,xpath="capec:Entry_Name")) 188 | data.frame(taxonomy_id=ifelse(identical(eids, character(0)), NA, eids), 189 | taxonomy_name=ifelse(identical(enam, character(0)), NA, enam), 190 | stringsAsFactors = FALSE) 191 | }) 192 | names(k) <- xml2::xml_attr(kl, "Taxonomy_Name") 193 | c2t <- dplyr::bind_rows(k, .id = "taxonomy") 194 | c2t 195 | }) 196 | names(df) <- att.id 197 | df <- dplyr::bind_rows(df, .id = "from") 198 | selected <- which(df$taxonomy == "ATTACK") 199 | df$taxonomy_id[selected] <- paste0("T", df$taxonomy_id[selected]) 200 | selected <- which(df$taxonomy == "WASC") 201 | df$taxonomy_id[selected] <- paste0("WASC-", df$taxonomy_id[selected]) 202 | selected <- which(df$taxonomy == "OWASP Attacks") 203 | df$taxonomy_id[selected] <- paste0("OWASP-", df$taxonomy_name[selected]) 204 | names(df) <- c("from", "name", "to", "title") 205 | 206 | capec.relations <- dplyr::bind_rows(capec.relations, df) 207 | 208 | capec.patterns <- data.frame(id = att.id, 209 | name = att.name, 210 | abstraction = att.abstraction, 211 | status = att.status, 212 | description = att.descr, 213 | alternate_terms = att.alernate_terms, 214 | likelihood = att.likelihoodatt, 215 | severity = att.severity, 216 | execution_flow = att.flow, 217 | prerequisites = att.prerequisites, 218 | skills = att.skills, 219 | resources = att.reqsrcs, 220 | indicators = att.indicators, 221 | consequences = att.consequences, 222 | mitigations = att.mitigations, 223 | examples = att.examples, 224 | stringsAsFactors = FALSE) 225 | 226 | capec.categories <- categories 227 | capec.views <- views 228 | 229 | 230 | usethis::use_data(capec.views, compress = "xz", overwrite = TRUE) 231 | usethis::use_data(capec.categories, compress = "xz", overwrite = TRUE) 232 | usethis::use_data(capec.patterns, compress = "xz", overwrite = TRUE) 233 | usethis::use_data(capec.relations, compress = "xz", overwrite = TRUE) 234 | 235 | 236 | rm(views, categories, selected, att.abstraction, att.alernate_terms, att.consequences, 237 | att.descr, att.examples, att.flow, att.id, att.indicators, att.likelihoodatt, 238 | att.mitigations, att.name, att.prerequisites, att.reqsrcs, att.severity, att.skills, 239 | att.status, capec.atcks, df, doc) 240 | -------------------------------------------------------------------------------- /data-raw/mitre-cwe.R: -------------------------------------------------------------------------------- 1 | library(usethis) 2 | library(dplyr, warn.conflicts = FALSE) 3 | library(rvest, warn.conflicts = FALSE) 4 | library(xml2, warn.conflicts = FALSE) 5 | if(any(grepl("package:jsonlite", search()))) detach("package:jsonlite") # else message("jsonlite not loaded") 6 | library(RJSONIO, warn.conflicts = FALSE) 7 | 8 | if (!dir.exists("data")) dir.create("data") 9 | 10 | # Latest XML definition 11 | cwes.file <- "data-raw/cwe-latest.xml.zip" 12 | if (!file.exists(cwes.file)) { 13 | download.file(url = "http://cwe.mitre.org/data/xml/cwec_latest.xml.zip", 14 | destfile = cwes.file) 15 | } 16 | 17 | ##### 18 | # PARSE WEAKNESSES 19 | # 20 | doc <- read_html(cwes.file) 21 | raw.cwes <- html_nodes(doc, "weakness") 22 | # Extract Weakness node attributes 23 | cwes <- as.data.frame(t(sapply(raw.cwes, rvest::html_attrs)), stringsAsFactors = F) 24 | names(cwes) <- c("ID", "Name", "Abstraction", "Structure", "Status") 25 | cwes$CWE_Type <- rep("Weakness", nrow(cwes)) 26 | # Set factors (improve setting levels according to XSD) 27 | cwes$Abstraction <- as.factor(cwes$Abstraction) 28 | cwes$Structure <- as.factor(cwes$Structure) 29 | # Add extra field with code standard 30 | cwes$Code_Standard <- paste("CWE-", cwes$ID, sep = "") 31 | 32 | cwes$Description <- sapply(rvest::html_nodes(doc, xpath = "//weakness/description"), 33 | rvest::html_text) 34 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//weakness/extended_description/parent::*/@id")) 35 | vals <- sapply(xml2::xml_find_all(doc, "//weakness/extended_description"), xml2::xml_text) 36 | df <- data.frame(ID = ids, Extended_Description = vals, stringsAsFactors = F) 37 | cwes <- dplyr::left_join(cwes, df, by = c("ID")) 38 | 39 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//weakness/related_weaknesses/parent::*/@id")) 40 | vals <- sapply(xml2::xml_find_all(doc, "//weakness/related_weaknesses"), 41 | function(x) RJSONIO::toJSON(lapply(rvest::html_children(x), 42 | rvest::html_attrs), 43 | pretty = T)) 44 | df <- data.frame(ID = ids, Related_Weakness = vals, stringsAsFactors = F) 45 | cwes <- dplyr::left_join(cwes, df, by = c("ID")) 46 | 47 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//weakness/weakness_ordinalities/parent::*/@id")) 48 | vals <- sapply(xml2::xml_find_all(doc, "//weakness/weakness_ordinalities"), 49 | function(x) RJSONIO::toJSON(lapply(rvest::html_children(x), 50 | function(x) rvest::html_text(rvest::html_children(x))), 51 | pretty = T)) 52 | df <- data.frame(ID = ids, Weakness_Ordinality = vals, stringsAsFactors = F) 53 | cwes <- dplyr::left_join(cwes, df, by = c("ID")) 54 | 55 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//weakness/applicable_platforms/parent::*/@id")) 56 | vals <- sapply(xml2::xml_find_all(doc, "//weakness/applicable_platforms"), 57 | function(x) { 58 | y <- lapply(rvest::html_children(x), rvest::html_attrs) 59 | names(y) <- rvest::html_name(rvest::html_children(x)) 60 | RJSONIO::toJSON(y, pretty = T) 61 | }) 62 | df <- data.frame(ID = ids, Applicable_Platforms = vals, stringsAsFactors = F) 63 | cwes <- dplyr::left_join(cwes, df, by = c("ID")) 64 | 65 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//weakness/background_details/parent::*/@id")) 66 | vals <- sapply(xml2::xml_find_all(doc, "//weakness/background_details"), 67 | function(x) RJSONIO::toJSON(xml2::xml_text(x), 68 | pretty = T)) 69 | df <- data.frame(ID = ids, Background_Details = vals, stringsAsFactors = F) 70 | cwes <- dplyr::left_join(cwes, df, by = c("ID")) 71 | 72 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//weakness/alternate_terms/parent::*/@id")) 73 | vals <- sapply(xml2::xml_find_all(doc, "//weakness/alternate_terms"), 74 | function(x) RJSONIO::toJSON(lapply(rvest::html_children(x), 75 | rvest::html_text), 76 | pretty = T)) 77 | df <- data.frame(ID = ids, Alternate_Terms = vals, stringsAsFactors = F) 78 | cwes <- dplyr::left_join(cwes, df, by = c("ID")) 79 | 80 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//weakness/modes_of_introduction/parent::*/@id")) 81 | vals <- sapply(xml2::xml_find_all(doc, "//weakness/modes_of_introduction"), 82 | function(x) 83 | RJSONIO::toJSON(lapply(lapply(rvest::html_children(x), 84 | function(x) rvest::html_children(x)), 85 | function(y) { 86 | z <- rvest::html_text(y) 87 | names(z) <- rvest::html_name(y) 88 | z 89 | }), 90 | pretty = T)) 91 | df <- data.frame(ID = ids, Modes_Of_Introduction = vals, stringsAsFactors = F) 92 | cwes <- dplyr::left_join(cwes, df, by = c("ID")) 93 | 94 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//weakness/likelihood_of_exploit/parent::*/@id")) 95 | vals <- sapply(xml2::xml_find_all(doc, "//weakness/likelihood_of_exploit"), rvest::html_text) 96 | df <- data.frame(ID = ids, Likelihood_Of_Exploit = vals, stringsAsFactors = F) 97 | cwes <- dplyr::left_join(cwes, df, by = c("ID")) 98 | cwes$Likelihood_Of_Exploit <- as.factor(cwes$Likelihood_Of_Exploit) 99 | 100 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//weakness/common_consequences/parent::*/@id")) 101 | vals <- sapply(xml2::xml_find_all(doc, "//weakness/common_consequences"), 102 | function(x) RJSONIO::toJSON(lapply( 103 | lapply(rvest::html_children(x), 104 | function(x) rvest::html_children(x)), 105 | function(y) { 106 | z <- rvest::html_text(y) 107 | names(z) <- rvest::html_name(y) 108 | z 109 | } 110 | ), 111 | pretty = T)) 112 | df <- data.frame(ID = ids, Common_Consequences = vals, stringsAsFactors = F) 113 | cwes <- dplyr::left_join(cwes, df, by = c("ID")) 114 | 115 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//weakness/detection_methods/parent::*/@id")) 116 | vals <- sapply(xml2::xml_find_all(doc, "//weakness/detection_methods"), 117 | function(x) RJSONIO::toJSON(lapply( 118 | lapply(rvest::html_children(x), 119 | function(x) rvest::html_children(x)), 120 | function(y) { 121 | z <- rvest::html_text(y) 122 | names(z) <- rvest::html_name(y) 123 | z 124 | } 125 | ), 126 | pretty = T)) 127 | df <- data.frame(ID = ids, Detection_Methods = vals, stringsAsFactors = F) 128 | cwes <- dplyr::left_join(cwes, df, by = c("ID")) 129 | 130 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//weakness/potential_mitigations/parent::*/@id")) 131 | vals <- sapply(xml2::xml_find_all(doc, "//weakness/potential_mitigations"), 132 | function(x) RJSONIO::toJSON(lapply( 133 | lapply(rvest::html_children(x), 134 | function(x) rvest::html_children(x)), 135 | function(y) { 136 | z <- rvest::html_text(y) 137 | names(z) <- rvest::html_name(y) 138 | z 139 | } 140 | ), 141 | pretty = T)) 142 | df <- data.frame(ID = ids, Potential_Mitigations = vals, stringsAsFactors = F) 143 | cwes <- dplyr::left_join(cwes, df, by = c("ID")) 144 | 145 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//weakness/observed_examples/parent::*/@id")) 146 | vals <- sapply(xml2::xml_find_all(doc, "//weakness/observed_examples"), 147 | function(x) RJSONIO::toJSON(lapply( 148 | lapply(rvest::html_children(x), 149 | function(x) rvest::html_children(x)), 150 | function(y) { 151 | z <- rvest::html_text(y) 152 | names(z) <- rvest::html_name(y) 153 | z 154 | } 155 | ), 156 | pretty = T)) 157 | df <- data.frame(ID = ids, Observed_Examples = vals, stringsAsFactors = F) 158 | cwes <- dplyr::left_join(cwes, df, by = c("ID")) 159 | 160 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//weakness/functional_areas/parent::*/@id")) 161 | vals <- sapply(xml2::xml_find_all(doc, "//weakness/functional_areas"), 162 | function(x) RJSONIO::toJSON(sapply(rvest::html_children(x), rvest::html_text))) 163 | df <- data.frame(ID = ids, Functional_Areas = vals, stringsAsFactors = F) 164 | cwes <- dplyr::left_join(cwes, df, by = c("ID")) 165 | 166 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//weakness/affected_resources/parent::*/@id")) 167 | vals <- sapply(xml2::xml_find_all(doc, "//weakness/affected_resources"), 168 | function(x) RJSONIO::toJSON(sapply(rvest::html_children(x), rvest::html_text))) 169 | df <- data.frame(ID = ids, Affected_Resources = vals, stringsAsFactors = F) 170 | cwes <- dplyr::left_join(cwes, df, by = c("ID")) 171 | 172 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//weakness/taxonomy_mappings/parent::*/@id")) 173 | vals <- sapply(xml2::xml_find_all(doc, "//weakness/taxonomy_mappings"), 174 | function(x) RJSONIO::toJSON({w <- lapply( 175 | lapply(rvest::html_children(x), 176 | function(x) rvest::html_children(x)), 177 | function(y) { 178 | z <- rvest::html_text(y) 179 | names(z) <- rvest::html_name(y) 180 | z 181 | }) 182 | names(w) <- unlist(rvest::html_attrs(rvest::html_children(x))) 183 | w}, pretty = T)) 184 | df <- data.frame(ID = ids, Taxonomy_Mappings = vals, stringsAsFactors = F) 185 | cwes <- dplyr::left_join(cwes, df, by = c("ID")) 186 | 187 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//weakness/related_attack_patterns/parent::*/@id")) 188 | vals <- sapply(xml2::xml_find_all(doc, "//weakness/related_attack_patterns"), 189 | function(x) RJSONIO::toJSON(sapply(rvest::html_children(x), rvest::html_attrs))) 190 | df <- data.frame(ID = ids, Related_Attack_Patterns = vals, stringsAsFactors = F) 191 | cwes <- dplyr::left_join(cwes, df, by = c("ID")) 192 | 193 | cwe.weaknesses <- cwes 194 | usethis::use_data(cwe.weaknesses, compress = "xz", overwrite = TRUE) 195 | 196 | 197 | ##### 198 | # PARSE CATEGORIES 199 | 200 | raw.cwes <- rvest::html_nodes(doc, "category") 201 | cwes <- as.data.frame(t(sapply(raw.cwes, rvest::html_attrs)), stringsAsFactors = F) 202 | names(cwes) <- c("ID", "Name", "Status") 203 | cwes$CWE_Type <- rep("Category", nrow(cwes)) 204 | cwes$Code_Standard <- paste("CWE-", cwes$ID, sep = "") 205 | 206 | cwes$Description <- sapply(rvest::html_nodes(doc, xpath = "//category/summary"), 207 | rvest::html_text) 208 | 209 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//category/relationships/parent::*/@id")) 210 | vals <- sapply(xml2::xml_find_all(doc, "//category/relationships"), 211 | function(x) { 212 | members <- rvest::html_attrs(rvest::html_children(x)) 213 | names(members) <- rvest::html_name(rvest::html_children(x)) 214 | RJSONIO::toJSON(members, pretty = T) 215 | } 216 | ) 217 | df <- data.frame(ID = ids, Related_Weakness = vals, stringsAsFactors = F) 218 | cwe.categories <- dplyr::left_join(cwes, df, by = c("ID")) 219 | usethis::use_data(cwe.categories, compress = "xz", overwrite = TRUE) 220 | 221 | 222 | ##### 223 | # PARSE VIEWS 224 | 225 | raw.cwes <- rvest::html_nodes(doc, "view") 226 | cwes <- as.data.frame(t(sapply(raw.cwes, rvest::html_attrs)), stringsAsFactors = F) 227 | # View attribute "Type" overwriten with character "View" 228 | names(cwes) <- c("ID", "Name", "CWE_Type", "Status") 229 | cwes$CWE_Type <- rep("View", nrow(cwes)) 230 | cwes$Code_Standard <- paste("CWE-", cwes$ID, sep = "") 231 | cwes$Description <- sapply(rvest::html_nodes(doc, xpath = "//view/objective"), 232 | rvest::html_text) 233 | ids <- xml2::xml_text(xml2::xml_find_all(doc, "//view/members/parent::*/@id")) 234 | vals <- sapply(xml2::xml_find_all(doc, "//view/members"), 235 | function(x) { 236 | members <- rvest::html_attrs(rvest::html_children(x)) 237 | names(members) <- rvest::html_name(rvest::html_children(x)) 238 | RJSONIO::toJSON(members, pretty = T) 239 | } 240 | ) 241 | df <- data.frame(ID = ids, Related_Weakness = vals, stringsAsFactors = F) 242 | cwe.views <- dplyr::left_join(cwes, df, by = c("ID")) 243 | usethis::use_data(cwe.views, compress = "xz", overwrite = TRUE) 244 | 245 | rm(cwes, df, doc, raw.cwes, cwes.file, ids, vals) 246 | -------------------------------------------------------------------------------- /R/mitre.R: -------------------------------------------------------------------------------- 1 | #' Create a list of nodes and edges related to all standards in data folder. 2 | #' 3 | #' @param verbose logical, FALSE by default. Change it to see the process messages. 4 | #' @param as_igraph logical, TRUE by default. Change it to get list of nodes and edges. 5 | #' 6 | #' @return list, containing nodes and edges as data frames 7 | #' @export 8 | #' 9 | #' @examples 10 | #' mitrenet <- mitre::build_network(as_igraph = FALSE) 11 | build_network <- function(verbose = FALSE, as_igraph = TRUE) { 12 | if (verbose) print(paste0("[NET] Building nodes ...")) 13 | nodes <- build_nodes(verbose) 14 | if (verbose) print(paste0("[NET] Building edges ...")) 15 | edges <- build_edges(verbose) 16 | 17 | if (verbose) print(paste0("[NET] Cleaning network ...")) 18 | edges <- dplyr::left_join(edges, nodes[, c("id", "standard")], by = c("from_std"="standard")) 19 | edges$from <- edges$id 20 | edges$id <- NULL 21 | edges <- dplyr::left_join(edges, nodes[, c("id", "standard")], by = c("to_std"="standard")) 22 | edges$to <- edges$id 23 | edges$id <- NULL 24 | 25 | # Select complete edges and its nodes 26 | edges <- edges[!(is.na(edges$to) | is.na(edges$from)),] 27 | nodes <- nodes[nodes$id %in% unique(c(edges$from, edges$to)), ] 28 | 29 | 30 | if (as_igraph) { 31 | nodes$shape[nodes$shape %in% c("triangle", "box")] <- "circle" 32 | mitrenet <- igraph::graph_from_data_frame(edges, directed = T, vertices = nodes) 33 | } else { 34 | mitrenet <- list(nodes = nodes, edges = edges) 35 | } 36 | return(mitrenet) 37 | } 38 | 39 | 40 | #' Transform all standards as nodes in a data frame. 41 | #' 42 | #' \code{id} : The id of the node unique value for all standard elements. 43 | #' \code{label} : The label is the piece of text shown in or under the node, depending on the shape. 44 | #' \code{group} : When not undefined, the group of node(s) 45 | #' \code{type} : Used as subgroup to classify different object from 46 | #' \code{value} : When a value is set, the nodes will be scaled using the options in the scaling object defined above. 47 | #' \code{title} : Title to be displayed when the user hovers over the node. The title can be an HTML element or a string containing plain text or HTML. 48 | #' \code{standard} : The id of the standard 49 | #' \code{shape} : The shape defines what the node looks like. The types with the label inside of it are: ellipse, circle, database, box, text. The ones with the label outside of it are: image, circularImage, diamond, dot, star, triangle, triangleDown, square and icon. 50 | #' \code{color} : Color for the node. 51 | #' \code{hidden} : When true, the node will not be shown. It will still be part of the physics simulation though! 52 | #' \code{mass} : Default to 1. The barnesHut physics model (which is enabled by default) is based on an inverted gravity model. By increasing the mass of a node, you increase it's repulsion. Values lower than 1 are not recommended. 53 | #' \code{description} : Description could include extra information or nested data which include other columns from original data frame observation. 54 | #' 55 | #' @param verbose logical, FALSE by default. Change it to see the process messages. 56 | #' 57 | #' @importFrom rlang .data 58 | #' 59 | #' @return data.frame 60 | build_nodes <- function(verbose = FALSE) { 61 | nodes <- newNode() 62 | 63 | ### CPE 64 | if (verbose) print(paste0("[NET][CPE] extracting nodes ...")) 65 | cpe.nodes <- cpe.nist[, c("title", "cpe.23", "deprecated")] 66 | names(cpe.nodes) <- c("label", "title", "hidden") 67 | cpe.nodes$id <- rep(NA, nrow(cpe.nodes)) 68 | cpe.nodes$group <- rep("cpe", nrow(cpe.nodes)) 69 | cpe.nodes$type <- rep("cpe", nrow(cpe.nodes)) 70 | cpe.nodes$value <- rep(1, nrow(cpe.nodes)) 71 | cpe.nodes$standard <- cpe.nodes$title 72 | cpe.nodes$shape <- rep("circle", nrow(cpe.nodes)) 73 | cpe.nodes$color <- rep("blue", nrow(cpe.nodes)) 74 | cpe.nodes$mass <- rep(1, nrow(cpe.nodes)) 75 | cpe.nodes$description <- cpe.nodes$label 76 | 77 | nodes <- dplyr::bind_rows(nodes, cpe.nodes) 78 | 79 | ### CVE 80 | if (verbose) print(paste0("[NET][CVE] extracting nodes ...")) 81 | cve.nodes <- cve.nist[, c("cve.id", "description", "cvss3.score", "cvss2.score", "references")] 82 | cve.nodes$id <- rep(NA, nrow(cve.nodes)) 83 | cve.nodes$label <- cve.nodes$cve.id 84 | cve.nodes$group <- rep("cve", nrow(cve.nodes)) 85 | cve.nodes$type <- rep("cve", nrow(cve.nodes)) 86 | cve.nodes$cvss3.score[is.na(cve.nodes$cvss3.score)] <- 0 87 | cve.nodes$cvss2.score[is.na(cve.nodes$cvss2.score)] <- 0 88 | cve.nodes$value <- as.numeric(apply(cve.nodes, 1, function(x) max(x["cvss2.score"], x["cvss3.score"]))) 89 | cve.nodes$title <- cve.nodes$cve.id 90 | cve.nodes$standard <- cve.nodes$cve.id 91 | cve.nodes$shape <- rep("triangle", nrow(cve.nodes)) 92 | cve.nodes$color <- rep("blue", nrow(cve.nodes)) 93 | cve.nodes$hidden <- rep(FALSE, nrow(cve.nodes)) 94 | cve.nodes$mass <- cve.nodes$value 95 | cve.nodes$description <- cve.nodes$references 96 | cve.nodes <- cve.nodes[, names(nodes)] 97 | 98 | nodes <- dplyr::bind_rows(nodes, cve.nodes) 99 | 100 | ### CWE 101 | if (verbose) print(paste0("[NET][CWE] extracting nodes ...")) 102 | cwe.nodes <- dplyr::bind_rows(cwe.weaknesses, cwe.categories, cwe.views) 103 | cwe.nodes$id <- rep(NA, nrow(cwe.nodes)) 104 | cwe.nodes$label <- cwe.nodes$Code_Standard 105 | cwe.nodes$group <- rep("cwe", nrow(cwe.nodes)) 106 | cwe.nodes$type <- tolower(cwe.nodes$CWE_Type) 107 | cwe.nodes$value <- rep(1, nrow(cwe.nodes)) 108 | cwe.nodes$title <- cwe.nodes$Name 109 | cwe.nodes$standard <- cwe.nodes$Code_Standard 110 | cwe.nodes$shape <- rep("box", nrow(cwe.nodes)) 111 | cwe.nodes$color <- rep("blue", nrow(cwe.nodes)) 112 | cwe.nodes$hidden <- cwe.nodes$Status %in% c("Deprecated", "Obsolete") 113 | cwe.nodes$mass <- cwe.nodes$value 114 | cwe.nodes$description <- cwe.nodes$Description 115 | cwe.nodes <- cwe.nodes[, names(nodes)] 116 | 117 | nodes <- dplyr::bind_rows(nodes, cwe.nodes) 118 | 119 | ## ATT&CK MITRE 120 | ### Tactics 121 | if (verbose) print(paste0("[NET][ATTCK] extracting tactic nodes ...")) 122 | attck.nodes <- attck.tactics 123 | attck.nodes$id <- rep(NA, nrow(attck.nodes)) 124 | attck.nodes$label <- attck.nodes$external_id 125 | attck.nodes$group <- rep("attck", nrow(attck.nodes)) 126 | attck.nodes$type <- rep("tactic", nrow(attck.nodes)) 127 | attck.nodes$value <- rep(1, nrow(attck.nodes)) 128 | attck.nodes$title <- attck.nodes$name 129 | attck.nodes$standard <- attck.nodes$external_id 130 | attck.nodes$shape <- rep("box", nrow(attck.nodes)) 131 | attck.nodes$color <- rep("red", nrow(attck.nodes)) 132 | attck.nodes$hidden <- rep(FALSE, nrow(attck.nodes)) 133 | attck.nodes$mass <- attck.nodes$value 134 | attck.nodes$description <- attck.nodes$description 135 | attck.nodes <- attck.nodes[, names(nodes)] 136 | 137 | nodes <- dplyr::bind_rows(nodes, attck.nodes) 138 | 139 | ### Techniques 140 | if (verbose) print(paste0("[NET][ATTCK] extracting technique nodes ...")) 141 | attck.nodes <- attck.techniques 142 | attck.nodes$id <- rep(NA, nrow(attck.nodes)) 143 | attck.nodes$label <- attck.nodes$external_id 144 | attck.nodes$group <- rep("attck", nrow(attck.nodes)) 145 | attck.nodes$type <- rep("technique", nrow(attck.nodes)) 146 | attck.nodes$value <- rep(1, nrow(attck.nodes)) 147 | attck.nodes$title <- attck.nodes$name 148 | attck.nodes$standard <- attck.nodes$external_id 149 | attck.nodes$shape <- rep("triangle", nrow(attck.nodes)) 150 | attck.nodes$color <- rep("red", nrow(attck.nodes)) 151 | attck.nodes$hidden <- rep(FALSE, nrow(attck.nodes)) 152 | attck.nodes$mass <- attck.nodes$value 153 | attck.nodes$description <- attck.nodes$description 154 | attck.nodes <- attck.nodes[, names(nodes)] 155 | 156 | nodes <- dplyr::bind_rows(nodes, attck.nodes) 157 | 158 | ### Mitigations 159 | if (verbose) print(paste0("[NET][ATTCK] extracting mitigation nodes ...")) 160 | attck.nodes <- attck.mitigations 161 | attck.nodes$id <- rep(NA, nrow(attck.nodes)) 162 | attck.nodes$label <- attck.nodes$external_id 163 | attck.nodes$group <- rep("attck", nrow(attck.nodes)) 164 | attck.nodes$type <- rep("mitigation", nrow(attck.nodes)) 165 | attck.nodes$value <- rep(1, nrow(attck.nodes)) 166 | attck.nodes$title <- attck.nodes$name 167 | attck.nodes$standard <- attck.nodes$external_id 168 | attck.nodes$shape <- rep("square", nrow(attck.nodes)) 169 | attck.nodes$color <- rep("red", nrow(attck.nodes)) 170 | attck.nodes$hidden <- rep(FALSE, nrow(attck.nodes)) 171 | attck.nodes$mass <- attck.nodes$value 172 | attck.nodes$description <- attck.nodes$description 173 | attck.nodes <- attck.nodes[, names(nodes)] 174 | 175 | nodes <- dplyr::bind_rows(nodes, attck.nodes) 176 | 177 | ### Software 178 | if (verbose) print(paste0("[NET][ATTCK] extracting software nodes ...")) 179 | attck.nodes <- attck.software 180 | attck.nodes$id <- rep(NA, nrow(attck.nodes)) 181 | attck.nodes$label <- attck.nodes$external_id 182 | attck.nodes$group <- rep("attck", nrow(attck.nodes)) 183 | attck.nodes$type <- as.character(sapply(attck.nodes$type, 184 | function(x) paste0("software-", x))) 185 | attck.nodes$value <- rep(1, nrow(attck.nodes)) 186 | attck.nodes$title <- attck.nodes$name 187 | attck.nodes$standard <- attck.nodes$external_id 188 | attck.nodes$shape <- rep("square", nrow(attck.nodes)) 189 | attck.nodes$color <- rep("red", nrow(attck.nodes)) 190 | attck.nodes$hidden <- rep(FALSE, nrow(attck.nodes)) 191 | attck.nodes$mass <- attck.nodes$value 192 | attck.nodes$description <- attck.nodes$description 193 | attck.nodes <- attck.nodes[, names(nodes)] 194 | 195 | nodes <- dplyr::bind_rows(nodes, attck.nodes) 196 | 197 | ### Groups 198 | if (verbose) print(paste0("[NET][ATTCK] extracting groups nodes ...")) 199 | attck.nodes <- attck.groups 200 | attck.nodes$id <- rep(NA, nrow(attck.nodes)) 201 | attck.nodes$label <- attck.nodes$external_id 202 | attck.nodes$group <- rep("attck", nrow(attck.nodes)) 203 | attck.nodes$type <- rep("group", nrow(attck.nodes)) 204 | attck.nodes$value <- rep(1, nrow(attck.nodes)) 205 | attck.nodes$title <- attck.nodes$name 206 | attck.nodes$standard <- attck.nodes$external_id 207 | attck.nodes$shape <- rep("circle", nrow(attck.nodes)) 208 | attck.nodes$color <- rep("red", nrow(attck.nodes)) 209 | attck.nodes$hidden <- rep(FALSE, nrow(attck.nodes)) 210 | attck.nodes$mass <- attck.nodes$value 211 | attck.nodes$description <- attck.nodes$description 212 | attck.nodes <- attck.nodes[, names(nodes)] 213 | 214 | nodes <- dplyr::bind_rows(nodes, attck.nodes) 215 | 216 | ## CAPEC MITRE 217 | if (verbose) print(paste0("[NET][CAPEC] extracting nodes ...")) 218 | capec.p <- capec.patterns 219 | capec.p$type <- rep("pattern", nrow(capec.p)) 220 | capec.c <- capec.categories 221 | capec.c$type <- rep("category", nrow(capec.c)) 222 | capec.v <- capec.views 223 | capec.v$type <- rep("view", nrow(capec.v)) 224 | capec.nodes <- dplyr::bind_rows(capec.p, capec.c, capec.v) 225 | rm(capec.p, capec.c, capec.v) 226 | capec.nodes$label <- capec.nodes$id 227 | capec.nodes$id <- rep(NA, nrow(capec.nodes)) 228 | capec.nodes$group <- rep("capec", nrow(capec.nodes)) 229 | capec.nodes$type <- capec.nodes$type 230 | capec.nodes$value <- rep(1, nrow(capec.nodes)) 231 | capec.nodes$title <- capec.nodes$name 232 | capec.nodes$standard <- capec.nodes$label 233 | capec.nodes$shape <- rep("box", nrow(capec.nodes)) 234 | capec.nodes$color <- rep("orange", nrow(capec.nodes)) 235 | capec.nodes$hidden <- capec.nodes$status %in% c("Deprecated", "Obsolete") 236 | capec.nodes$mass <- capec.nodes$value 237 | capec.nodes$description <- capec.nodes$description 238 | capec.nodes <- capec.nodes[, names(nodes)] 239 | 240 | nodes <- dplyr::bind_rows(nodes, capec.nodes) 241 | 242 | ## SHIELD MITRE 243 | ### Tactics 244 | if (verbose) print(paste0("[NET][SHIELD] extracting tactic nodes ...")) 245 | shield.nodes <- shield.tactics 246 | shield.nodes$label <- shield.nodes$id 247 | shield.nodes$id <- rep(NA, nrow(shield.nodes)) 248 | shield.nodes$group <- rep("shield", nrow(shield.nodes)) 249 | shield.nodes$type <- rep("tactic", nrow(shield.nodes)) 250 | shield.nodes$value <- rep(1, nrow(shield.nodes)) 251 | shield.nodes$title <- shield.nodes$name 252 | shield.nodes$standard <- shield.nodes$label 253 | shield.nodes$shape <- rep("box", nrow(shield.nodes)) 254 | shield.nodes$color <- rep("grey", nrow(shield.nodes)) 255 | shield.nodes$hidden <- rep(FALSE, nrow(shield.nodes)) 256 | shield.nodes$mass <- shield.nodes$value 257 | shield.nodes$description <- shield.nodes$description 258 | shield.nodes <- shield.nodes[, names(nodes)] 259 | 260 | nodes <- dplyr::bind_rows(nodes, shield.nodes) 261 | 262 | ### Techniques 263 | if (verbose) print(paste0("[NET][SHIELD] extracting technique nodes ...")) 264 | shield.nodes <- shield.techniques 265 | shield.nodes$label <- shield.nodes$id 266 | shield.nodes$id <- rep(NA, nrow(shield.nodes)) 267 | shield.nodes$group <- rep("shield", nrow(shield.nodes)) 268 | shield.nodes$type <- rep("technique", nrow(shield.nodes)) 269 | shield.nodes$value <- rep(1, nrow(shield.nodes)) 270 | shield.nodes$title <- shield.nodes$name 271 | shield.nodes$standard <- shield.nodes$label 272 | shield.nodes$shape <- rep("triangle", nrow(shield.nodes)) 273 | shield.nodes$color <- rep("grey", nrow(shield.nodes)) 274 | shield.nodes$hidden <- rep(FALSE, nrow(shield.nodes)) 275 | shield.nodes$mass <- shield.nodes$value 276 | shield.nodes$description <- shield.nodes$description 277 | shield.nodes <- shield.nodes[, names(nodes)] 278 | 279 | nodes <- dplyr::bind_rows(nodes, shield.nodes) 280 | 281 | ### Use Cases 282 | if (verbose) print(paste0("[NET][SHIELD] extracting use case nodes ...")) 283 | shield.nodes <- shield.use_cases 284 | shield.nodes$label <- shield.nodes$id 285 | shield.nodes$id <- rep(NA, nrow(shield.nodes)) 286 | shield.nodes$group <- rep("shield", nrow(shield.nodes)) 287 | shield.nodes$type <- rep("use_case", nrow(shield.nodes)) 288 | shield.nodes$value <- rep(1, nrow(shield.nodes)) 289 | shield.nodes$title <- shield.nodes$label 290 | shield.nodes$standard <- shield.nodes$label 291 | shield.nodes$shape <- rep("circle", nrow(shield.nodes)) 292 | shield.nodes$color <- rep("grey", nrow(shield.nodes)) 293 | shield.nodes$hidden <- rep(FALSE, nrow(shield.nodes)) 294 | shield.nodes$mass <- shield.nodes$value 295 | shield.nodes$description <- shield.nodes$description 296 | shield.nodes <- shield.nodes[, names(nodes)] 297 | 298 | nodes <- dplyr::bind_rows(nodes, shield.nodes) 299 | 300 | ### Opportunities 301 | if (verbose) print(paste0("[NET][SHIELD] extracting opportunity nodes ...")) 302 | shield.nodes <- shield.opportunities 303 | shield.nodes$label <- shield.nodes$id 304 | shield.nodes$id <- rep(NA, nrow(shield.nodes)) 305 | shield.nodes$group <- rep("shield", nrow(shield.nodes)) 306 | shield.nodes$type <- rep("opportunity", nrow(shield.nodes)) 307 | shield.nodes$value <- rep(1, nrow(shield.nodes)) 308 | shield.nodes$title <- shield.nodes$label 309 | shield.nodes$standard <- shield.nodes$label 310 | shield.nodes$shape <- rep("square", nrow(shield.nodes)) 311 | shield.nodes$color <- rep("grey", nrow(shield.nodes)) 312 | shield.nodes$hidden <- rep(FALSE, nrow(shield.nodes)) 313 | shield.nodes$mass <- shield.nodes$value 314 | shield.nodes$description <- shield.nodes$description 315 | shield.nodes <- shield.nodes[, names(nodes)] 316 | 317 | nodes <- dplyr::bind_rows(nodes, shield.nodes) 318 | 319 | ### Procedures 320 | if (verbose) print(paste0("[NET][SHIELD] extracting procedure nodes ...")) 321 | shield.nodes <- shield.procedures 322 | shield.nodes$label <- shield.nodes$id 323 | shield.nodes$id <- rep(NA, nrow(shield.nodes)) 324 | shield.nodes$group <- rep("shield", nrow(shield.nodes)) 325 | shield.nodes$type <- rep("procedure", nrow(shield.nodes)) 326 | shield.nodes$value <- rep(1, nrow(shield.nodes)) 327 | shield.nodes$title <- shield.nodes$label 328 | shield.nodes$standard <- shield.nodes$label 329 | shield.nodes$shape <- rep("square", nrow(shield.nodes)) 330 | shield.nodes$color <- rep("grey", nrow(shield.nodes)) 331 | shield.nodes$hidden <- rep(FALSE, nrow(shield.nodes)) 332 | shield.nodes$mass <- shield.nodes$value 333 | shield.nodes$description <- shield.nodes$description 334 | shield.nodes <- shield.nodes[, names(nodes)] 335 | 336 | nodes <- dplyr::bind_rows(nodes, shield.nodes) 337 | 338 | ## CAR MITRE 339 | ### Analytics 340 | if (verbose) print(paste0("[NET][CAR] extracting analytic nodes ...")) 341 | car.nodes <- car.analytics 342 | car.nodes$label <- car.nodes$id 343 | car.nodes$group <- rep("car", nrow(car.nodes)) 344 | car.nodes$type <- rep("analytic", nrow(car.nodes)) 345 | car.nodes$value <- rep(1, nrow(car.nodes)) 346 | car.nodes$title <- car.nodes$title 347 | car.nodes$standard <- car.nodes$label 348 | car.nodes$shape <- rep("triangle", nrow(car.nodes)) 349 | car.nodes$color <- rep("green", nrow(car.nodes)) 350 | car.nodes$hidden <- rep(FALSE, nrow(car.nodes)) 351 | car.nodes$mass <- car.nodes$value 352 | car.nodes$description <- car.nodes$description 353 | car.nodes$id <- rep(NA, nrow(car.nodes)) 354 | car.nodes <- car.nodes[, names(nodes)] 355 | 356 | nodes <- dplyr::bind_rows(nodes, car.nodes) 357 | 358 | ### Data Model 359 | if (verbose) print(paste0("[NET][CAR] extracting data model nodes ...")) 360 | car.nodes <- car.model 361 | car.nodes$label <- car.nodes$model.id 362 | car.nodes$group <- rep("car", nrow(car.nodes)) 363 | car.nodes$type <- rep("data_model", nrow(car.nodes)) 364 | car.nodes$value <- rep(1, nrow(car.nodes)) 365 | car.nodes$title <- car.nodes$label 366 | car.nodes$standard <- car.nodes$label 367 | car.nodes$shape <- rep("circle", nrow(car.nodes)) 368 | car.nodes$color <- rep("green", nrow(car.nodes)) 369 | car.nodes$hidden <- rep(FALSE, nrow(car.nodes)) 370 | car.nodes$mass <- car.nodes$value 371 | car.nodes <- dplyr::mutate(car.nodes, 372 | description = paste(.data$description, .data$action.description, 373 | "Example: ", .data$field.example, sep = "\n\n")) 374 | car.nodes$id <- rep(NA, nrow(car.nodes)) 375 | car.nodes <- car.nodes[, names(nodes)] 376 | 377 | nodes <- dplyr::bind_rows(nodes, car.nodes) 378 | 379 | ### Sensors 380 | if (verbose) print(paste0("[NET][CAR] extracting sensor nodes ...")) 381 | car.nodes <- car.sensors 382 | car.nodes <- dplyr::mutate(car.nodes, label = paste(.data$sensor_name, .data$sensor_version, sep = "_")) 383 | car.nodes$group <- rep("car", nrow(car.nodes)) 384 | car.nodes$type <- rep("sensor", nrow(car.nodes)) 385 | car.nodes$value <- rep(1, nrow(car.nodes)) 386 | car.nodes$title <- car.nodes$label 387 | car.nodes$standard <- car.nodes$label 388 | car.nodes$shape <- rep("circle", nrow(car.nodes)) 389 | car.nodes$color <- rep("green", nrow(car.nodes)) 390 | car.nodes$hidden <- rep(FALSE, nrow(car.nodes)) 391 | car.nodes$mass <- car.nodes$value 392 | car.nodes$description = car.nodes$sensor_description 393 | car.nodes$id <- rep(NA, nrow(car.nodes)) 394 | car.nodes <- car.nodes[, names(nodes)] 395 | 396 | nodes <- dplyr::bind_rows(nodes, car.nodes) 397 | nodes$id <- 1:nrow(nodes) 398 | 399 | return(nodes) 400 | } 401 | 402 | #' Extract relationships between standards as edges in a data frame. 403 | #' 404 | #' \code{from} : node id of edge start 405 | #' \code{to} : node id of edge end 406 | #' \code{from_std} : standard id of edge start 407 | #' \code{to_std} : standard id of edge end 408 | #' \code{value} : When a value is set, the nodes will be scaled using the options in the scaling object defined above. 409 | #' \code{title} : The title is shown in a pop-up when the mouse moves over the edge. 410 | #' \code{arrows} : To draw an arrow with default settings a string can be supplied. For example: 'to, from,middle' or 'to;from', any combination with any separating symbol is fine. If you want to control the size of the arrowheads, you can supply an object. 411 | #' \code{dashes} : When true, the edge will be drawn as a dashed line. 412 | #' \code{color} : Color for the node. 413 | #' \code{hidden} : When true, the node will not be shown. It will still be part of the physics simulation though! 414 | #' 415 | #' @param verbose logical, FALSE by default. Change it to see the process messages. 416 | #' 417 | #' @return data.frame 418 | build_edges <- function(verbose = FALSE) { 419 | edges <- newEdge() 420 | 421 | ### CPE -> CVE 422 | cpe.edges <- lapply(cpe.nist$refs, function(x) stringr::str_extract_all(x, "CVE-\\d+-\\d+")) 423 | cpe.edges <- sapply(cpe.edges, function(x) ifelse(identical(x[[1]], character(0)), NA, x[[1]])) 424 | cpe.edges <- data.frame(from_std = cpe.nist$cpe.23, to_std = cpe.edges, stringsAsFactors = FALSE) 425 | cpe.edges <- cpe.edges[stats::complete.cases(cpe.edges), ] 426 | cpe.edges$to_std <- as.character(cpe.edges$to_std) 427 | cpe.edges$from <- as.character(rep(NA, nrow(cpe.edges))) 428 | cpe.edges$to <- as.character(rep(NA, nrow(cpe.edges))) 429 | cpe.edges$title <- rep("is_vulnerable", nrow(cpe.edges)) 430 | cpe.edges$value <- rep(1, nrow(cpe.edges)) 431 | cpe.edges$label <- rep("is_vulnerable", nrow(cpe.edges)) 432 | cpe.edges$arrows <- rep("to", nrow(cpe.edges)) 433 | cpe.edges$dashes <- rep(FALSE, nrow(cpe.edges)) 434 | cpe.edges$hidden <- rep(FALSE, nrow(cpe.edges)) 435 | cpe.edges$color <- rep("red", nrow(cpe.edges)) 436 | 437 | cpe.edges <- cpe.edges[, names(edges)] 438 | edges <- dplyr::bind_rows(edges, cpe.edges) 439 | 440 | ### CVE -> CWE 441 | cve.edges <- dplyr::select(cve.nist, c("cve.id", "problem.type")) 442 | cve.edges[cve.edges$problem.type == "{}", "problem.type"] <- "[\"NVD-CWE-noinfo\"]" 443 | cve.edges$problem.type <- lapply(cve.edges$problem.type, jsonlite::fromJSON) 444 | cve.edges <- tidyr::unnest(cve.edges, cols = c("problem.type")) 445 | names(cve.edges) <- c("from_std", "to_std") 446 | cve.edges$from <- as.character(rep(NA, nrow(cve.edges))) 447 | cve.edges$to <- as.character(rep(NA, nrow(cve.edges))) 448 | cve.edges$title <- rep("takes_advantage_of", nrow(cve.edges)) 449 | cve.edges$value <- rep(1, nrow(cve.edges)) 450 | cve.edges$label <- rep("problem_type", nrow(cve.edges)) 451 | cve.edges$arrows <- rep("to", nrow(cve.edges)) 452 | cve.edges$dashes <- rep(FALSE, nrow(cve.edges)) 453 | cve.edges$hidden <- rep(FALSE, nrow(cve.edges)) 454 | cve.edges$color <- rep("orange", nrow(cve.edges)) 455 | 456 | cve.edges <- cve.edges[-which(cve.edges$to_std == "NVD-CWE-noinfo"), ] 457 | cve.edges <- cve.edges[-which(cve.edges$to_std == "NVD-CWE-Other"), ] 458 | 459 | cve.edges <- cve.edges[, names(edges)] 460 | edges <- dplyr::bind_rows(edges, cve.edges) 461 | 462 | ### CVE -> CPE 463 | cve.edges <- dplyr::select(cve.nist, c("cve.id", "vulnerable.configuration")) 464 | cpematch <- lapply(cve.edges$vulnerable.configuration, 465 | function(x) 466 | unique(jsonlite::fromJSON(x)$cpe_match[[1]]$cpe23Uri)) 467 | cpematch <- unlist(lapply(cpematch, function(x) ifelse(is.null(x), NA, x))) 468 | cpechild <- lapply(cve.edges$vulnerable.configuration, 469 | function(x) 470 | unique(unlist(sapply(jsonlite::fromJSON(x)$children, 471 | function(y) 472 | unlist(sapply(y$cpe_match, 473 | function(z) z$cpe23Uri)))))) 474 | cpechild <- unlist(lapply(cpechild, function(x) ifelse(is.null(x), NA, x))) 475 | tocpes <- data.frame(cpematch = cpematch, 476 | cpechild = cpechild, 477 | stringsAsFactors = FALSE) 478 | cve.edges$to_std <- apply(tocpes, 1, 479 | function(x) 480 | as.character(stats::na.exclude(unique(c(x[["cpematch"]], x[["cpechild"]]))))) 481 | cve.edges <- tidyr::unnest(cve.edges, cols = c("to_std")) 482 | cve.edges$vulnerable.configuration <- NULL 483 | cve.edges$from_std <- cve.edges$cve.id 484 | cve.edges$from <- as.character(rep(NA, nrow(cve.edges))) 485 | cve.edges$to <- as.character(rep(NA, nrow(cve.edges))) 486 | cve.edges$title <- rep("vulnerable_configuration", nrow(cve.edges)) 487 | cve.edges$value <- rep(1, nrow(cve.edges)) 488 | cve.edges$label <- rep("is_vulnerable", nrow(cve.edges)) 489 | cve.edges$arrows <- rep("to", nrow(cve.edges)) 490 | cve.edges$dashes <- rep(FALSE, nrow(cve.edges)) 491 | cve.edges$hidden <- rep(FALSE, nrow(cve.edges)) 492 | cve.edges$color <- rep("red", nrow(cve.edges)) 493 | rm(cpematch, cpechild, tocpes) 494 | 495 | cve.edges <- cve.edges[, names(edges)] 496 | edges <- dplyr::bind_rows(edges, cve.edges) 497 | 498 | ### CWE -> CVE 499 | cwe.edges <- lapply(cwe.weaknesses$Observed_Examples, 500 | function(x) { 501 | cves <- stringr::str_extract_all(x, "CVE-\\d+-\\d+")[[1]] 502 | data.frame(to_std = cves, stringsAsFactors = FALSE) 503 | }) 504 | names(cwe.edges) <- cwe.weaknesses$Code_Standard 505 | cwe.edges <- plyr::ldply(cwe.edges, rbind) 506 | names(cwe.edges) <- c("from_std", "to_std") 507 | cwe.edges <- cwe.edges[stats::complete.cases(cwe.edges), ] 508 | cwe.edges$from <- as.character(rep(NA, nrow(cwe.edges))) 509 | cwe.edges$to <- as.character(rep(NA, nrow(cwe.edges))) 510 | cwe.edges$title <- rep("vulnerability_example", nrow(cwe.edges)) 511 | cwe.edges$value <- rep(1, nrow(cwe.edges)) 512 | cwe.edges$label <- rep("example", nrow(cwe.edges)) 513 | cwe.edges$arrows <- rep("to", nrow(cwe.edges)) 514 | cwe.edges$dashes <- rep(FALSE, nrow(cwe.edges)) 515 | cwe.edges$hidden <- rep(FALSE, nrow(cwe.edges)) 516 | cwe.edges$color <- rep("orange", nrow(cwe.edges)) 517 | 518 | cwe.edges <- cwe.edges[, names(edges)] 519 | edges <- dplyr::bind_rows(edges, cwe.edges) 520 | 521 | ### CWE -> CAPEC 522 | cwe.edges <- cwe.weaknesses[, c("Code_Standard", "Related_Attack_Patterns")] 523 | cwe.edges <- cwe.edges[stats::complete.cases(cwe.edges), ] 524 | cwe2capec <- lapply(cwe.edges$Related_Attack_Patterns, 525 | function(x) 526 | data.frame(to_std = paste0("CAPEC-", RJSONIO::fromJSON(x)), 527 | stringsAsFactors = FALSE)) 528 | names(cwe2capec) <- cwe.edges$Code_Standard 529 | cwe.edges <- dplyr::bind_rows(cwe2capec, .id = "from_std") 530 | cwe.edges <- cwe.edges[stats::complete.cases(cwe.edges), ] 531 | cwe.edges$from <- as.character(rep(NA, nrow(cwe.edges))) 532 | cwe.edges$to <- as.character(rep(NA, nrow(cwe.edges))) 533 | cwe.edges$title <- rep("leverage_attack", nrow(cwe.edges)) 534 | cwe.edges$value <- rep(1, nrow(cwe.edges)) 535 | cwe.edges$label <- rep("leverage", nrow(cwe.edges)) 536 | cwe.edges$arrows <- rep("to", nrow(cwe.edges)) 537 | cwe.edges$dashes <- rep(FALSE, nrow(cwe.edges)) 538 | cwe.edges$hidden <- rep(FALSE, nrow(cwe.edges)) 539 | cwe.edges$color <- rep("red", nrow(cwe.edges)) 540 | 541 | cwe.edges <- cwe.edges[, names(edges)] 542 | edges <- dplyr::bind_rows(edges, cwe.edges) 543 | 544 | ### CWE -> CWE 545 | cwe.edges <- dplyr::bind_rows(cwe.views[, c("Code_Standard", "Related_Weakness")], 546 | cwe.categories[, c("Code_Standard", "Related_Weakness")], 547 | cwe.weaknesses[, c("Code_Standard", "Related_Weakness")]) 548 | cwe.edges <- cwe.edges[stats::complete.cases(cwe.edges), ] 549 | cwe2cwe <- lapply(cwe.edges$Related_Weakness, 550 | function(x) { 551 | k <- RJSONIO::fromJSON(x) 552 | if (length(k) == 1) { 553 | k <- as.data.frame.array(t(k[[1]])) 554 | } else { 555 | k <- dplyr::bind_rows(lapply(k, function(x) as.data.frame(t(x)))) 556 | # names(k) <- c("nature", "cwe_id", "view_id", "ordinal") 557 | } 558 | k 559 | }) 560 | names(cwe2cwe) <- cwe.edges$Code_Standard 561 | cwe.edges <- dplyr::bind_rows(cwe2cwe, .id = "from_std") 562 | cwe.edges$to_std <- paste0("CWE-", cwe.edges$cwe_id) 563 | cwe.edges$from <- as.character(rep(NA, nrow(cwe.edges))) 564 | cwe.edges$to <- as.character(rep(NA, nrow(cwe.edges))) 565 | cwe.edges$nature[is.na(cwe.edges$nature)] <- "include" 566 | cwe.edges$title <- cwe.edges$nature 567 | cwe.edges$value <- rep(1, nrow(cwe.edges)) 568 | cwe.edges$label <- rep("include", nrow(cwe.edges)) 569 | cwe.edges$arrows <- rep("to", nrow(cwe.edges)) 570 | cwe.edges$dashes <- rep(FALSE, nrow(cwe.edges)) 571 | cwe.edges$hidden <- rep(FALSE, nrow(cwe.edges)) 572 | cwe.edges$color <- rep("blue", nrow(cwe.edges)) 573 | 574 | cwe.edges <- cwe.edges[, names(edges)] 575 | edges <- dplyr::bind_rows(edges, cwe.edges) 576 | rm(cwe2capec, cwe2cwe) 577 | 578 | ### CAPEC multiple relations 579 | capec.edges <- capec.relations 580 | # XXX: Workaround for empty relations to CWEs 581 | capec.edges <- capec.edges[!grepl(pattern = "^CWE-$", x = capec.edges$to), ] 582 | names(capec.edges) <- c("from_std", "label", "to_std", "title") 583 | capec.edges$from <- as.character(rep(NA, nrow(capec.edges))) 584 | capec.edges$to <- as.character(rep(NA, nrow(capec.edges))) 585 | capec.edges$value <- rep(1, nrow(capec.edges)) 586 | capec.edges$arrows <- rep("to", nrow(capec.edges)) 587 | capec.edges$dashes <- rep(FALSE, nrow(capec.edges)) 588 | capec.edges$hidden <- rep(FALSE, nrow(capec.edges)) 589 | capec.edges$color <- rep("orange", nrow(capec.edges)) 590 | 591 | capec.edges <- capec.edges[, names(edges)] 592 | edges <- dplyr::bind_rows(edges, capec.edges) 593 | 594 | ### ATTCK multiple relations 595 | attck.edges <- attck.relations 596 | attck.edges <- attck.edges[, c("from", "to", "description", "relationship_type")] 597 | names(attck.edges) <- c("from_std", "to_std", "title", "label") 598 | attck.edges$from <- as.character(rep(NA, nrow(attck.edges))) 599 | attck.edges$to <- as.character(rep(NA, nrow(attck.edges))) 600 | attck.edges$value <- rep(1, nrow(attck.edges)) 601 | attck.edges$arrows <- rep("to", nrow(attck.edges)) 602 | attck.edges$dashes <- rep(FALSE, nrow(attck.edges)) 603 | attck.edges$hidden <- rep(FALSE, nrow(attck.edges)) 604 | attck.edges$color <- rep("red", nrow(attck.edges)) 605 | 606 | attck.edges <- attck.edges[, names(edges)] 607 | edges <- dplyr::bind_rows(edges, attck.edges) 608 | 609 | ### SHIELD multiple relations 610 | shield.edges <- shield.relations 611 | names(shield.edges) <- c("from_std", "to_std", "label") 612 | shield.edges$title <- shield.edges$label 613 | shield.edges$from <- as.character(rep(NA, nrow(shield.edges))) 614 | shield.edges$to <- as.character(rep(NA, nrow(shield.edges))) 615 | shield.edges$value <- rep(1, nrow(shield.edges)) 616 | shield.edges$arrows <- rep("to", nrow(shield.edges)) 617 | shield.edges$dashes <- rep(FALSE, nrow(shield.edges)) 618 | shield.edges$hidden <- rep(FALSE, nrow(shield.edges)) 619 | shield.edges$color <- rep("blue", nrow(shield.edges)) 620 | 621 | shield.edges <- shield.edges[, names(edges)] 622 | edges <- dplyr::bind_rows(edges, shield.edges) 623 | 624 | ### CAR multiple relations 625 | #### CAR -> ATTCK 626 | car.edges <- car.coverage 627 | names(car.edges) <- c("from_std", "to_std", "title", "value") 628 | car.edges$label <- rep("cover", nrow(car.edges)) 629 | car.edges$from <- as.character(rep(NA, nrow(car.edges))) 630 | car.edges$to <- as.character(rep(NA, nrow(car.edges))) 631 | car.edges$arrows <- rep("to", nrow(car.edges)) 632 | car.edges$dashes <- rep(FALSE, nrow(car.edges)) 633 | car.edges$hidden <- rep(FALSE, nrow(car.edges)) 634 | car.edges$color <- rep("blue", nrow(car.edges)) 635 | 636 | car.edges <- car.edges[, names(edges)] 637 | edges <- dplyr::bind_rows(edges, car.edges) 638 | 639 | #### CAR -> CAR Data Model 640 | #### CAR Data Model -> CAR Sensor 641 | car.edges <- car.relations 642 | names(car.edges) <- c("from_std", "to_std") 643 | car.edges$label <- rep("implement", nrow(car.edges)) 644 | car.edges$title <- car.edges$label 645 | car.edges$from <- as.character(rep(NA, nrow(car.edges))) 646 | car.edges$to <- as.character(rep(NA, nrow(car.edges))) 647 | car.edges$value <- rep(1, nrow(car.edges)) 648 | car.edges$arrows <- rep("to", nrow(car.edges)) 649 | car.edges$dashes <- rep(FALSE, nrow(car.edges)) 650 | car.edges$hidden <- rep(FALSE, nrow(car.edges)) 651 | car.edges$color <- rep("blue", nrow(car.edges)) 652 | 653 | car.edges <- car.edges[, names(edges)] 654 | edges <- dplyr::bind_rows(edges, car.edges) 655 | 656 | return(edges) 657 | } 658 | 659 | #' Create an empty node 660 | #' 661 | #' \code{id} : The id of the node unique value for all standard elements. 662 | #' \code{label} : The label is the piece of text shown in or under the node, depending on the shape. 663 | #' \code{group} : When not undefined, the group of node(s) 664 | #' \code{type} : Used as subgroup to classify different object from 665 | #' \code{value} : When a value is set, the nodes will be scaled using the options in the scaling object defined above. 666 | #' \code{title} : Title to be displayed when the user hovers over the node. The title can be an HTML element or a string containing plain text or HTML. 667 | #' \code{standard} : The id of the standard 668 | #' \code{shape} : The shape defines what the node looks like. The types with the label inside of it are: ellipse, circle, database, box, text. The ones with the label outside of it are: image, circularImage, diamond, dot, star, triangle, triangleDown, square and icon. 669 | #' \code{color} : Color for the node. 670 | #' \code{hidden} : When true, the node will not be shown. It will still be part of the physics simulation though! 671 | #' \code{mass} : Default to 1. The "barnesHut" physics model (which is enabled by default) is based on an inverted gravity model. By increasing the mass of a node, you increase it's repulsion. Values lower than 1 are not recommended. 672 | #' \code{description} : Description could include extra information or nested data which include other columns from original data frame observation. 673 | #' 674 | #' @return data.frame 675 | newNode <- function() { 676 | node <- data.frame( 677 | id = character(), 678 | label = character(), 679 | group = character(), 680 | type = character(), 681 | value = numeric(), 682 | title = character(), 683 | standard = character(), 684 | shape = character(), 685 | color = character(), 686 | hidden = logical(), 687 | mass = numeric(), 688 | description = character(), 689 | stringsAsFactors = FALSE 690 | ) 691 | 692 | return(node) 693 | } 694 | 695 | 696 | #' Create an empty node 697 | #' 698 | #' \code{from} : node id of edge start 699 | #' \code{to} : node id of edge end 700 | #' \code{from_std} : standard id of edge start 701 | #' \code{to_std} : standard id of edge end 702 | #' \code{title} : The title is shown in a pop-up when the mouse moves over the edge. 703 | #' \code{value} : When a value is set, the nodes will be scaled using the options in the scaling object defined above. 704 | #' \code{label} : The label of the edge. HTML does not work in here because the network uses HTML5 Canvas. 705 | #' \code{arrows} : To draw an arrow with default settings a string can be supplied. For example: 'to, from,middle' or 'to;from', any combination with any separating symbol is fine. If you want to control the size of the arrowheads, you can supply an object. 706 | #' \code{dashes} : When true, the edge will be drawn as a dashed line. 707 | #' \code{hidden} : When true, the node will not be shown. It will still be part of the physics simulation though! 708 | #' \code{color} : Color for the node. 709 | #' \code{hidden} : When true, the node will not be shown. It will still be part of the physics simulation though! 710 | #' 711 | #' @return data.frame 712 | newEdge <- function() { 713 | edge <- data.frame( 714 | from = character(), 715 | to = character(), 716 | from_std = character(), 717 | to_std = character(), 718 | title = character(), 719 | value = numeric(), 720 | label = character(), 721 | arrows = character(), 722 | dashes = logical(), 723 | hidden = logical(), 724 | color = character(), 725 | stringsAsFactors = FALSE 726 | ) 727 | 728 | return(edge) 729 | } 730 | --------------------------------------------------------------------------------