Accept CVSS strings in finding creation

This commit is contained in:
2026-08-24 15:51:44 +02:00
parent a74aa0fb8a
commit febe95f7a5
5 changed files with 123 additions and 51 deletions
+48 -15
View File
@@ -32,8 +32,7 @@
table.cell(riskCategories.at(status).title, fill: riskCategories.at(status).color, align: center)
}
// Create a small CIA table to be included for every finding
#let createTable(attackVector: "-", attackComplexity: "-", privilegesRequired: "-", userInteraction: "-", scope: "-", confidentiality: "-", integrity: "-", availability: "-") = {
#let score(attackVector: "-", attackComplexity: "-", privilegesRequired: "-", userInteraction: "-", scope: "-", confidentiality: "-", integrity: "-", availability: "-") = {
// Check values
panicOnInvalid(attackVector, ("N", "A", "L", "P", "-"))
panicOnInvalid(attackComplexity, ("L", "H", "-"))
@@ -44,7 +43,6 @@
panicOnInvalid(integrity, ("H", "L", "N", "-"))
panicOnInvalid(availability, ("H", "L", "N", "-"))
let status = "?"
if((attackVector, attackComplexity, privilegesRequired, userInteraction, scope, confidentiality, integrity, availability).find(x => x == "-") == none) {
// Calculate base result, see https://www.first.org/cvss/v3-1/specification-document#7-1-Base-Metrics-Equations
let issLookup = ("H": 0.56, "L": 0.22, "N": 0)
@@ -56,21 +54,31 @@
let impact = if scope == "U" { 6.42 * iss } else { 7.52 * (iss - 0.029) - 3.25 * (iss - 0.02)}
let exploitability = 8.22 * attackVectorLookup.at(attackVector) * attackComplexityLookup.at(attackComplexity) * privilegesLookup.at(privilegesRequired) * userInteractionLookup.at(userInteraction)
let baseScore = if impact <= 0 { 0 } else { if scope == "U" { calc.round(calc.min(impact + exploitability, 10), digits: 1) } else { calc.round(calc.min(1.08 * (impact + exploitability), 10), digits: 1) } }
if baseScore >= 9.0 {
status = "CRITICAL"
} else if baseScore >= 7.0 {
status = "HIGH"
} else if baseScore >= 4.0 {
status = "MEDIUM"
} else if baseScore >= 0.1 {
status = "LOW"
} else {
status = "NONE"
}
return baseScore
} else {
return -1
}
}
// Create a small CIA table to be included for every finding.
#let createTable(attackVector: "-", attackComplexity: "-", privilegesRequired: "-", userInteraction: "-", scope: "-", confidentiality: "-", integrity: "-", availability: "-") = {
let baseScore = score(attackVector: attackVector, attackComplexity: attackComplexity, privilegesRequired: privilegesRequired, userInteraction: userInteraction, scope: scope, confidentiality: confidentiality, integrity: integrity, availability: availability)
let status = "?"
if baseScore >= 9.0 {
status = "CRITICAL"
} else if baseScore >= 7.0 {
status = "HIGH"
} else if baseScore >= 4.0 {
status = "MEDIUM"
} else if baseScore >= 0.1 {
status = "LOW"
} else if baseScore == -1 {
// At least one value is unspecified, so this finding will be categorized as "other" and CVSS Score calculation is skipped
status = "OTHER"
} else {
status = "NONE"
}
stack(
@@ -107,6 +115,31 @@
isUsed.update(true)
}
// parse eats a CVSS:3.1 string and creates the appropiate table for it
#let parse(input: str) = {
let parts = input.split("/")
if parts.len() != 9 {
panic("Invalid CVSS string: " + input + ", expected 9 parts")
}
if parts.at(0) != "CVSS:3.1" {
panic("Unsupported CVSS string version: " + parts.at(0) + ", expected 'CVSS:3.1'")
}
if not parts.at(1).starts-with("AV:") or not parts.at(2).starts-with("AC:") or not parts.at(3).starts-with("PR:") or not parts.at(4).starts-with("UI:") or not parts.at(5).starts-with("S:") or not parts.at(6).starts-with("C:") or not parts.at(7).starts-with("I:") or not parts.at(8).starts-with("A:") {
panic("Invalid CVSS string: " + input + ", expected format CVSS:3.1/AV:*/AC:*/PR:*/UI:*/S:*/C:*/I:*/A:*")
}
return (
"attackVector": parts.at(1).last(),
"attackComplexity": parts.at(2).last(),
"privilegesRequired": parts.at(3).last(),
"userInteraction": parts.at(4).last(),
"scope": parts.at(5).last(),
"confidentiality": parts.at(6).last(),
"integrity": parts.at(7).last(),
"availability": parts.at(8).last()
)
}
#let appendix() = {
[
== Common Vulnerability Scoring System (CVSS)