Browse Source

initial commit

master
boB Rudis 3 years ago
parent
commit
8e2183b29f
No known key found for this signature in database GPG Key ID: 1D7529BE14E2BBA9
  1. 1
      .Rbuildignore
  2. 11
      DESCRIPTION
  3. 2
      LICENSE
  4. 21
      LICENSE.md
  5. 8
      NAMESPACE
  6. 9
      R/aaa.R
  7. 35
      R/api-key.R
  8. 117
      R/assessments.R
  9. 9
      R/attackerkb-package.R
  10. 81
      R/contributor.R
  11. 305
      R/topics.R
  12. 4
      R/utils-infix-helpers.R
  13. 116
      R/utils.R
  14. 71
      README.md
  15. 6
      man/attackerkb.Rd
  16. 20
      man/attackerkb_api_key.Rd
  17. 50
      man/kb_assessments.Rd
  18. 41
      man/kb_contributors.Rd
  19. 56
      man/kb_topics.Rd

1
.Rbuildignore

@ -19,3 +19,4 @@
^CRAN-RELEASE$
^appveyor\.yml$
^tools$
^LICENSE\.md$

11
DESCRIPTION

@ -1,6 +1,6 @@
Package: attackerkb
Type: Package
Title: attackerkb title goes here otherwise CRAN checks fail
Title: Tools to Query the Rapid7 AttackerKB API
Version: 0.1.0
Date: 2020-04-15
Authors@R: c(
@ -8,17 +8,20 @@ Authors@R: c(
comment = c(ORCID = "0000-0001-5670-2640"))
)
Maintainer: Bob Rudis <bob@rud.is>
Description: A good description goes here otherwise CRAN checks fail.
Description: Rapid7 manages a service — <https://attackerkb.com/> - where experts can evaluate
various aspects of emergent or existing vulnerabilities and the community can query and
retrieve results. Tools are provides to query the AttackerKB API.
URL: https://git.rud.is/hrbrmstr/attackerkb
BugReports: https://git.rud.is/hrbrmstr/attackerkb/issues
Encoding: UTF-8
License: AGPL
License: MIT + file LICENSE
Suggests:
covr, tinytest
Depends:
R (>= 3.2.0)
Imports:
httr,
jsonlite
jsonlite,
data.table
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.1.0

2
LICENSE

@ -0,0 +1,2 @@
YEAR: 2020
COPYRIGHT HOLDER: Bob Rudis

21
LICENSE.md

@ -0,0 +1,21 @@
# MIT License
Copyright (c) 2020 Bob Rudis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

8
NAMESPACE

@ -1,4 +1,12 @@
# Generated by roxygen2: do not edit by hand
export(attackerkb_api_key)
export(kb_assessment)
export(kb_assessments)
export(kb_contributors)
export(kb_topic)
export(kb_topics)
export(kd_contributor)
import(httr)
importFrom(data.table,rbindlist)
importFrom(jsonlite,fromJSON)

9
R/aaa.R

@ -0,0 +1,9 @@
set_names <- function (object = nm, nm) { names(object) <- nm ; object }
httr::user_agent(
sprintf(
"{attackerkb} package v%s: (<%s>)",
utils::packageVersion("attackerkb"),
utils::packageDescription("attackerkb")$URL
)
) -> .ATTACKERKB_UA

35
R/api-key.R

@ -0,0 +1,35 @@
#' Get or set ATTACKERKB_API_KEY value
#'
#' The API wrapper functions in this package all rely on a AttackerKB API
#' key residing in the environment variable `ATTACKERKB_API_KEY`.
#' The easiest way to accomplish this is to set it
#' in the `.Renviron` file in your home directory.
#'
#' @md
#' @param force Force setting a new AttackerKB key for the current environment?
#' @return atomic character vector containing the AttackerKB api key
#' @export
attackerkb_api_key <- function(force = FALSE) {
env <- Sys.getenv('ATTACKERKB_API_KEY')
if (!identical(env, "") && !force) return(env)
if (!interactive()) {
stop("Please set env var ATTACKERKB_API_KEY to your AttackerKB key",
call. = FALSE)
}
message("Couldn't find env var ATTACKERKB_API_KEY See ?ATTACKERKB_API_KEY for more details.")
message("Please enter your API key:")
pat <- readline(": ")
if (identical(pat, "")) {
stop("AttackerKB key entry failed", call. = FALSE)
}
message("Updating ATTACKERKB_API_KEY env var")
Sys.setenv(ATTACKERKB_API_KEY = pat)
pat
}

117
R/assessments.R

@ -0,0 +1,117 @@
#' Helpers to query AttackerKB assessments
#'
#' The main `kb_contributors` function maps 1:1 to the API. Leave values
#' `NULL` that you do not want included in the search parameters.
#'
#' @param assessment_id UUID of a specific assessment to return
#' @param editor_id UUID of a contributor.
#' @param topid_id UUID of the topic this assessment was based on.
#' @param created Return all assessments that were created on the given date.
#' @param revised Return all assessments that were revised on the given date.
#' @param document Text to query the document attribute. A substring match is performed
#' @param metadata Text to query the metadata attribute. A substring match is performed
#' @param score Return all assessments with this score.
#' @param q Return all assessments that have content that match the query string.
#' @param api_key See [attackerkb_api_key()]
#' @references <https://api.attackerkb.com/api-docs/docs>
#' @export
kb_assessments <- function(assessment_id = NULL,
editor_id = NULL,
topid_id = NULL,
created = NULL,
revised = NULL,
document = NULL,
metadata = NULL,
score = NULL,
q = NULL,
api_key = attackerkb_api_key()) {
assessment_id <- assessment_id[1]
editor_id <- editor_id[1]
topid_id <- topid_id[1]
created <- created[1]
revised <-revised[1]
document <- document[1]
metadata <- metadata[1]
score <-score[1]
q <- q[1]
if (length(created)) created <- as.character(as.Date(created[1]))
if (length(revised)) created <- as.character(as.Date(created[1]))
httr::GET(
url = "https://api.attackerkb.com/assessments",
.ATTACKERKB_UA,
query = list(
id = assessment_id,
editorId = editor_id,
topicId = topid_id,
created = created,
revisionDate = revised,
document = document,
metadata = metadata,
score = score,
q = q,
size = 500L
),
httr::add_headers(`Authorization` = sprintf("basic %s", api_key))
) -> res
httr::stop_for_status(res)
out <- httr::content(res, as = "text", encoding = "UTF-8")
out <- jsonlite::fromJSON(out)
out <- handle_response(out)
out
}
#' @rdname kb_assessments
#' @export
kb_assessment <- function(assessment_id, api_key = attackerkb_api_key()) {
assessment_id <- assessment_id[1]
httr::GET(
url = sprintf("https://api.attackerkb.com/assessments/%s", assessment_id),
.ATTACKERKB_UA,
httr::add_headers(`Authorization` = sprintf("basic %s", api_key))
) -> res
httr::stop_for_status(res)
out <- httr::content(res, as = "text", encoding = "UTF-8")
out <- jsonlite::fromJSON(out)
out <- out$data
metadata <- out$metadata
out$metadata <- NULL
out <- as.data.frame(out, stringsAsFactors = FALSE)
out$tags <- list(metadata[["tags"]]) %l0% NA_character_
out$attacker_value <- metadata[["attacker-value"]] %l0% NA_integer_
out$exploitability <- metadata[["exploitability"]] %l0% NA_integer_
out$stability <- metadata[["stability"]] %l0% NA_integer_
out$reliability <- metadata[["reliability"]] %l0% NA_integer_
out$urgent_to_patch <- metadata[["urgent-to-patch"]] %l0% NA_integer_
out$used_successfully <- metadata[["used-successfully"]] %l0% NA_integer_
out$mitigation_strength <- metadata[["mitigation-strength"]] %l0% NA_integer_
out$confidence_in_ratings <- metadata[["confidence-in-ratings"]] %l0% NA_integer_
out$effort_to_develop_exploit <- metadata[["effort-to-develop-exploit"]] %l0% NA_integer_
out$versions <- list(metadata[["versions"]]) %||% list()
out$mitigation <- metadata[["mitigation"]] %l0% NA_character_
out$forever_day_versions <- list(metadata[["forever_day_versions"]]) %l0% list()
out$offensive_application <- metadata[["offensive-application"]] %l0% NA_character_
out$atacker_utility <- metadata[["atacker-utility"]] %l0% NA_integer_
out$urgent_topatch <- metadata[["urgent-to patch"]] %l0% NA_integer_
class(out) <- c("tbl_df", "tbl", "data.frame")
out
}

9
R/attackerkb-package.R

@ -1,9 +1,14 @@
#' ...
#'
#' Tools to Query the Rapid7 AttackerKB API
#'
#' Rapid7 manages a service — <https://attackerkb.com/> - where experts can evaluate
#' various aspects of emergent or existing vulnerabilities and the community can query and
#' retrieve results. Tools are provides to query the AttackerKB API.
#'
#' @md
#' @name attackerkb
#' @keywords internal
#' @author Bob Rudis (bob@@rud.is)
#' @import httr
#' @importFrom jsonlite fromJSON
#' @importFrom data.table rbindlist
"_PACKAGE"

81
R/contributor.R

@ -0,0 +1,81 @@
#' Helpers to query AttackerKB contributors
#'
#' The main `kb_contributors` function maps 1:1 to the API. Leave values
#' `NULL` that you do not want included in the search parameters.
#'
#' @param contributor_id UUID of a specific contributror to return
#' @param username Return contributors with the matching username.
#' @param avatar Return all contributors where avatar matches the given value
#' @param created Return all contributors that were created on the given date.
#' @param score Return all contributors with this score.
#' @param q Return all contributors that have usernames that match the query string.
#' @param api_key See [attackerkb_api_key()]
#' @references <https://api.attackerkb.com/api-docs/docs>
#' @export
kb_contributors <- function(contributor_id = NULL,
username = NULL,
avatar = NULL,
created = NULL,
score = NULL,
q = NULL,
api_key = attackerkb_api_key()) {
contributor_id <- contributor_id[1]
username <- username[1]
avatar <- avatar[1]
created <- created[1]
score <- score[1]
q <- q[1]
if (length(created)) created <- as.character(as.Date(created[1]))
httr::GET(
url = "https://api.attackerkb.com/contributors",
.ATTACKERKB_UA,
query = list(
id = contributor_id,
username = username,
avatar = avatar,
created = created,
score = score,
q = q,
size = 500L
),
httr::add_headers(`Authorization` = sprintf("basic %s", api_key))
) -> res
httr::stop_for_status(res)
out <- httr::content(res, as = "text", encoding = "UTF-8")
out <- jsonlite::fromJSON(out)
out <- handle_response(out)
out
}
#' @rdname kb_contributors
#' @export
kd_contributor <- function(contributor_id, api_key = attackerkb_api_key()) {
contributor_id <- contributor_id[1]
httr::GET(
url = sprintf("https://api.attackerkb.com/contributors/%s", contributor_id),
.ATTACKERKB_UA,
httr::add_headers(`Authorization` = sprintf("basic %s", api_key))
) -> res
httr::stop_for_status(res)
out <- httr::content(res, as = "text", encoding = "UTF-8")
out <- jsonlite::fromJSON(out)
out <- as.data.frame(out$data, stringsAsFactors=FALSE)
class(out) <- c("tbl_df", "tbl", "data.frame")
out
}

305
R/topics.R

@ -0,0 +1,305 @@
#' Helpers to query AttackerKB topics
#'
#' The main `kb_topics` function maps 1:1 to the API. Leave values
#' `NULL` that you do not want included in the search parameters.
#'
#' @param topic_id UUID of a specific topic to return
#' @param editor_id UUID of a contributor
#' @param name Text to query the name attribute. A substring match is performed
#' @param created Return all topics that were created on the given date.
#' @param revised Return all topics that were revised on the given date.
#' @param disclosed Return all topics that were disclosed on the given date.
#' @param document Text to query the document attribute. A substring match is performed
#' @param metadata Text to query the metadata attribute. A substring match is performed
#' @param featured (lgl) `TRUE`/`FALSE`. Return all topics that are featured.
#' @param q Return all topics that have content that matches the query string.
#' @param api_key See [attackerkb_api_key()]
#' @references <https://api.attackerkb.com/api-docs/docs>
#' @export
kb_topics <- function(topic_id = NULL,
editor_id = NULL,
name = NULL,
created = NULL,
revised = NULL,
disclosed = NULL,
document = NULL,
metadata = NULL,
featured = NULL,
q = NULL,
api_key = attackerkb_api_key()) {
topic_id <- topic_id[1]
editor_id <-editor_id[1]
name <- name[1]
created <- created[1]
revised <-revised[1]
disclosed <- disclosed[1]
document <- document[1]
metadata <- metadata[1]
featured <- featured[1]
q <- q[1]
if (length(featured)) featured <- tolower(as.character(as.logical(featured)))
if (length(created)) created <- as.character(as.Date(created[1]))
if (length(revised)) revised <- as.character(as.Date(revised[1]))
if (length(disclosed)) disclosed <- as.character(as.Date(disclosed[1]))
httr::GET(
url = "https://api.attackerkb.com/topics",
.ATTACKERKB_UA,
query = list(
id = topic_id,
editorId = editor_id,
name = name,
created = created,
revisionDate = revised,
disclosureDate = disclosed,
document = document,
metadata = metadata,
featured = featured,
q = q,
size = 500L
),
httr::add_headers(`Authorization` = sprintf("basic %s", api_key))
) -> res
httr::stop_for_status(res)
out <- httr::content(res, as = "text", encoding = "UTF-8")
out <- jsonlite::fromJSON(out)
out <- handle_response(out)
out
}
#' @rdname kb_topics
#' @export
kb_topic <- function(topic_id = "131226a6-a1e9-48a1-a5d0-ac94baf8dfd2", api_key = attackerkb_api_key()) {
httr::GET(
url = sprintf("https://api.attackerkb.com/topics/%s", topic_id[1]),
.ATTACKERKB_UA,
httr::add_headers(`Authorization` = sprintf("basic %s", api_key))
) -> res
httr::stop_for_status(res)
out <- httr::content(res, as = "text", encoding = "UTF-8")
out <- jsonlite::fromJSON(out)
out <- handle_response(out)
out
}
#
# #' @rdname kb_topics
# #' @export
# kb_topics_by_contributor <- function(editor_id = "7191a637-aa4e-4885-98a0-f4f2da285b99", api_key = attackerkb_api_key()) {
#
# httr::GET(
# url = "https://api.attackerkb.com/topics",
# .ATTACKERKB_UA,
# query = list(
# editorId = editor_id[1],
# size = 500L
# ),
# httr::add_headers(`Authorization` = sprintf("basic %s", api_key))
# ) -> res
#
# httr::stop_for_status(res)
#
# out <- httr::content(res, as = "text", encoding = "UTF-8")
# out <- jsonlite::fromJSON(out)
#
# out <- handle_response(out)
#
# out
#
# }
#
# #' @rdname kb_topics
# #' @export
# kb_topics_by_name <- function(q = "bluekeep", api_key = attackerkb_api_key()) {
#
# httr::GET(
# url = "https://api.attackerkb.com/topics",
# .ATTACKERKB_UA,
# query = list(
# name = q[1],
# size = 500L
# ),
# httr::add_headers(`Authorization` = sprintf("basic %s", api_key))
# ) -> res
#
# httr::stop_for_status(res)
#
# out <- httr::content(res, as = "text", encoding = "UTF-8")
# out <- jsonlite::fromJSON(out)
#
# out <- handle_response(out)
#
# out
#
# }
#
# #' @rdname kb_topics
# #' @export
# kb_topics_by_document <- function(q = "bluekeep", api_key = attackerkb_api_key()) {
#
# httr::GET(
# url = "https://api.attackerkb.com/topics",
# .ATTACKERKB_UA,
# query = list(
# document = q[1],
# size = 500L
# ),
# httr::add_headers(`Authorization` = sprintf("basic %s", api_key))
# ) -> res
#
# httr::stop_for_status(res)
#
# out <- httr::content(res, as = "text", encoding = "UTF-8")
# out <- jsonlite::fromJSON(out)
#
# out <- handle_response(out)
#
# out
#
# }
#
#
# #' @rdname kb_topics
# #' @export
# kb_topics_by_content <- function(q = "bluekeep", api_key = attackerkb_api_key()) {
#
# httr::GET(
# url = "https://api.attackerkb.com/topics",
# .ATTACKERKB_UA,
# query = list(
# content = q[1],
# size = 500L
# ),
# httr::add_headers(`Authorization` = sprintf("basic %s", api_key))
# ) -> res
#
# httr::stop_for_status(res)
#
# out <- httr::content(res, as = "text", encoding = "UTF-8")
# out <- jsonlite::fromJSON(out)
#
# out <- handle_response(out)
#
# out
#
# }
#
# #' @rdname kb_topics
# #' @export
# kb_topics_by_metadata <- function(lookup = "bluekeep", api_key = attackerkb_api_key()) {
#
# httr::GET(
# url = "https://api.attackerkb.com/topics",
# .ATTACKERKB_UA,
# query = list(
# metadata = lookup[1],
# size = 500L
# ),
# httr::add_headers(`Authorization` = sprintf("basic %s", api_key))
# ) -> res
#
# httr::stop_for_status(res)
#
# out <- httr::content(res, as = "text", encoding = "UTF-8")
# out <- jsonlite::fromJSON(out)
#
# out <- handle_response(out)
#
# out
#
# }
#
#
# #' @rdname kb_topics
# #' @export
# kb_topics_by_date_created_date <- function(created = "2019-07-04", api_key = attackerkb_api_key()) {
#
# created <- as.Date(created[1])
#
# httr::GET(
# url = "https://api.attackerkb.com/topics",
# .ATTACKERKB_UA,
# query = list(
# created = as.character(created[1]),
# size = 500L
# ),
# httr::add_headers(`Authorization` = sprintf("basic %s", api_key))
# ) -> res
#
# httr::stop_for_status(res)
#
# out <- httr::content(res, as = "text", encoding = "UTF-8")
# out <- jsonlite::fromJSON(out)
#
# out <- handle_response(out)
#
# out
#
# }
#
# #' @rdname kb_topics
# #' @export
# kb_topics_by_date_revised_date <- function(revised = "2019-07-04", api_key = attackerkb_api_key()) {
#
# revised <- as.Date(revised[1])
#
# httr::GET(
# url = "https://api.attackerkb.com/topics",
# .ATTACKERKB_UA,
# query = list(
# revisionDate = as.character(revised[1]),
# size = 500L
# ),
# httr::add_headers(`Authorization` = sprintf("basic %s", api_key))
# ) -> res
#
# httr::stop_for_status(res)
#
# out <- httr::content(res, as = "text", encoding = "UTF-8")
# out <- jsonlite::fromJSON(out)
#
# out <- handle_response(out)
#
# out
#
# }
#
# #' @rdname kb_topics
# #' @export
# kb_topics_by_date_disclosed_date <- function(disclosed = "2019-07-04", api_key = attackerkb_api_key()) {
#
# disclosed <- as.Date(disclosed[1])
#
# httr::GET(
# url = "https://api.attackerkb.com/topics",
# .ATTACKERKB_UA,
# query = list(
# disclosureDate = as.character(disclosed[1]),
# size = 500L
# ),
# httr::add_headers(`Authorization` = sprintf("basic %s", api_key))
# ) -> res
#
# httr::stop_for_status(res)
#
# out <- httr::content(res, as = "text", encoding = "UTF-8")
# out <- jsonlite::fromJSON(out)
#
# out <- handle_response(out)
#
# out
#
# }
#

4
R/utils-infix-helpers.R

@ -0,0 +1,4 @@
`%l0%` <- function(x, y) if (length(x) == 0) y else x
`%||%` <- function(x, y) if (is.null(x)) y else x
`%@%` <- function(x, name) attr(x, name, exact = TRUE)
`%nin%` <- function(x, table) match(x, table, nomatch = 0) == 0

116
R/utils.R

@ -0,0 +1,116 @@
.kb_reshape <- function(.x, path) {
if (path == "/topics") {
easy_cols <- .x[, c("id", "editorId", "name", "created", "revisionDate", "disclosureDate", "document")]
easy_cols$references <- .x[["metadata"]][["references"]]
cvss_v3 <- .x[["metadata"]][["baseMetricV3"]][["cvssV3"]]
easy_cols$cvss_v3_scope <- cvss_v3[["scope"]]
easy_cols$cvss_v3_version <- cvss_v3[["version"]]
easy_cols$cvss_v3_baseScore <- cvss_v3[["baseScore"]]
easy_cols$cvss_v3_attackVector <- cvss_v3[["attackVector"]]
easy_cols$cvss_v3_baseSeverity <- cvss_v3[["baseSeverity"]]
easy_cols$cvss_v3_vectorString <- cvss_v3[["vectorString"]]
easy_cols$cvss_v3_integrityImpact <- cvss_v3[["integrityImpact"]]
easy_cols$cvss_v3_userInteraction <- cvss_v3[["userInteraction"]]
easy_cols$cvss_v3_attackComplexity <- cvss_v3[["attackComplexity"]]
easy_cols$cvss_v3_availabilityImpact <- cvss_v3[["availabilityImpact"]]
easy_cols$cvss_v3_privilegesRequired <- cvss_v3[["privilegesRequired"]]
easy_cols$cvss_v3_confidentialityImpact <- cvss_v3[["confidentialityImpact"]]
easy_cols$cvss_v3_impact <- .x[["metadata"]][["baseMetricV3"]][["impactScore"]]
easy_cols$cvss_v3_exploitability <- .x[["metadata"]][["baseMetricV3"]][["exploitabilityScore"]]
easy_cols$vulnerable_versions <- .x[["metadata"]][["vulnerable-versions"]]
easy_cols$kb_attacker_value <- .x[["score"]][["attackerValue"]]
easy_cols$kb_exploitability <- .x[["score"]][["exploitability"]]
easy_cols$tag_commonEnterprise <- .x$tags[["commonEnterprise"]]
easy_cols$tag_defaultConfiguration <- .x$tags[["defaultConfiguration"]]
easy_cols$tag_difficultToPatch <- .x$tags[["difficultToPatch"]]
easy_cols$tag_highPrivilegeAccess <- .x$tags[["highPrivilegeAccess"]]
easy_cols$tag_easyToDevelop <- .x$tags[["easyToDevelop"]]
easy_cols$tag_requiresInteraction <- .x$tags[["requiresInteraction"]]
easy_cols$tag_obscureConfiguration <- .x$tags[["obscureConfiguration"]]
easy_cols$tag_difficultToExploit <- .x$tags[["difficultToExploit"]]
easy_cols$tag_noUsefulData <- .x$tags[["noUsefulData"]]
easy_cols$tag_difficultToDevelop <- .x$tags[["difficultToDevelop"]]
easy_cols$tag_preAuth <- .x$tags[["preAuth"]]
easy_cols$tag_postAuth <- .x$tags[["postAuth"]]
easy_cols
rownames(easy_cols) <- NULL
easy_cols
} else if (path == "/contributors") {
.x
} else if (path == "/assessments") {
easy_cols <- .x[,c("id", "editorId", "topicId", "created", "revisionDate", "document", "score")]
metadata <- easy_cols[["metadata"]]
easy_cols$tags <- metadata[["tags"]]
easy_cols$attacker_value <- metadata[["attacker-value"]]
easy_cols$exploitability <- metadata[["exploitability"]]
easy_cols$stability <- metadata[["stability"]]
easy_cols$reliability <- metadata[["reliability"]]
easy_cols$urgent_to_patch <- metadata[["urgent-to-patch"]]
easy_cols$used_successfully <- metadata[["used-successfully"]]
easy_cols$mitigation_strength <- metadata[["mitigation-strength"]]
easy_cols$confidence_in_ratings <- metadata[["confidence-in-ratings"]]
easy_cols$effort_to_develop_exploit <- metadata[["effort-to-develop-exploit"]]
easy_cols$versions <- metadata[["versions"]]
easy_cols$mitigation <- metadata[["mitigation"]]
easy_cols$forever_day_versions <- metadata[["forever_day_versions"]]
easy_cols$offensive_application <- metadata[["offensive-application"]]
easy_cols$atacker_utility <- metadata[["atacker-utility"]]
easy_cols$urgent_topatch <- metadata[["urgent-to patch"]]
easy_cols
}
}
handle_response <- function(.x, api_key = attackerkb_api_key()) {
path <- .x[["links"]][["self"]][["href"]]
ret <- .x[["data"]]
ret <- .kb_reshape(ret, path)
next_href <- .x[["links"]][["next"]][["href"]]
while(length(next_href)) {
cat(".")
httr::GET(
url = sprintf("https://api.attackerkb.com%s", next_href),
.ATTACKERKB_UA,
httr::add_headers(`Authorization` = sprintf("basic %s", api_key))
) -> res
httr::stop_for_status(res)
out <- httr::content(res, as = "text", encoding = "UTF-8")
out <- jsonlite::fromJSON(out)
next_href <- out[["links"]][["next"]][["href"]]
ret <- data.table::rbindlist(list(ret, .kb_reshape(out[["data"]], path)), fill = TRUE)
}
cat("\n")
class(ret) <- c("tbl_df", "tbl", "data.frame")
ret
}

71
README.md

@ -0,0 +1,71 @@
[![Project Status: Active – The project has reached a stable, usable
state and is being actively
developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)
[![Signed
by](https://img.shields.io/badge/Keybase-Verified-brightgreen.svg)](https://keybase.io/hrbrmstr)
![Signed commit
%](https://img.shields.io/badge/Signed_Commits-100%25-lightgrey.svg)
[![Linux build
Status](https://travis-ci.org/hrbrmstr/attackerkb.svg?branch=master)](https://travis-ci.org/hrbrmstr/attackerkb)
![Minimal R
Version](https://img.shields.io/badge/R%3E%3D-3.2.0-blue.svg)
![License](https://img.shields.io/badge/License-MIT-blue.svg)
# attackerkb
Tools to Query the Rapid7 AttackerKB API
## Description
Rapid7 manages a service — <https://attackerkb.com/> - where experts can
evaluate various aspects of emergent or existing vulnerabilities and the
community can query and retrieve results. Tools are provides to query
the AttackerKB API.
## What’s Inside The Tin
The following functions are implemented:
- `attackerkb_api_key`: Get or set ATTACKERKB\_API\_KEY value
- `kb_assessments`: Helpers to query AttackerKB assessments
- `kb_contributors`: Helpers to query AttackerKB contributors
- `kb_topics`: Helpers to query AttackerKB topics
## Installation
``` r
remotes::install_git("https://git.rud.is/hrbrmstr/attackerkb.git")
# or
remotes::install_git("https://git.sr.ht/~hrbrmstr/attackerkb")
# or
remotes::install_gitlab("hrbrmstr/attackerkb")
# or
remotes::install_bitbucket("hrbrmstr/attackerkb")
```
NOTE: To use the ‘remotes’ install options you will need to have the
[{remotes} package](https://github.com/r-lib/remotes) installed.
## Usage
``` r
library(attackerkb)
# current version
packageVersion("attackerkb")
## [1] '0.1.0'
```
## attackerkb Metrics
| Lang | \# Files | (%) | LoC | (%) | Blank lines | (%) | \# Lines | (%) |
| :--- | -------: | --: | --: | ---: | ----------: | ---: | -------: | ---: |
| R | 9 | 0.9 | 302 | 0.97 | 96 | 0.86 | 288 | 0.91 |
| Rmd | 1 | 0.1 | 8 | 0.03 | 15 | 0.14 | 28 | 0.09 |
## Code of Conduct
Please note that this project is released with a Contributor Code of
Conduct. By participating in this project you agree to abide by its
terms.

6
man/attackerkb.Rd

@ -4,9 +4,11 @@
\name{attackerkb}
\alias{attackerkb}
\alias{attackerkb-package}
\title{...}
\title{Tools to Query the Rapid7 AttackerKB API}
\description{
A good description goes here otherwise CRAN checks fail.
Rapid7 manages a service — \url{https://attackerkb.com/} - where experts can evaluate
various aspects of emergent or existing vulnerabilities and the community can query and
retrieve results. Tools are provides to query the AttackerKB API.
}
\seealso{
Useful links:

20
man/attackerkb_api_key.Rd

@ -0,0 +1,20 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/api-key.R
\name{attackerkb_api_key}
\alias{attackerkb_api_key}
\title{Get or set ATTACKERKB_API_KEY value}
\usage{
attackerkb_api_key(force = FALSE)
}
\arguments{
\item{force}{Force setting a new AttackerKB key for the current environment?}
}
\value{
atomic character vector containing the AttackerKB api key
}
\description{
The API wrapper functions in this package all rely on a AttackerKB API
key residing in the environment variable \code{ATTACKERKB_API_KEY}.
The easiest way to accomplish this is to set it
in the \code{.Renviron} file in your home directory.
}

50
man/kb_assessments.Rd

@ -0,0 +1,50 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/assessments.R
\name{kb_assessments}
\alias{kb_assessments}
\alias{kb_assessment}
\title{Helpers to query AttackerKB assessments}
\usage{
kb_assessments(
assessment_id = NULL,
editor_id = NULL,
topid_id = NULL,
created = NULL,
revised = NULL,
document = NULL,
metadata = NULL,
score = NULL,
q = NULL,
api_key = attackerkb_api_key()
)
kb_assessment(assessment_id, api_key = attackerkb_api_key())
}
\arguments{
\item{assessment_id}{UUID of a specific assessment to return}
\item{editor_id}{UUID of a contributor.}
\item{topid_id}{UUID of the topic this assessment was based on.}
\item{created}{Return all assessments that were created on the given date.}
\item{revised}{Return all assessments that were revised on the given date.}
\item{document}{Text to query the document attribute. A substring match is performed}
\item{metadata}{Text to query the metadata attribute. A substring match is performed}
\item{score}{Return all assessments with this score.}
\item{q}{Return all assessments that have content that match the query string.}
\item{api_key}{See \code{\link[=attackerkb_api_key]{attackerkb_api_key()}}}
}
\description{
The main \code{kb_contributors} function maps 1:1 to the API. Leave values
\code{NULL} that you do not want included in the search parameters.
}
\references{
\url{https://api.attackerkb.com/api-docs/docs}
}

41
man/kb_contributors.Rd

@ -0,0 +1,41 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/contributor.R
\name{kb_contributors}
\alias{kb_contributors}
\alias{kd_contributor}
\title{Helpers to query AttackerKB contributors}
\usage{
kb_contributors(
contributor_id = NULL,
username = NULL,
avatar = NULL,
created = NULL,
score = NULL,
q = NULL,
api_key = attackerkb_api_key()
)
kd_contributor(contributor_id, api_key = attackerkb_api_key())
}
\arguments{
\item{contributor_id}{UUID of a specific contributror to return}
\item{username}{Return contributors with the matching username.}
\item{avatar}{Return all contributors where avatar matches the given value}
\item{created}{Return all contributors that were created on the given date.}
\item{score}{Return all contributors with this score.}
\item{q}{Return all contributors that have usernames that match the query string.}
\item{api_key}{See \code{\link[=attackerkb_api_key]{attackerkb_api_key()}}}
}
\description{
The main \code{kb_contributors} function maps 1:1 to the API. Leave values
\code{NULL} that you do not want included in the search parameters.
}
\references{
\url{https://api.attackerkb.com/api-docs/docs}
}

56
man/kb_topics.Rd

@ -0,0 +1,56 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/topics.R
\name{kb_topics}
\alias{kb_topics}
\alias{kb_topic}
\title{Helpers to query AttackerKB topics}
\usage{
kb_topics(
topic_id = NULL,
editor_id = NULL,
name = NULL,
created = NULL,
revised = NULL,
disclosed = NULL,
document = NULL,
metadata = NULL,
featured = NULL,
q = NULL,
api_key = attackerkb_api_key()
)
kb_topic(
topic_id = "131226a6-a1e9-48a1-a5d0-ac94baf8dfd2",
api_key = attackerkb_api_key()
)
}
\arguments{
\item{topic_id}{UUID of a specific topic to return}
\item{editor_id}{UUID of a contributor}
\item{name}{Text to query the name attribute. A substring match is performed}
\item{created}{Return all topics that were created on the given date.}
\item{revised}{Return all topics that were revised on the given date.}
\item{disclosed}{Return all topics that were disclosed on the given date.}
\item{document}{Text to query the document attribute. A substring match is performed}
\item{metadata}{Text to query the metadata attribute. A substring match is performed}
\item{featured}{(lgl) \code{TRUE}/\code{FALSE}. Return all topics that are featured.}
\item{q}{Return all topics that have content that matches the query string.}
\item{api_key}{See \code{\link[=attackerkb_api_key]{attackerkb_api_key()}}}
}
\description{
The main \code{kb_topics} function maps 1:1 to the API. Leave values
\code{NULL} that you do not want included in the search parameters.
}
\references{
\url{https://api.attackerkb.com/api-docs/docs}
}
Loading…
Cancel
Save