use std::sync::LazyLock;
use regex::Regex;
use crate::oleobj::ole_object::OleObject;
#[derive(Debug, Clone)]
pub struct CveDetection {
pub cve_id: String,
pub description: String,
pub class_name: String,
}
static RE_EXECUTABLE_EXT: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"(?i)\.(bat|cmd|com|cpl|dll|exe|hta|inf|js|jse|lnk|msi|msp|mst|ocx|pif|ps1|reg|scr|sct|vb|vbe|vbs|wsc|wsf|wsh)$").unwrap()
});
pub fn detect_cves(obj: &OleObject) -> Vec<CveDetection> {
let mut detections = Vec::new();
if obj.is_ole2link() {
detections.push(CveDetection {
cve_id: "CVE-2017-0199".to_string(),
description: "OLE2Link object detected — may exploit HTA handler".to_string(),
class_name: obj.class_name.clone(),
});
}
if obj.is_equation() {
detections.push(CveDetection {
cve_id: "CVE-2017-11882".to_string(),
description: "Equation Editor object detected — potential buffer overflow"
.to_string(),
class_name: obj.class_name.clone(),
});
}
detections
}
pub fn is_executable_extension(filename: &str) -> bool {
RE_EXECUTABLE_EXT.is_match(filename)
}
#[cfg(test)]
mod tests {
use super::*;
fn make_ole_object(class_name: &str) -> OleObject {
OleObject {
ole_version: 0x501,
format_id: 2,
class_name: class_name.to_string(),
topic_name: String::new(),
item_name: String::new(),
data_size: 0,
data: Vec::new(),
}
}
#[test]
fn test_detect_cve_2017_0199() {
let obj = make_ole_object("OLE2Link");
let cves = detect_cves(&obj);
assert_eq!(cves.len(), 1);
assert_eq!(cves[0].cve_id, "CVE-2017-0199");
}
#[test]
fn test_detect_cve_2017_11882() {
let obj = make_ole_object("Equation.3");
let cves = detect_cves(&obj);
assert_eq!(cves.len(), 1);
assert_eq!(cves[0].cve_id, "CVE-2017-11882");
}
#[test]
fn test_detect_equation_case_insensitive() {
let obj = make_ole_object("EQUATION.3");
let cves = detect_cves(&obj);
assert_eq!(cves.len(), 1);
assert_eq!(cves[0].cve_id, "CVE-2017-11882");
}
#[test]
fn test_no_cve_clean_object() {
let obj = make_ole_object("Package");
let cves = detect_cves(&obj);
assert!(cves.is_empty());
}
#[test]
fn test_executable_extensions() {
assert!(is_executable_extension("payload.exe"));
assert!(is_executable_extension("script.vbs"));
assert!(is_executable_extension("test.HTA"));
assert!(is_executable_extension("file.PS1"));
assert!(is_executable_extension("dropper.SCR"));
assert!(!is_executable_extension("document.docx"));
assert!(!is_executable_extension("image.png"));
assert!(!is_executable_extension("noext"));
}
#[test]
fn test_executable_bat_cmd() {
assert!(is_executable_extension("run.bat"));
assert!(is_executable_extension("run.cmd"));
assert!(is_executable_extension("lib.dll"));
}
}