pub const VOLATILITY3_ISF_SERVER: &str = "https://isf-server.code.digitalpolice.ca";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct KapeMapping {
pub artifact_id: &'static str,
pub kape_targets: &'static [&'static str],
pub kape_modules: &'static [&'static str],
pub velociraptor_artifacts: &'static [&'static str],
}
pub static KAPE_MAPPINGS: &[KapeMapping] = &[
KapeMapping {
artifact_id: "prefetch_dir",
kape_targets: &["!BasicCollection", "Prefetch"],
kape_modules: &["PECmd"],
velociraptor_artifacts: &["Windows.Forensics.Prefetch"],
},
KapeMapping {
artifact_id: "prefetch_file",
kape_targets: &["!BasicCollection", "Prefetch"],
kape_modules: &["PECmd"],
velociraptor_artifacts: &["Windows.Forensics.Prefetch"],
},
KapeMapping {
artifact_id: "amcache_app_file",
kape_targets: &["Amcache", "!BasicCollection"],
kape_modules: &["AmcacheParser"],
velociraptor_artifacts: &["Windows.Forensics.Amcache"],
},
KapeMapping {
artifact_id: "shimcache",
kape_targets: &["AppCompatCache", "!BasicCollection"],
kape_modules: &["AppCompatCacheParser"],
velociraptor_artifacts: &["Windows.Registry.AppCompatCache"],
},
KapeMapping {
artifact_id: "userassist_exe",
kape_targets: &["!BasicCollection", "RegistryHives"],
kape_modules: &["RECmd"],
velociraptor_artifacts: &["Windows.Registry.UserAssist"],
},
KapeMapping {
artifact_id: "userassist_folder",
kape_targets: &["!BasicCollection", "RegistryHives"],
kape_modules: &["RECmd"],
velociraptor_artifacts: &["Windows.Registry.UserAssist"],
},
KapeMapping {
artifact_id: "bam_user",
kape_targets: &["BAM_DAM", "!BasicCollection"],
kape_modules: &["RECmd"],
velociraptor_artifacts: &["Windows.Registry.BAM"],
},
KapeMapping {
artifact_id: "mft_file",
kape_targets: &["$MFT", "!BasicCollection"],
kape_modules: &["MFTECmd"],
velociraptor_artifacts: &["Windows.NTFS.MFT"],
},
KapeMapping {
artifact_id: "lnk_files",
kape_targets: &["LNKFilesAndJumpLists", "!BasicCollection"],
kape_modules: &["LECmd"],
velociraptor_artifacts: &["Windows.Forensics.Lnk"],
},
KapeMapping {
artifact_id: "lnk_files_office",
kape_targets: &["LNKFilesAndJumpLists", "!BasicCollection"],
kape_modules: &["LECmd"],
velociraptor_artifacts: &["Windows.Forensics.Lnk"],
},
KapeMapping {
artifact_id: "evtx_dir",
kape_targets: &["EventLogs", "!SANS_Triage"],
kape_modules: &["EvtxECmd"],
velociraptor_artifacts: &["Windows.EventLogs.Evtx"],
},
KapeMapping {
artifact_id: "evtx_security",
kape_targets: &["EventLogs", "!SANS_Triage"],
kape_modules: &["EvtxECmd"],
velociraptor_artifacts: &["Windows.EventLogs.Evtx"],
},
KapeMapping {
artifact_id: "evtx_system",
kape_targets: &["EventLogs", "!SANS_Triage"],
kape_modules: &["EvtxECmd"],
velociraptor_artifacts: &["Windows.EventLogs.Evtx"],
},
KapeMapping {
artifact_id: "evtx_powershell",
kape_targets: &["EventLogs", "!SANS_Triage"],
kape_modules: &["EvtxECmd"],
velociraptor_artifacts: &[
"Windows.EventLogs.Evtx",
"Windows.EventLogs.PowerShell.ScriptBlock",
],
},
KapeMapping {
artifact_id: "evtx_sysmon",
kape_targets: &["EventLogs", "!SANS_Triage"],
kape_modules: &["EvtxECmd"],
velociraptor_artifacts: &["Windows.EventLogs.Evtx", "Windows.Sysmon.Events"],
},
KapeMapping {
artifact_id: "sam_users",
kape_targets: &["SAM", "!SANS_Triage"],
kape_modules: &["RECmd"],
velociraptor_artifacts: &["Windows.Registry.SAM"],
},
KapeMapping {
artifact_id: "ntds_dit",
kape_targets: &["NTDS", "!SANS_Triage"],
kape_modules: &["ntdsutil"],
velociraptor_artifacts: &["Windows.Carving.NTDS"],
},
KapeMapping {
artifact_id: "linux_bash_history",
kape_targets: &[],
kape_modules: &[],
velociraptor_artifacts: &["Linux.Forensics.BashHistory"],
},
KapeMapping {
artifact_id: "linux_zsh_history",
kape_targets: &[],
kape_modules: &[],
velociraptor_artifacts: &["Linux.Forensics.ZshHistory"],
},
KapeMapping {
artifact_id: "linux_wtmp",
kape_targets: &[],
kape_modules: &[],
velociraptor_artifacts: &["Linux.Sys.Wtmp"],
},
KapeMapping {
artifact_id: "linux_auth_log",
kape_targets: &[],
kape_modules: &[],
velociraptor_artifacts: &["Linux.Sys.AuthLog"],
},
KapeMapping {
artifact_id: "linux_journal_dir",
kape_targets: &[],
kape_modules: &[],
velociraptor_artifacts: &["Linux.Sys.Journal"],
},
KapeMapping {
artifact_id: "linux_passwd",
kape_targets: &[],
kape_modules: &[],
velociraptor_artifacts: &["Linux.Sys.Users"],
},
KapeMapping {
artifact_id: "linux_shadow",
kape_targets: &[],
kape_modules: &[],
velociraptor_artifacts: &["Linux.Sys.Users"],
},
KapeMapping {
artifact_id: "linux_user_crontab",
kape_targets: &[],
kape_modules: &[],
velociraptor_artifacts: &["Linux.Sys.Crontab"],
},
KapeMapping {
artifact_id: "linux_crontab_system",
kape_targets: &[],
kape_modules: &[],
velociraptor_artifacts: &["Linux.Sys.Crontab"],
},
KapeMapping {
artifact_id: "linux_ssh_authorized_keys",
kape_targets: &[],
kape_modules: &[],
velociraptor_artifacts: &["Linux.Forensics.SSH.AuthorizedKeys"],
},
];
pub fn kape_mapping_for(artifact_id: &str) -> Option<&'static KapeMapping> {
KAPE_MAPPINGS.iter().find(|m| m.artifact_id == artifact_id)
}
pub fn kape_target_set(artifact_ids: &[&str]) -> Vec<&'static str> {
let mut targets: Vec<&'static str> = artifact_ids
.iter()
.filter_map(|id| kape_mapping_for(id))
.flat_map(|m| m.kape_targets.iter().copied())
.collect();
targets.sort_unstable();
targets.dedup();
targets
}
pub fn velociraptor_artifact_set(artifact_ids: &[&str]) -> Vec<&'static str> {
let mut arts: Vec<&'static str> = artifact_ids
.iter()
.filter_map(|id| kape_mapping_for(id))
.flat_map(|m| m.velociraptor_artifacts.iter().copied())
.collect();
arts.sort_unstable();
arts.dedup();
arts
}
#[cfg(test)]
mod tests {
use super::*;
use crate::catalog::CATALOG;
#[test]
fn prefetch_has_kape_mapping() {
let m = kape_mapping_for("prefetch_file").expect("prefetch_file must have mapping");
assert!(!m.kape_targets.is_empty());
assert!(!m.velociraptor_artifacts.is_empty());
}
#[test]
fn evtx_security_has_velociraptor_artifact() {
let m = kape_mapping_for("evtx_security").expect("evtx_security must have mapping");
assert!(m
.velociraptor_artifacts
.iter()
.any(|a| a.contains("EventLog")));
}
#[test]
fn kape_target_set_deduplicates() {
let targets = kape_target_set(&["evtx_security", "evtx_system", "evtx_sysmon"]);
let unique: std::collections::HashSet<_> = targets.iter().collect();
assert_eq!(
targets.len(),
unique.len(),
"kape_target_set should deduplicate"
);
}
#[test]
fn velociraptor_artifact_set_deduplicates() {
let arts = velociraptor_artifact_set(&["evtx_security", "evtx_system"]);
let unique: std::collections::HashSet<_> = arts.iter().collect();
assert_eq!(arts.len(), unique.len());
}
#[test]
fn unknown_artifact_returns_none() {
assert!(kape_mapping_for("nonexistent").is_none());
}
#[test]
fn all_table_ids_exist_in_catalog() {
for mapping in KAPE_MAPPINGS {
assert!(
CATALOG.by_id(mapping.artifact_id).is_some(),
"kape table references unknown artifact: {}",
mapping.artifact_id
);
}
}
#[test]
fn linux_artifacts_have_velociraptor_mappings() {
let linux_with_velociraptor = KAPE_MAPPINGS
.iter()
.filter(|m| m.artifact_id.starts_with("linux_"))
.filter(|m| !m.velociraptor_artifacts.is_empty())
.count();
assert!(
linux_with_velociraptor >= 2,
"Linux artifacts should have Velociraptor mappings"
);
}
#[test]
fn volatility3_isf_server_is_https() {
assert!(VOLATILITY3_ISF_SERVER.starts_with("https://"));
}
#[test]
fn volatility3_isf_server_contains_digitalpolice() {
assert!(VOLATILITY3_ISF_SERVER.contains("digitalpolice"));
}
}