boB Rudis
4 years ago
19 changed files with 955 additions and 8 deletions
@ -0,0 +1,2 @@ |
|||
YEAR: 2020 |
|||
COPYRIGHT HOLDER: Bob Rudis |
@ -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. |
@ -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) |
|||
|
@ -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 |
@ -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 |
|||
|
|||
} |
@ -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 |
|||
|
|||
|
|||
} |
@ -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" |
|||
|
@ -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 |
|||
|
|||
|
|||
} |
@ -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 |
|||
# |
|||
# } |
|||
# |
@ -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 |
@ -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 |
|||
|
|||
} |
@ -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. |
@ -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. |
|||
} |
@ -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} |
|||
} |
@ -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} |
|||
} |
@ -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…
Reference in new issue