Skip to content

Instantly share code, notes, and snippets.

@ribsy
Created April 19, 2022 02:49
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ribsy/7570d3b8b68b59792c220bb9486335d2 to your computer and use it in GitHub Desktop.
Save ribsy/7570d3b8b68b59792c220bb9486335d2 to your computer and use it in GitHub Desktop.
# Package names
packages <- c("readr", "tidyverse", "lubridate", "survival", "survminer", "shiny", "shinydashboard","reactable","shinyalert")
# Install packages not yet installed
installed_packages <- packages %in% rownames(installed.packages())
if (any(installed_packages == FALSE)) {
install.packages(packages[!installed_packages])
}
# Packages loading
invisible(lapply(packages, library, character.only = TRUE))
GetSearchButton <- function(){
return(div(style="display:inline-block; width:43%;text-align: left;",actionButton("search", "Search Dates")))
}
GetResetButton <- function(){
return(div(style="display:inline-block; width:43%;text-align: left;",actionButton("reset", "Reset Values")))
}
GetUpdatedVulnData <- function(df){
min_date <- min(mdy(df$discovered_date))
max_date <- max(mdy(df$last_scan_date))
#Fetch Data from data()
vuln_update <- UpdateVulnData(df, min_date, max_date)
return(vuln_update)
}
PlotPois <- function(df){
gf <- goodfit(df, "poisson")
return (plot(gf, type = "standing", scale = "raw"))
}
GetPoisVals <- function(v){
gs <- GetGammaParams(v)
res <- rpois(n=100, lambda=rgamma(100, shape=gs[2],scale=gs[1]))
return(mean(res))
}
GetGammaParams <- function(v){
#Requires fitdistplus
fg <- fitdist(v, "gamma", lower=c(0,0), start=list(scale=1,shape=1))
return(fg$estimate)
}
UpdateVulnData <- function(vmd, start, end){
#message("The value of start_date is ", start_date)
vuln_data <- vmd %>% filter( mdy(discovered_date) >= start & mdy(last_scan_date) <= end )
return(vuln_data)
}
GetVulnTable <- function(vmd, status){
vtable <- vmd %>% select(severity, remediation_status, vulnerability_title, cvss_score, risk, ip_address, diff_date,
discovered_date, last_scan_date, func_code, server_type, site_code, environment_type) %>%
filter(remediation_status == status) %>%
mutate(diff_date = as.numeric(diff_date))
vtable <- vtable %>% rename(title = vulnerability_title, function.code = func_code, ip = ip_address,
first.seen = discovered_date, last.seen = last_scan_date, time.open = diff_date,
server.type = server_type, site.code = site_code, env.type = environment_type,
status = remediation_status, cvss = cvss_score)
return(vtable)
}
GetFileData <- function(file_val){
csv = vroom::vroom(file_val$datapath, delim = ",")
df <- CleanVulnData(csv)
return(df)
}
GetTTLBox <- function(severity, vmd){
fixed <- GetTimesByAsset(vmd, min(vmd$discovered_date), max(vmd$last_scan_date), "REMEDIATED", c(severity))
not_fixed <- GetAvgOpenTime(vmd, min(mdy(vmd$discovered_date)), max(mdy(vmd$last_scan_date)), c(severity))
infoBox(
paste0(severity ," Time To Live Rates"), paste0(fixed$ratio_val,"% Closed Vuln < ", fixed$fifty_or_less, "D ",fixed$change_text), icon = icon(fixed$icon_name),
color = fixed$color_val, subtitle = paste0(not_fixed$ratio_val,"% of Open < ", not_fixed$fifty_less,"D | Max Open: ", not_fixed$max_days_total, "D")
)
}
GetCountBox <- function(severity, vulns){
icon_val <- "user-secret"
if( vulns$vuln_count <= vulns$vuln_count_lweek){
color_val <- "green"
diff_text <- "Decrease"
}else if(abs(vulns$vuln_diff) <= 5){
color_val <- "yellow"
diff_text <- "Increase"
}else{
color_val <- "red"
diff_text <- "Increase"
}
res <- infoBox(
paste0(severity," Open Vulnerabilities"), paste0(vulns$vuln_count, " Open Now (", vulns$vuln_diff,"% ", diff_text ,")"), icon = icon(icon_val),
color = color_val, subtitle = paste0("-1W: ", vulns$vuln_count_lweek, " | -1M: ", vulns$vuln_count_lmonth, " | Uniq: ", vulns$vuln_count_unique )
)
return(res)
}
GetBurndownBox <- function(severity, vmd, kpi = .95, mode){
crit_rates <- RateValues(vmd, severity, kpi)
kpi_success_rate <- 100 - round(crit_rates$fail_rates[length(crit_rates$fail_rates)] * 100)
crvals <- InfoBoxRateConfig(crit_rates$rates)
kpi_trend <- GetBestKPI(vmd, severity) * 100
kpi_diff <- (kpi * 100) - kpi_trend
diff_val <- crvals$diff
fill_val <- FALSE
#Adjust colors for KPI slider activity
if( mode == "kpi" ){
fill_val <- TRUE
if(kpi_success_rate <= 25){
crvals$color_val <- "red"
}else if(kpi_success_rate > 25 & kpi_success_rate <= 75){
crvals$color_val <- "yellow"
}else{
crvals$color_val <- "green"
}
}
if( mode == "mixed"){
fill_val <- TRUE
message("In Mixed Diff Val: ", diff_val, " KPI Success RateL ", kpi_success_rate )
if( diff_val < 0 & kpi_success_rate <= 25){
crvals$color_val <- "red"
}else if(kpi_success_rate <= 100 & diff_val < 0){
crvals$color_val <- "yellow"
}else{
crvals$color_val <- "green"
}
}
if(mode == "kpi" | mode == "mixed"){
ret_val <- infoBox(
paste0(severity," Vulnerability Burndown Rate"),
paste0(kpi * 100, "% KPI (",kpi_success_rate,"% Met)"),
icon = icon(crvals$icon_name),
color = crvals$color_val,
fill = fill_val,
subtitle = paste0(crvals$rate_now ,"% Burn ", crvals$change_text," -",crvals$one_mon,"W: ", crvals$rate_last_mn,"% | -",crvals$two_mon,"W: ",
crvals$rate_prev_mn,"%" )
)
}else{
ret_val <- infoBox(
paste0(severity," Vulnerability Burndown Rate"),
paste0(crvals$rate_now, "% Now ", crvals$change_text),
icon = icon(crvals$icon_name),
color = crvals$color_val,
fill = fill_val,
subtitle = paste0("-",crvals$one_mon,"W: ", crvals$rate_last_mn,"% | -",crvals$two_mon,"W: ",
crvals$rate_prev_mn,"% | ", kpi * 100 ,"% Goal: ", kpi_success_rate,"% Met")
)
}
return(ret_val)
}
GetVulnVariables <- function(vmd){
vulns <- list()
#Crit Vulns
vulns[["critical"]][["vuln_count"]] <- GetVulnCount(vmd, c("Critical"))
vulns[["critical"]][["vuln_count_unique"]] <- GetVulnCountUnique(vmd, c("Critical"))
vulns[["critical"]][["vuln_count_lweek"]] <- GetVulnCountPast(vmd, c("Critical"), 7)
vulns[["critical"]][["vuln_diff"]] <- GetVulnDiff(vulns$critical$vuln_count, vulns$critical$vuln_count_lweek)
vulns[["critical"]][["vuln_count_lmonth"]] <- GetVulnCountPast(vmd, c("Critical"), 30)
#Severe Vulns
vulns[["severe"]][["vuln_count"]] <- GetVulnCount(vmd, c("Severe"))
vulns[["severe"]][["vuln_count_unique"]] <- GetVulnCountUnique(vmd, c("Severe"))
vulns[["severe"]][["vuln_count_lweek"]] <- GetVulnCountPast(vmd, c("Severe"), 7)
vulns[["severe"]][["vuln_diff"]] <- GetVulnDiff(vulns$severe$vuln_count, vulns$severe$vuln_count_lweek)
vulns[["severe"]][["vuln_count_lmonth"]] <- GetVulnCountPast(vmd, c("Severe"), 30)
#Moderate Vulns
vulns[["moderate"]][["vuln_count"]] <- GetVulnCount(vmd, c("Moderate"))
vulns[["moderate"]][["vuln_count_unique"]] <- GetVulnCountUnique(vmd, c("Moderate"))
vulns[["moderate"]][["vuln_count_lweek"]] <- GetVulnCountPast(vmd, c("Moderate"), 7)
vulns[["moderate"]][["vuln_diff"]] <- GetVulnDiff(vulns$moderate$vuln_count, vulns$moderate$vuln_count_lweek)
vulns[["moderate"]][["vuln_count_lmonth"]] <- GetVulnCountPast(vmd, c("Moderate"), 30)
return(vulns)
}
CleanVulnData <- function(vmd){
print_cols <- c(
"asset_id: Integer",
"ip_address: 10.97.2.67",
"scan_finished: MM/DD/YY",
"host_name: dash delim text like: SAL-VS-COMMWFE1",
"vulnerability_title: Text",
"severity: Critical, Severe, Moderate",
"vulnerability_id: Integer",
"cvss_score: numbers like 4.5, 9.5 etc",
"risk: Integer",
"remediation_status: REMEDIATED, NOT_REMEDIATED",
"discovered_date: MM/DD/YY",
"last_scan_date: : MM/DD/YY"
)
required_columns <- c('asset_id', 'ip_address', 'scan_finished', 'host_name', 'vulnerability_title',
'severity', 'vulnerability_id', 'cvss_score', 'risk', 'remediation_status',
'discovered_date', 'last_scan_date')
column_names <- colnames(vmd)
max_columns <- 12
ncol_vmd <- ncol(vmd)
if( ncol_vmd != max_columns){
print_cols <- c(" ",print_cols)
col_str <- paste(print_cols,collapse = "\n",sep="")
return(paste("Error: Uploaded data must have 12 columns.\nRequired Cols:", col_str))
}
dvals <- setdiff(required_columns,column_names)
if( length(dvals) >= 1){
dvals <- c(" ", dvals)
col_str <- paste(dvals,collapse = "\n",sep="")
return(paste("Error: Missing Colums:", col_str))
}
#### Depricated - but useful if you have meaningful host names
## That can be split by a delimiter into useful components
## I put in dummy data for now.
#hn <- str_split(vmd$host_name,"-",simplify = TRUE)
#Get first portion (site code) of host name
vmd <- vmd %>% mutate(site_code = "Unknown")
#Get Second Section of Host name and create columns
stenv <- "test"
vmd <- GetServerType(vmd, stenv)
vmd <- GetEnvType(vmd, stenv)
#Get Third portion of host name and create columns
stcode <- "test"
vmd <- GetAppCode(vmd, stcode)
vmd <- GetFunCode(vmd, stcode)
#Create Columns with first portion of host name
#fp <- str_split(stcode,"\\.",simplify = TRUE)
vmd <- vmd %>% mutate(fqdn_first = "test")
#If Last Scan Date Is Empty - Put Max Date
vmd <- SetRemediatedClosedDate(vmd)
#Add +1 so that a vulnerability discovered and closed on the same day is 1
vmd <- vmd %>% mutate( diff_date = (mdy(last_scan_date) - mdy(discovered_date) + 1))
#print(vmd)
return(vmd)
}
GetBestKPI <- function(vmd, severity){
hit_vals <- GetCountByAsset(vmd,min(vmd$discovered_date), max(vmd$last_scan_date), "REMEDIATED", c(severity))
miss_vals <- GetCountByAsset(vmd,min(vmd$discovered_date), max(vmd$last_scan_date), "NOT_REMEDIATED", c(severity))
for(i in 100:1){
rate <- i/100
#Really this is success rate...but anyway....
fail_rate_vals <- GetFailRates(rate, hit_vals$n, miss_vals$n)
max_fail <- fail_rate_vals[length(fail_rate_vals)]
kpi_fail_rate <- 100 - round(max_fail * 100)
if(kpi_fail_rate == 100){
return(rate)
}
}
}
GetSurvData <- function(vmd){
vmd <- vmd %>% select(diff_date, remediation_status, severity) %>%
mutate(status = ifelse(remediation_status == "NOT_REMEDIATED",0,1),
diff_date = as.numeric(diff_date)) %>%
select(diff_date, status, severity)
#paste0("res:", head(res_val,10))
t_surv <- survfit(data = vmd, Surv(vmd$diff_date, vmd$status) ~ vmd$severity)
return(t_surv)
}
GetSurvPlot <- function(vmd){
#t_surv <- GetSurvData(vmd)
res <- vmd %>% select(diff_date, remediation_status, severity) %>%
mutate(status = ifelse(remediation_status == "NOT_REMEDIATED",0,1),
diff_date = as.numeric(diff_date)) %>%
select(diff_date, status, severity)
#paste("VMD: ", vmd)
t_surv <- surv_fit(data = res, Surv(diff_date, status) ~ severity)
#print(t_surv)
surv_plot <- ggsurvplot(t_surv,
conf.int = TRUE,
risk.table.col = "strata", # Change risk table color by groups
ggtheme = theme_light(), # Change ggplot2 theme
palette = c("coral3", "darkorange","deepskyblue4"),
risk.table = "abs_pct",
risk.table.y.text.col = T,
fun = "event")
return(surv_plot)
}
SetRemediatedClosedDate <- function(vmd){
m_date <- max(mdy(vmd[!is.na(vmd$last_scan_date),"last_scan_date"][[1]]))
m_date <- format(m_date, "%m/%d/%y")
m_date <- sub("^0", "", m_date)
vmd[is.na(vmd$last_scan_date),"last_scan_date"] <- as.character(m_date)
return(vmd)
}
TimeValues <- function(vmd, severity){
hit_vals <- GetTimesByAsset(vmd,min(vmd$discovered_date), max(vmd$last_scan_date), "REMEDIATED", c(severity))
miss_vals <- GetTimesByAsset(vmd,min(vmd$discovered_date), max(vmd$last_scan_date), "NOT_REMEDIATED", c(severity))
rate_vals <- round(cumsum(hit_vals$n)/(cumsum(miss_vals$n) + cumsum(hit_vals$n)) ,2) * 100
fail_rate_vals <- GetFailRates(kpi, hit_vals$n, miss_vals$n)
rate_return <- tibble(
hits = hit_vals,
misses = miss_vals,
rates = rate_vals,
fail_rates = fail_rate_vals
)
return(rate_return)
}
GetAvgOpenTime_test <- function(vmd, start, end, sev){
print(paste("Start: ", start, " End: ", end))
res <- vmd %>% select(asset_id, vulnerability_id, severity,risk, discovered_date, last_scan_date, remediation_status, diff_date) %>%
filter(remediation_status == "NOT_REMEDIATED" & severity %in% sev) %>%
filter(mdy(discovered_date) >= start & mdy(last_scan_date) <= end) %>% distinct()
return(res)
time_val <- table(res$diff_date)
#print(paste("Time Val: ", time_val))
time_tib <- tibble(
day_val = as.numeric(names(time_val)),
vuln_count = as.vector(time_val),
sum_val = cumsum(vuln_count),
day_ratio = round(sum_val / sum(vuln_count) * 100,1)
)
#print(paste("Time Tib: ", time_tib))
if ( min(time_tib$day_ratio) > 50 ){
ratio_val <- min(time_tib$day_ratio)
}else{
ratio_val <- 50
}
fifty_less <- max(time_tib[time_tib$day_ratio <= ratio_val,]$day_val)
max_days_total <- max(time_tib$day_val)
ret_tibble <- tibble(
fifty_less = fifty_less,
max_days_total = max_days_total
)
return(ret_tibble)
}
GetAvgOpenTime <- function(vmd, start, end, sev){
res <- vmd %>% select(asset_id, vulnerability_id, severity,risk, discovered_date, last_scan_date, remediation_status, diff_date) %>%
filter(remediation_status == "NOT_REMEDIATED" & severity %in% sev) %>%
filter(mdy(discovered_date) >= start & mdy(last_scan_date) <= end) %>% distinct()
time_val <- table(res$diff_date)
#print(paste("Time Val: ", time_val))
time_tib <- tibble(
day_val = as.numeric(names(time_val)),
vuln_count = as.vector(time_val),
sum_val = cumsum(vuln_count),
day_ratio = round(sum_val / sum(vuln_count) * 100,1)
)
#print(paste("Time Tib: ", time_tib))
if ( min(time_tib$day_ratio) > 50 ){
ratio_val <- min(time_tib$day_ratio)
}else{
ratio_val <- 50
}
fifty_less <- max(time_tib[time_tib$day_ratio <= ratio_val,]$day_val)
max_days_total <- max(time_tib$day_val)
ret_tibble <- tibble(
fifty_less = fifty_less,
max_days_total = max_days_total,
ratio_val = ratio_val
)
return(ret_tibble)
}
GetTimesByAsset_test <- function(vmd, start, end, rem_status, sev){
res <- vmd %>% select(asset_id, vulnerability_id, severity,risk, discovered_date, last_scan_date, remediation_status, diff_date) %>%
filter(remediation_status == rem_status & severity %in% sev) %>%
filter(mdy(discovered_date) >= mdy(start) & mdy(last_scan_date) <= mdy(end)) %>% distinct()
time_val <- table(res$diff_date)
#return(res)
time_tib <- tibble(
day_val = as.numeric(names(time_val)),
vuln_count = as.vector(time_val),
sum_val = cumsum(vuln_count),
day_ratio = round(sum_val / sum(vuln_count) * 100,1)
)
if(max(res$diff_date) < 30){
sub_days <- round(max(res$diff_date)/2)
}else{
sub_days <- 30
}
print(paste("Sub Days: ", sub_days))
return(time_tib)
thirty_days <- res %>% select(asset_id, vulnerability_id, discovered_date, last_scan_date, diff_date) %>%
filter(mdy(last_scan_date) < max(mdy(last_scan_date)) - sub_days)
prior_val <- table(thirty_days$diff_date)
prior_tib <- tibble(
day_val = as.numeric(names(prior_val)),
vuln_count = as.vector(prior_val),
sum_val = cumsum(vuln_count),
day_ratio = round(sum_val / sum(vuln_count) * 100,1)
)
#return(prior_tib)
}
GetTimesByAsset <- function(vmd, start, end, rem_status, sev){
#Build A Table Object and Tibble to Hold First REsults
res <- vmd %>% select(asset_id, vulnerability_id, severity,risk, discovered_date, last_scan_date, remediation_status, diff_date) %>%
filter(remediation_status == rem_status & severity %in% sev) %>%
filter(mdy(discovered_date) >= mdy(start) & mdy(last_scan_date) <= mdy(end)) %>% distinct()
time_val <- table(res$diff_date)
#Current Tibb
time_tib <- tibble(
day_val = as.numeric(names(time_val)),
vuln_count = as.vector(time_val),
sum_val = cumsum(vuln_count),
day_ratio = round(sum_val / sum(vuln_count) * 100,1)
)
if(max(res$diff_date) < 30){
sub_days <- round(max(res$diff_date)/2)
}else{
sub_days <- 30
}
#Make A Second Result Set For 30 days ago
thirty_days <- res %>% select(asset_id, vulnerability_id, discovered_date, last_scan_date, diff_date) %>%
filter(mdy(last_scan_date) < max(mdy(last_scan_date)) - sub_days)
prior_val <- table(thirty_days$diff_date)
#print(paste("Prior Val: ", prior_val))
#For 30 days ago
prior_tib <- tibble(
day_val = as.numeric(names(prior_val)),
vuln_count = as.vector(prior_val),
sum_val = cumsum(vuln_count),
day_ratio = round(sum_val / sum(vuln_count) * 100,1)
)
#print(paste("Prior TIB: ", prior_tib))
if ( min(time_tib$day_ratio) > 50 ){
ratio_val <- min(time_tib$day_ratio)
}else{
ratio_val <- 50
}
if ( min(prior_tib$day_ratio) > 50 ){
prior_ratio_val <- min(prior_tib$day_ratio)
}else{
prior_ratio_val <- 50
}
fifty_less <- max(time_tib[time_tib$day_ratio <= ratio_val,]$day_val)
#ninety_less <- max(time_tib[time_tib$day_ratio <= 90,]$day_val)
max_days_total <- max(time_tib$day_val)
thirty_days_ago <- max(prior_tib[prior_tib$day_ratio <= prior_ratio_val,]$day_val)
diff_val <- thirty_days_ago - fifty_less
if(diff_val >= 0){
color_val = "green"
if( diff_val == 0){
change_text <- ""
}else{
change_text <- paste0("(",diff_val,"D -)")
}
icon_name <- "clock"
}else if(diff_val >= -5){
color_val = "yellow"
change_text <- paste0("(",abs(diff_val),"D +)")
icon_name <- "clock"
}else{
color_val = "red"
change_text <- paste0("(",abs(diff_val),"D +)")
icon_name <- "clock"
}
ret_tib <- tibble(
fifty_or_less = fifty_less,
#ninety_or_less = ninety_less,
max_days = max_days_total,
thirty_d_prior = thirty_days_ago,
color_val = color_val,
change_text = change_text,
icon_name = icon_name,
ratio_val = ratio_val,
prior_ratio_val = prior_ratio_val
)
return(ret_tib)
}
GetKpiRate <- function(crit_rates){
last_fail_rate <- crit_rates$fail_rates[length(crit_rates$fail_rates)]
kpi_fail_rate <- 100 - round(last_fail_rate * 100)
return(kpi_fail_rate)
}
RateValues <- function(vmd, severity, kpi){
hit_vals <- GetCountByAsset(vmd,min(vmd$discovered_date), max(vmd$last_scan_date), "REMEDIATED", c(severity))
miss_vals <- GetCountByAsset(vmd,min(vmd$discovered_date), max(vmd$last_scan_date), "NOT_REMEDIATED", c(severity))
rate_vals <- round(cumsum(hit_vals$n)/(cumsum(miss_vals$n) + cumsum(hit_vals$n)) ,2) * 100
fail_rate_vals <- GetFailRates(kpi, hit_vals$n, miss_vals$n)
rate_return <- tibble(
hits = hit_vals,
misses = miss_vals,
rates = rate_vals,
fail_rates = fail_rate_vals
)
return(rate_return)
}
InfoBoxRateConfig <- function(rate_vals){
r_len <- length(rate_vals)
one_mon <- 4
two_mon <- 8
if( r_len < 9){
one_mon <- round(r_len/2) #It's suppose to be a month...but it may be short
two_mon <- r_len - 1 #It's suppose to be two month...but it may be short
}
rate_val_now <- rate_vals[r_len]
rate_val_last_mn <- rate_vals[r_len - one_mon]
rate_val_prev_mn <- rate_vals[r_len - two_mon]
diff_val <- rate_val_now - rate_val_last_mn
if(diff_val >= 0){
color_val = "green"
change_text <- paste0("(",diff_val,"% Increase)")
icon_name <- "fire-alt"
}else if(diff_val >= -5){
color_val = "yellow"
change_text <- paste0("(",abs(diff_val),"% Decrease)")
icon_name <- "fire-alt"
}else{
color_val = "red"
change_text <- paste0("(",abs(diff_val),"% Decrease)")
icon_name <- "fire-alt"
}
if(r_len < 13 & r_len > 6){
msg_val <- paste0(r_len, " weeks SMALL data")
}else if(r_len < 6){
msg_val <- paste0(r_len, " weeks TINY data")
}else{
msg_val <- paste0(r_len, " weeks data")
}
#For now, hold off on this - could confuse the user
msg_val <- ""
rates <- tibble(
rate_now = rate_val_now,
rate_last_mn = rate_val_last_mn,
rate_prev_mn = rate_val_prev_mn,
diff = diff_val,
color_val = color_val,
change_text = change_text,
icon_name = icon_name,
one_mon = one_mon,
two_mon = two_mon,
msg_val = msg_val
)
return(rates)
}
GetVulnDiff <- function(new, old){
diff <- new - old
diff_rate <- round(diff / old,2) * 100
return(diff_rate)
}
GetVulnCountPast <- function(vmd, severity_val, delay){
#While the record may say remediated, the last date it was found is LATER than the day we are asking for.
# So, we may has for 30 days ago, but this record was actually found fixed 10 days ago...for example
critical_vulns_rem <- vmd %>% select(asset_id, vulnerability_id, severity, remediation_status,last_scan_date) %>%
filter(remediation_status == "REMEDIATED" & severity %in% severity_val & (mdy(last_scan_date) > max(mdy(vmd$last_scan_date)) - delay))
critical_vulns_rem <- unique(critical_vulns_rem)
critical_vuln_count_rem <- count(critical_vulns_rem)
#vuln still not remediated and its discovery date is before the time being asked for.
critical_vulns_not <- vmd %>% select(asset_id, vulnerability_id, severity, remediation_status, discovered_date) %>%
filter(remediation_status == "NOT_REMEDIATED" & severity %in% severity_val & (mdy(discovered_date) < max(mdy(vmd$last_scan_date)) - delay))
critical_vulns_not <- unique(critical_vulns_not)
critical_vuln_count_not <- count(critical_vulns_not)
return(critical_vuln_count_rem + critical_vuln_count_not)
}
GetVulnCountUnique <- function(vmd,severity_val){
critical_vulns <- vmd %>% select(vulnerability_id, severity, remediation_status) %>%
filter(remediation_status == "NOT_REMEDIATED" & severity %in% severity_val)
critical_vulns <- unique(critical_vulns)
critical_vuln_count <- count(critical_vulns)
return(critical_vuln_count)
}
GetVulnCount <- function(vmd,severity_val){
critical_vulns <- vmd %>% select(asset_id, vulnerability_id, severity, remediation_status) %>%
filter(remediation_status == "NOT_REMEDIATED" & severity %in% severity_val)
critical_vulns <- unique(critical_vulns)
critical_vuln_count <- count(critical_vulns)
return(critical_vuln_count)
}
GetFailRates <- function(KPIRate, hits, misses){
fail_rate <- round(pbeta(KPIRate, cumsum(hits), cumsum(misses)),3)
#qvalue <- cummean(arrange(fail_rate))
#qvalue <- round(cummean(sort(fail_rate)),4)
return(fail_rate)
}
GetWeekYears <- function(start_year, cur_date){
cur_date <- mdy(cur_date)
cur_year <- year(cur_date)
start_year_add <- (cur_year - start_year) * 52
week_val <- week(cur_date) + start_year_add
#print(paste("Week Val: ", week_val))
return(week_val)
}
GetCountByVuln <- function(vmd, start, end, remediation_state, sev = c("Severe","Critical","Moderate"), risk_score = 0){
#We are creating a week over week cummulative count of discovered vulnerabilties.
#And they are all within a time range in terms of when they are discovered.
#Week #, Vuln Count
#Adjust for multiple year span - add multiples of 52 to account of yeach additional year from a baseline min_year
min_year <- min(year(mdy(vmd$discovered_date)))
start_year <- year(mdy(start))
start_year_add <- (start_year - min_year) * 52 # Number of weeks to add to start week
end_year <- year(mdy(end))
end_year_add <- (end_year - min_year) * 52 # Number of weeks to add to end week.
start_week <- week(mdy(start)) + start_year_add
end_week <- week(mdy(end)) + end_year_add
#print(paste("Start Week: ", start_week))
#print(paste("End Week: ", end_week))
rem_val <- vmd %>% select(vulnerability_id, severity,risk, discovered_date, last_scan_date, remediation_status) %>%
filter(mdy(discovered_date) >= mdy(start) & mdy(discovered_date) <= mdy(end)) %>%
#Need to create dataframe columns to hold the week number for discovery and last scan
mutate(week_disc = GetWeekYears(min_year, discovered_date)) %>%
mutate(week_last = GetWeekYears(min_year, last_scan_date)) %>%
select(vulnerability_id, severity,risk, remediation_status, week_disc, week_last) %>%
filter(remediation_status == remediation_state & severity %in% sev) %>%
filter(risk >= risk_score) %>%
distinct() %>%
group_by(week = week_disc) %>%
tally()
#print(paste("Rem Val: ", rem_val))
#This creates a simple data frame with a week index starting with the
# starting week and the ending week.
# Pre load the count field (n) with 0x
res <- tibble(
week = start_week:end_week,
n = 0
)
#print(paste("Res Tibble: ", res))
#Get the weeks that are missing in rem_val and give them 0s for counts
missing_vals <- res %>% anti_join(rem_val, by = "week")
rem_val <- rbind(rem_val,missing_vals) #Bind it all together as a whole set of weeks with counts
rem_val <- arrange(rem_val, week) #Rank order buy week.
return(rem_val)
}
GetCountByAsset <- function(vmd, start, end, remediation_state, sev = c("Severe","Critical","Moderate"), risk_score = 0){
#Largely the same as above, but more voluminous due to vuln and asset_id
min_year <- min(year(mdy(vmd$discovered_date)))
start_year <- year(mdy(start))
start_year_add <- (start_year - min_year) * 52 # Number of weeks to add to start week
end_year <- year(mdy(end))
end_year_add <- (end_year - min_year) * 52 # Number of weeks to add to end week.
start_week <- week(mdy(start)) + start_year_add
end_week <- week(mdy(end)) + end_year_add
#Query
rem_val <- vmd %>% select(asset_id, vulnerability_id, severity,risk, discovered_date, last_scan_date, remediation_status) %>%
filter(remediation_status == remediation_state & severity %in% sev) %>%
filter(risk >= risk_score) %>%
filter(mdy(discovered_date) >= mdy(start) & mdy(discovered_date) <= mdy(end)) %>%
#group_by(week = week(mdy(discovered_date))) %>%
group_by(week = GetWeekYears(min_year, discovered_date)) %>%
tally()
#A Tibble To Hold Results To Fix Missing Values
res <- tibble(
week = start_week:end_week,
n = 0
)
#Get Missing Values, Merge, Sort
missing_vals <- res %>% anti_join(rem_val, by = "week")
rem_val <- rbind(rem_val,missing_vals)
rem_val <- arrange(rem_val, week)
return(rem_val)
}
#Server Type
GetServerType <- function(vmd, stenv){
# Function Code (if needed)
# Overwrite here to "Unknown" but could include options as seen below...
vmd <- vmd %>% mutate(server_type = "Unknown")
# vmd$server_type[grep("^P|^S",stenv,ignore.case = TRUE)] <- "Server"
# vmd$server_type[grep("^V",stenv, ignore.case = TRUE)] <- "Virtual"
return(vmd)
}
#Env Type
GetEnvType <- function(vmd, stenv){
# Function Code (if needed)
# Overwrite here to "Unknown" but could include options as seen below...
vmd <- vmd %>% mutate(environment_type = "Unknown")
# vmd$environment_type[grep("DZ",stenv,ignore.case = TRUE)] <- "DMZ"
# vmd$environment_type[grep("ST",stenv,ignore.case = TRUE)] <- "Staging"
# vmd$environment_type[grep("X",stenv,ignore.case = TRUE)] <- "Sandbox"
# vmd$environment_type[grep("Q",stenv,ignore.case = TRUE)] <- "QA"
# vmd$environment_type[grep("U",stenv,ignore.case = TRUE)] <- "UAT"
# vmd$environment_type[grep("D",stenv,ignore.case = TRUE)] <- "Dev"
return(vmd)
}
GetAppCode <- function(vmd,stcode){
# Function Code (if needed)
# Overwrite here to "Unknown" but could include options as seen below...
vmd <- vmd %>% mutate(app_code = "Unknown")
# vmd$app_code[grep("CRD",stcode,ignore.case = TRUE)] <- "CARD Systems"
# vmd$app_code[grep("HRM",stcode,ignore.case = TRUE)] <- "HR Systems"
# vmd$app_code[grep("TPC",stcode,ignore.case = TRUE)] <- "Third Party Cloud"
return(vmd)
}
GetFunCode <- function(vmd,stcode){
# Function Code (if needed)
# Overwrite here to "Unknown" but could include options as seen below...
vmd <- vmd %>% mutate(func_code = "Unknown")
# vmd$func_code[grep("APP",stcode,ignore.case = TRUE)] <- "Application Server"
# vmd$func_code[grep("DB",stcode,ignore.case = TRUE)] <- "Database Server"
# vmd$func_code[grep("WEB",stcode,ignore.case = TRUE)] <- "Web Server"
# vmd$func_code[grep("HI",stcode,ignore.case = TRUE)] <- "Host Interface"
# vmd$func_code[grep("MBL",stcode,ignore.case = TRUE)] <- "Mobile"
# vmd$func_code[grep("SQL",stcode,ignore.case = TRUE)] <- "SQL"
# vmd$func_code[grep("WFE",stcode,ignore.case = TRUE)] <- "Web Front End"
# vmd$func_code[grep("apig",stcode,ignore.case = TRUE)] <- "API Gateway"
# vmd$func_code[grep("dhcp",stcode,ignore.case = TRUE)] <- "DHCP"
return(vmd)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment