use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Technique {
pub id: String,
pub name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Detection {
pub source: String,
pub rule: String,
pub confidence: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub verdict: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct KbEntry {
pub id: String,
#[serde(default)]
pub command: Option<String>,
#[serde(default)]
pub args_contains: Option<String>,
#[serde(default)]
pub raw_contains: Option<String>,
pub description: String,
pub techniques: Vec<Technique>,
#[serde(default)]
pub telemetry: Vec<String>,
#[serde(default)]
pub detections: Vec<Detection>,
pub noise: u8,
}
#[derive(Debug, Clone, Deserialize)]
pub struct KnowledgeBase {
pub platform: String,
#[serde(default)]
pub note: String,
pub entries: Vec<KbEntry>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum Severity {
Low,
Medium,
High,
Critical,
}
impl Severity {
pub fn from_noise(noise: u8) -> Self {
match noise {
0..=24 => Severity::Low,
25..=49 => Severity::Medium,
50..=74 => Severity::High,
_ => Severity::Critical,
}
}
pub fn label(self) -> &'static str {
match self {
Severity::Low => "LOW",
Severity::Medium => "MEDIUM",
Severity::High => "HIGH",
Severity::Critical => "CRITICAL",
}
}
pub fn color(self) -> &'static str {
match self {
Severity::Low => crate::theme::CYAN,
Severity::Medium => crate::theme::YELLOW,
Severity::High => crate::theme::ORANGE,
Severity::Critical => crate::theme::RED,
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct Finding {
pub line: usize,
pub source: String,
pub rule_id: String,
pub description: String,
pub techniques: Vec<Technique>,
pub telemetry: Vec<String>,
pub detections: Vec<Detection>,
pub noise: u8,
pub severity: Severity,
#[serde(skip)]
pub matched_command: Option<crate::parser::Command>,
}
#[derive(Debug, Clone, Serialize)]
pub struct Report {
pub platform: String,
pub note: String,
pub findings: Vec<Finding>,
pub max_noise: u8,
pub lines_analyzed: usize,
}
impl Report {
pub fn max_severity(&self) -> Severity {
Severity::from_noise(self.max_noise)
}
}