1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24pub enum ArtifactType {
25 RegistryKey,
27 RegistryValue,
29 File,
31 Directory,
33 EventLog,
35 MemoryRegion,
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
41pub enum HiveTarget {
42 HklmSystem,
43 HklmSoftware,
44 HklmSam,
45 HklmSecurity,
46 NtUser,
47 UsrClass,
48 Amcache,
49 Bcd,
50 None,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
56pub enum DataScope {
57 User,
58 System,
59 Network,
60 Mixed,
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
65pub enum OsScope {
66 All,
68 Win7Plus,
69 Win8Plus,
70 Win10Plus,
71 Win11Plus,
72 Win11_22H2,
73 Linux,
76 LinuxSystemd,
78 LinuxDebian,
80 LinuxRhel,
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
88pub enum BinaryFieldType {
89 U16Le,
90 U32Le,
91 U64Le,
92 I32Le,
93 I64Le,
94 FiletimeLe,
95 Bytes { len: usize },
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq)]
101pub struct BinaryField {
102 pub name: &'static str,
103 pub offset: usize,
104 pub field_type: BinaryFieldType,
105 pub description: &'static str,
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
116pub enum Decoder {
117 Identity,
119 Rot13Name,
121 FiletimeAt { offset: usize },
123 Utf16Le,
125 PipeDelimited { fields: &'static [&'static str] },
127 DwordLe,
129 MultiSz,
131 MruListEx,
133 BinaryRecord(&'static [BinaryField]),
135 Rot13NameWithBinaryValue(&'static [BinaryField]),
138}
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
144pub enum ValueType {
145 Text,
146 Integer,
147 UnsignedInt,
148 Timestamp,
149 Bytes,
150 Bool,
151 List,
152}
153
154#[derive(Debug, Clone, Copy, PartialEq, Eq)]
156pub struct FieldSchema {
157 pub name: &'static str,
158 pub value_type: ValueType,
159 pub description: &'static str,
160 pub is_uid_component: bool,
162}
163
164#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
166pub enum TriagePriority {
167 Critical = 3,
169 High = 2,
171 Medium = 1,
173 Low = 0,
175}
176
177#[derive(Debug, Clone, Copy, PartialEq, Eq)]
182pub struct ArtifactDescriptor {
183 pub id: &'static str,
185 pub name: &'static str,
187 pub artifact_type: ArtifactType,
189 pub hive: Option<HiveTarget>,
191 pub key_path: &'static str,
193 pub value_name: Option<&'static str>,
195 pub file_path: Option<&'static str>,
197 pub scope: DataScope,
199 pub os_scope: OsScope,
201 pub decoder: Decoder,
203 pub meaning: &'static str,
205 pub mitre_techniques: &'static [&'static str],
207 pub fields: &'static [FieldSchema],
209 pub retention: Option<&'static str>,
212 pub triage_priority: TriagePriority,
214 pub related_artifacts: &'static [&'static str],
216 pub sources: &'static [&'static str],
220}
221
222#[derive(Debug, Clone, PartialEq)]
226pub enum ArtifactValue {
227 Text(String),
228 Integer(i64),
229 UnsignedInt(u64),
230 Timestamp(String),
231 Bytes(Vec<u8>),
232 Bool(bool),
233 List(Vec<ArtifactValue>),
234 Map(Vec<(String, ArtifactValue)>),
235 Null,
236}
237
238#[derive(Debug, Clone, PartialEq)]
243pub struct ArtifactRecord {
244 pub uid: String,
247 pub artifact_id: &'static str,
249 pub artifact_name: &'static str,
251 pub scope: DataScope,
253 pub os_scope: OsScope,
255 pub timestamp: Option<String>,
257 pub fields: Vec<(&'static str, ArtifactValue)>,
259 pub meaning: String,
261 pub mitre_techniques: Vec<&'static str>,
263 pub confidence: f32,
265}
266
267#[derive(Debug, Clone, Default)]
272pub struct ArtifactQuery {
273 pub scope: Option<DataScope>,
274 pub os_scope: Option<OsScope>,
275 pub artifact_type: Option<ArtifactType>,
276 pub hive: Option<HiveTarget>,
277 pub mitre_technique: Option<&'static str>,
278 pub id: Option<&'static str>,
279}
280
281#[derive(Debug, Clone, PartialEq, Eq)]
285pub enum DecodeError {
286 BufferTooShort { expected: usize, actual: usize },
288 InvalidUtf8,
290 InvalidUtf16,
292 FieldOutOfBounds {
294 field: &'static str,
295 offset: usize,
296 size: usize,
297 buf_len: usize,
298 },
299 UnsupportedDecoder(&'static str),
301}
302
303impl core::fmt::Display for DecodeError {
304 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
305 match self {
306 Self::BufferTooShort { expected, actual } => {
307 write!(f, "buffer too short: need {expected} bytes, got {actual}")
308 }
309 Self::InvalidUtf8 => write!(f, "invalid UTF-8 in raw data"),
310 Self::InvalidUtf16 => write!(f, "invalid UTF-16LE in raw data"),
311 Self::FieldOutOfBounds {
312 field,
313 offset,
314 size,
315 buf_len,
316 } => write!(
317 f,
318 "field '{field}' at offset {offset} size {size} exceeds buffer length {buf_len}"
319 ),
320 Self::UnsupportedDecoder(msg) => write!(f, "unsupported decoder: {msg}"),
321 }
322 }
323}
324
325impl std::error::Error for DecodeError {}
326
327pub struct ForensicCatalog {
331 entries: &'static [ArtifactDescriptor],
332}
333
334impl ForensicCatalog {
335 pub const fn new(entries: &'static [ArtifactDescriptor]) -> Self {
337 Self { entries }
338 }
339
340 pub fn list(&self) -> &[ArtifactDescriptor] {
342 self.entries
343 }
344
345 pub fn by_id(&self, id: &str) -> Option<&ArtifactDescriptor> {
347 self.entries.iter().find(|d| d.id == id)
348 }
349
350 pub fn filter(&self, query: &ArtifactQuery) -> Vec<&ArtifactDescriptor> {
353 self.entries
354 .iter()
355 .filter(|d| {
356 if let Some(scope) = query.scope {
357 if d.scope != scope {
358 return false;
359 }
360 }
361 if let Some(os) = query.os_scope {
362 if d.os_scope != os {
363 return false;
364 }
365 }
366 if let Some(at) = query.artifact_type {
367 if d.artifact_type != at {
368 return false;
369 }
370 }
371 if let Some(hive) = query.hive {
372 if d.hive != Some(hive) {
373 return false;
374 }
375 }
376 if let Some(tech) = query.mitre_technique {
377 if !d.mitre_techniques.contains(&tech) {
378 return false;
379 }
380 }
381 if let Some(id) = query.id {
382 if d.id != id {
383 return false;
384 }
385 }
386 true
387 })
388 .collect()
389 }
390
391 pub fn by_mitre(&self, technique: &str) -> Vec<&ArtifactDescriptor> {
393 self.entries
394 .iter()
395 .filter(|d| d.mitre_techniques.contains(&technique))
396 .collect()
397 }
398
399 pub fn for_triage(&self) -> Vec<&ArtifactDescriptor> {
402 let mut v: Vec<&ArtifactDescriptor> = self.entries.iter().collect();
403 v.sort_by_key(|d| std::cmp::Reverse(d.triage_priority));
404 v
405 }
406
407 pub fn filter_by_keyword(&self, keyword: &str) -> Vec<&ArtifactDescriptor> {
410 let kw = keyword.to_ascii_lowercase();
411 self.entries
412 .iter()
413 .filter(|d| {
414 d.meaning.to_ascii_lowercase().contains(&kw)
415 || d.name.to_ascii_lowercase().contains(&kw)
416 })
417 .collect()
418 }
419
420 pub fn decode(
428 &self,
429 descriptor: &ArtifactDescriptor,
430 name: &str,
431 raw: &[u8],
432 ) -> Result<ArtifactRecord, DecodeError> {
433 decode_artifact(descriptor, name, raw)
434 }
435}
436
437fn rot13(s: &str) -> String {
441 s.chars()
442 .map(|c| match c {
443 'A'..='Z' => (b'A' + (c as u8 - b'A' + 13) % 26) as char,
444 'a'..='z' => (b'a' + (c as u8 - b'a' + 13) % 26) as char,
445 other => other,
446 })
447 .collect()
448}
449
450fn filetime_to_iso8601(ft: u64) -> Option<String> {
454 const EPOCH_DIFF: u64 = 116_444_736_000_000_000;
456 if ft == 0 {
457 return None;
458 }
459 if ft < EPOCH_DIFF {
460 return None;
461 }
462 let unix_secs = (ft - EPOCH_DIFF) / 10_000_000;
463
464 let secs_per_day: u64 = 86400;
467 let mut days = unix_secs / secs_per_day;
468 let day_secs = unix_secs % secs_per_day;
469 let hours = day_secs / 3600;
470 let minutes = (day_secs % 3600) / 60;
471 let seconds = day_secs % 60;
472
473 days += 719_468; let era = days / 146_097;
477 let doe = days - era * 146_097; let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146_096) / 365;
479 let y = yoe + era * 400;
480 let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
481 let mp = (5 * doy + 2) / 153;
482 let d = doy - (153 * mp + 2) / 5 + 1;
483 let m = if mp < 10 { mp + 3 } else { mp - 9 };
484 let y = if m <= 2 { y + 1 } else { y };
485
486 Some(format!(
487 "{y:04}-{m:02}-{d:02}T{hours:02}:{minutes:02}:{seconds:02}Z"
488 ))
489}
490
491fn read_u16_le(data: &[u8], offset: usize) -> u16 {
493 if offset + 2 > data.len() {
494 return 0;
495 }
496 u16::from_le_bytes([data[offset], data[offset + 1]])
497}
498
499fn read_u32_le(data: &[u8], offset: usize) -> u32 {
501 if offset + 4 > data.len() {
502 return 0;
503 }
504 u32::from_le_bytes([
505 data[offset],
506 data[offset + 1],
507 data[offset + 2],
508 data[offset + 3],
509 ])
510}
511
512fn read_u64_le(data: &[u8], offset: usize) -> u64 {
514 if offset + 8 > data.len() {
515 return 0;
516 }
517 u64::from_le_bytes([
518 data[offset],
519 data[offset + 1],
520 data[offset + 2],
521 data[offset + 3],
522 data[offset + 4],
523 data[offset + 5],
524 data[offset + 6],
525 data[offset + 7],
526 ])
527}
528
529fn read_i32_le(data: &[u8], offset: usize) -> i32 {
531 if offset + 4 > data.len() {
532 return 0;
533 }
534 i32::from_le_bytes([
535 data[offset],
536 data[offset + 1],
537 data[offset + 2],
538 data[offset + 3],
539 ])
540}
541
542fn read_i64_le(data: &[u8], offset: usize) -> i64 {
544 if offset + 8 > data.len() {
545 return 0;
546 }
547 i64::from_le_bytes([
548 data[offset],
549 data[offset + 1],
550 data[offset + 2],
551 data[offset + 3],
552 data[offset + 4],
553 data[offset + 5],
554 data[offset + 6],
555 data[offset + 7],
556 ])
557}
558
559fn decode_binary_field(field: &BinaryField, raw: &[u8]) -> Result<ArtifactValue, DecodeError> {
561 let size = match field.field_type {
562 BinaryFieldType::U16Le => 2,
563 BinaryFieldType::U32Le | BinaryFieldType::I32Le => 4,
564 BinaryFieldType::U64Le | BinaryFieldType::I64Le | BinaryFieldType::FiletimeLe => 8,
565 BinaryFieldType::Bytes { len } => len,
566 };
567 if field.offset + size > raw.len() {
568 return Err(DecodeError::FieldOutOfBounds {
569 field: field.name,
570 offset: field.offset,
571 size,
572 buf_len: raw.len(),
573 });
574 }
575 Ok(match field.field_type {
576 BinaryFieldType::U16Le => {
577 ArtifactValue::UnsignedInt(u64::from(read_u16_le(raw, field.offset)))
578 }
579 BinaryFieldType::U32Le => {
580 ArtifactValue::UnsignedInt(u64::from(read_u32_le(raw, field.offset)))
581 }
582 BinaryFieldType::U64Le => ArtifactValue::UnsignedInt(read_u64_le(raw, field.offset)),
583 BinaryFieldType::I32Le => ArtifactValue::Integer(i64::from(read_i32_le(raw, field.offset))),
584 BinaryFieldType::I64Le => ArtifactValue::Integer(read_i64_le(raw, field.offset)),
585 BinaryFieldType::FiletimeLe => {
586 let ft = read_u64_le(raw, field.offset);
587 match filetime_to_iso8601(ft) {
588 Some(ts) => ArtifactValue::Timestamp(ts),
589 None => ArtifactValue::Null,
590 }
591 }
592 BinaryFieldType::Bytes { len } => {
593 ArtifactValue::Bytes(raw[field.offset..field.offset + len].to_vec())
594 }
595 })
596}
597
598fn build_registry_uid(descriptor: &ArtifactDescriptor, name: &str) -> String {
600 let hive_prefix = match descriptor.hive {
601 Some(HiveTarget::NtUser) => "HKCU",
602 Some(HiveTarget::UsrClass) => "HKCU_Classes",
603 Some(HiveTarget::HklmSoftware) => "HKLM\\SOFTWARE",
604 Some(HiveTarget::HklmSystem) => "HKLM\\SYSTEM",
605 Some(HiveTarget::HklmSam) => "HKLM\\SAM",
606 Some(HiveTarget::HklmSecurity) => "HKLM\\SECURITY",
607 Some(HiveTarget::Amcache) => "Amcache",
608 Some(HiveTarget::Bcd) => "BCD",
609 Some(HiveTarget::None) | None => "unknown",
610 };
611 if name.is_empty() {
612 format!("winreg://{}/{}", hive_prefix, descriptor.key_path)
613 } else {
614 format!("winreg://{}/{}/{}", hive_prefix, descriptor.key_path, name)
615 }
616}
617
618fn build_file_uid(descriptor: &ArtifactDescriptor, name: &str) -> String {
620 let path = descriptor.file_path.unwrap_or("");
621 if name.is_empty() {
622 format!("file://{path}")
623 } else {
624 format!("file://{path}#{name}")
625 }
626}
627
628#[allow(clippy::type_complexity)]
631fn decode_binary_fields(
632 binary_fields: &[BinaryField],
633 raw: &[u8],
634) -> Result<(Vec<(&'static str, ArtifactValue)>, Option<String>), DecodeError> {
635 let mut decoded = Vec::new();
636 let mut ts = None;
637 for bf in binary_fields {
638 let val = decode_binary_field(bf, raw)?;
639 if bf.field_type == BinaryFieldType::FiletimeLe {
640 if let ArtifactValue::Timestamp(ref s) = val {
641 if ts.is_none() {
642 ts = Some(s.clone());
643 }
644 }
645 }
646 decoded.push((bf.name, val));
647 }
648 Ok((decoded, ts))
649}
650
651#[allow(clippy::too_many_lines)]
653fn decode_artifact(
654 descriptor: &ArtifactDescriptor,
655 name: &str,
656 raw: &[u8],
657) -> Result<ArtifactRecord, DecodeError> {
658 let (fields, timestamp) = match descriptor.decoder {
659 Decoder::Identity => {
660 let text = std::str::from_utf8(raw)
661 .map_err(|_| DecodeError::InvalidUtf8)?
662 .to_string();
663 (vec![("value", ArtifactValue::Text(text))], None)
664 }
665
666 Decoder::Rot13Name => {
667 let decoded = rot13(name);
668 (vec![("program", ArtifactValue::Text(decoded))], None)
669 }
670
671 Decoder::FiletimeAt { offset } => {
672 if offset + 8 > raw.len() {
673 return Err(DecodeError::BufferTooShort {
674 expected: offset + 8,
675 actual: raw.len(),
676 });
677 }
678 let ft = read_u64_le(raw, offset);
679 let ts = filetime_to_iso8601(ft);
680 (
681 vec![(
682 "timestamp",
683 match ts {
684 Some(ref s) => ArtifactValue::Timestamp(s.clone()),
685 None => ArtifactValue::Null,
686 },
687 )],
688 ts,
689 )
690 }
691
692 Decoder::Utf16Le => {
693 if raw.len() % 2 != 0 {
694 return Err(DecodeError::InvalidUtf16);
695 }
696 let u16s: Vec<u16> = raw
697 .chunks_exact(2)
698 .map(|c| u16::from_le_bytes([c[0], c[1]]))
699 .collect();
700 let trimmed: &[u16] = match u16s.iter().position(|&c| c == 0) {
702 Some(pos) => &u16s[..pos],
703 None => &u16s,
704 };
705 let text = String::from_utf16(trimmed).map_err(|_| DecodeError::InvalidUtf16)?;
706 (vec![("value", ArtifactValue::Text(text))], None)
707 }
708
709 Decoder::PipeDelimited {
710 fields: field_names,
711 } => {
712 let source = if name.is_empty() {
714 std::str::from_utf8(raw)
715 .map_err(|_| DecodeError::InvalidUtf8)?
716 .to_string()
717 } else {
718 name.to_string()
719 };
720 let parts: Vec<&str> = source.split('|').collect();
721 let decoded_fields: Vec<(&'static str, ArtifactValue)> = field_names
722 .iter()
723 .enumerate()
724 .map(|(i, &fname)| {
725 let val = match parts.get(i) {
726 Some(s) => ArtifactValue::Text((*s).to_string()),
727 None => ArtifactValue::Null,
728 };
729 (fname, val)
730 })
731 .collect();
732 (decoded_fields, None)
733 }
734
735 Decoder::DwordLe => {
736 if raw.len() < 4 {
737 return Err(DecodeError::BufferTooShort {
738 expected: 4,
739 actual: raw.len(),
740 });
741 }
742 let val = read_u32_le(raw, 0);
743 (
744 vec![("value", ArtifactValue::UnsignedInt(u64::from(val)))],
745 None,
746 )
747 }
748
749 Decoder::MultiSz => {
750 if raw.len() < 2 {
752 return Ok(make_record(
753 descriptor,
754 name,
755 vec![("values", ArtifactValue::List(vec![]))],
756 None,
757 ));
758 }
759 if raw.len() % 2 != 0 {
760 return Err(DecodeError::InvalidUtf16);
761 }
762 let u16s: Vec<u16> = raw
763 .chunks_exact(2)
764 .map(|c| u16::from_le_bytes([c[0], c[1]]))
765 .collect();
766 let strings: Vec<ArtifactValue> = u16s
768 .split(|&c| c == 0)
769 .filter(|s| !s.is_empty())
770 .map(|s| ArtifactValue::Text(String::from_utf16_lossy(s)))
771 .collect();
772 (vec![("values", ArtifactValue::List(strings))], None)
773 }
774
775 Decoder::MruListEx => {
776 let mut indices = Vec::new();
778 let mut offset = 0;
779 while offset + 4 <= raw.len() {
780 let idx = read_u32_le(raw, offset);
781 if idx == 0xFFFF_FFFF {
782 break;
783 }
784 indices.push(ArtifactValue::UnsignedInt(u64::from(idx)));
785 offset += 4;
786 }
787 (vec![("indices", ArtifactValue::List(indices))], None)
788 }
789
790 Decoder::BinaryRecord(binary_fields) => decode_binary_fields(binary_fields, raw)?,
791
792 Decoder::Rot13NameWithBinaryValue(binary_fields) => {
793 let (mut fields, ts) = decode_binary_fields(binary_fields, raw)?;
794 fields.insert(0, ("program", ArtifactValue::Text(rot13(name))));
795 (fields, ts)
796 }
797 };
798
799 Ok(make_record(descriptor, name, fields, timestamp))
800}
801
802fn make_record(
804 descriptor: &ArtifactDescriptor,
805 name: &str,
806 fields: Vec<(&'static str, ArtifactValue)>,
807 timestamp: Option<String>,
808) -> ArtifactRecord {
809 let uid = match descriptor.artifact_type {
810 ArtifactType::File | ArtifactType::Directory => build_file_uid(descriptor, name),
811 _ => build_registry_uid(descriptor, name),
812 };
813 ArtifactRecord {
814 uid,
815 artifact_id: descriptor.id,
816 artifact_name: descriptor.name,
817 scope: descriptor.scope,
818 os_scope: descriptor.os_scope,
819 timestamp,
820 fields,
821 meaning: descriptor.meaning.to_string(),
822 mitre_techniques: descriptor.mitre_techniques.to_vec(),
823 confidence: 1.0,
824 }
825}
826
827static USERASSIST_BINARY_FIELDS: &[BinaryField] = &[
831 BinaryField {
832 name: "run_count",
833 offset: 4,
834 field_type: BinaryFieldType::U32Le,
835 description: "Number of times the program was launched",
836 },
837 BinaryField {
838 name: "focus_count",
839 offset: 8,
840 field_type: BinaryFieldType::U32Le,
841 description: "Number of times the program received input focus",
842 },
843 BinaryField {
844 name: "focus_duration_ms",
845 offset: 12,
846 field_type: BinaryFieldType::U32Le,
847 description: "Total focus time in milliseconds",
848 },
849 BinaryField {
850 name: "last_run",
851 offset: 60,
852 field_type: BinaryFieldType::FiletimeLe,
853 description: "FILETIME of the last execution",
854 },
855];
856
857static USERASSIST_FIELDS: &[FieldSchema] = &[
859 FieldSchema {
860 name: "program",
861 value_type: ValueType::Text,
862 description: "ROT13-decoded program path or name",
863 is_uid_component: true,
864 },
865 FieldSchema {
866 name: "run_count",
867 value_type: ValueType::UnsignedInt,
868 description: "Number of times launched",
869 is_uid_component: false,
870 },
871 FieldSchema {
872 name: "focus_count",
873 value_type: ValueType::UnsignedInt,
874 description: "Number of times received focus",
875 is_uid_component: false,
876 },
877 FieldSchema {
878 name: "focus_duration_ms",
879 value_type: ValueType::UnsignedInt,
880 description: "Total focus time in milliseconds",
881 is_uid_component: false,
882 },
883 FieldSchema {
884 name: "last_run",
885 value_type: ValueType::Timestamp,
886 description: "FILETIME of last execution as ISO 8601",
887 is_uid_component: false,
888 },
889];
890
891pub static USERASSIST_EXE: ArtifactDescriptor = ArtifactDescriptor {
897 id: "userassist_exe",
898 name: "UserAssist (EXE)",
899 artifact_type: ArtifactType::RegistryValue,
900 hive: Some(HiveTarget::NtUser),
901 key_path: r"Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist\{CEBFF5CD-ACE2-4F4F-9178-9926F41749EA}\Count",
902 value_name: None, file_path: None,
904 scope: DataScope::User,
905 os_scope: OsScope::Win7Plus,
906 decoder: Decoder::Rot13NameWithBinaryValue(USERASSIST_BINARY_FIELDS),
907 meaning: "Program execution history with launch counts and timestamps",
908 mitre_techniques: &["T1059", "T1204.002"],
909 fields: USERASSIST_FIELDS,
910 retention: None,
911 triage_priority: TriagePriority::High,
912 related_artifacts: &["prefetch_dir", "shimcache", "srum_app_resource"],
913 sources: &[
914 "https://attack.mitre.org/techniques/T1059/",
915 "https://attack.mitre.org/techniques/T1204/002/",
916 "https://www.sans.org/blog/computer-forensic-artifacts-windows-7-userassist/",
917 "https://windowsir.blogspot.com/2004/02/userassist.html",
918 "http://windowsir.blogspot.com/2007/09/more-on-userassist-keys.html",
919 "https://www.magnetforensics.com/blog/artifact-profile-userassist/",
920 ],
921};
922
923static RUN_KEY_FIELDS: &[FieldSchema] = &[FieldSchema {
925 name: "value",
926 value_type: ValueType::Text,
927 description: "Autostart command or path",
928 is_uid_component: false,
929}];
930
931pub static RUN_KEY_HKLM_RUN: ArtifactDescriptor = ArtifactDescriptor {
933 id: "run_key_hklm",
934 name: "Run Key (HKLM)",
935 artifact_type: ArtifactType::RegistryKey,
936 hive: Some(HiveTarget::HklmSoftware),
937 key_path: r"Microsoft\Windows\CurrentVersion\Run",
938 value_name: None,
939 file_path: None,
940 scope: DataScope::System,
941 os_scope: OsScope::All,
942 decoder: Decoder::Identity,
943 meaning: "System-wide autostart entry executed at every user logon",
944 mitre_techniques: &["T1547.001"],
945 fields: RUN_KEY_FIELDS,
946 retention: None,
947 triage_priority: TriagePriority::High,
948 related_artifacts: &[
949 "run_key_hklm_run",
950 "services_imagepath",
951 "scheduled_tasks_dir",
952 ],
953 sources: &[
954 "https://attack.mitre.org/techniques/T1547/001/",
955 "https://learn.microsoft.com/en-us/windows/win32/setupapi/run-and-runonce-registry-keys",
956 "https://windowsir.blogspot.com/2013/01/run-mru.html",
957 ],
958};
959
960static TYPED_URLS_FIELDS: &[FieldSchema] = &[FieldSchema {
962 name: "value",
963 value_type: ValueType::Text,
964 description: "URL typed into the IE/Edge address bar",
965 is_uid_component: true,
966}];
967
968pub static TYPED_URLS: ArtifactDescriptor = ArtifactDescriptor {
970 id: "typed_urls",
971 name: "TypedURLs (IE/Edge)",
972 artifact_type: ArtifactType::RegistryKey,
973 hive: Some(HiveTarget::NtUser),
974 key_path: r"Software\Microsoft\Internet Explorer\TypedURLs",
975 value_name: None,
976 file_path: None,
977 scope: DataScope::User,
978 os_scope: OsScope::All,
979 decoder: Decoder::Identity,
980 meaning: "URLs manually typed into the Internet Explorer or Edge address bar",
981 mitre_techniques: &["T1071.001"],
982 fields: TYPED_URLS_FIELDS,
983 retention: None,
984 triage_priority: TriagePriority::Medium,
985 related_artifacts: &[],
986 sources: &[
987 "https://attack.mitre.org/techniques/T1071/001/",
988 "https://www.sans.org/blog/digital-forensics-windows-registry-forensics-part-6-internet-explorer-user-typed-urls/",
989 "https://windowsir.blogspot.com/2006/04/typed-urls.html",
990 "https://crucialsecurity.wordpress.com/2011/03/14/typedurls-part-1/",
991 ],
992};
993
994static PCA_FIELDS_SCHEMA: &[FieldSchema] = &[
996 FieldSchema {
997 name: "exe_path",
998 value_type: ValueType::Text,
999 description: "Full path to the executable",
1000 is_uid_component: true,
1001 },
1002 FieldSchema {
1003 name: "timestamp",
1004 value_type: ValueType::Text,
1005 description: "Launch timestamp string",
1006 is_uid_component: false,
1007 },
1008];
1009
1010static PCA_PIPE_FIELDS: &[&str] = &["exe_path", "timestamp"];
1011
1012pub static PCA_APPLAUNCH_DIC: ArtifactDescriptor = ArtifactDescriptor {
1016 id: "pca_applaunch_dic",
1017 name: "PCA AppLaunch.dic",
1018 artifact_type: ArtifactType::File,
1019 hive: None,
1020 key_path: "",
1021 value_name: None,
1022 file_path: Some(r"C:\Windows\appcompat\pca\AppLaunch.dic"),
1023 scope: DataScope::System,
1024 os_scope: OsScope::Win11_22H2,
1025 decoder: Decoder::PipeDelimited {
1026 fields: PCA_PIPE_FIELDS,
1027 },
1028 meaning: "Program execution evidence from the Program Compatibility Assistant",
1029 mitre_techniques: &["T1059", "T1204.002"],
1030 fields: PCA_FIELDS_SCHEMA,
1031 retention: None,
1032 triage_priority: TriagePriority::High,
1033 related_artifacts: &[],
1034 sources: &[
1035 "https://attack.mitre.org/techniques/T1059/",
1036 "https://attack.mitre.org/techniques/T1204/002/",
1037 "https://aboutdfir.com/new-windows-11-pro-22h2-evidence-of-execution-artifact/",
1038 "https://www.sygnia.co/blog/new-windows-11-pca-artifact/",
1039 "https://github.com/Psmths/windows-forensic-artifacts/blob/main/execution/program-compatibility-assistant.md",
1040 ],
1041};
1042
1043pub static RUN_KEY_HKCU_RUN: ArtifactDescriptor = ArtifactDescriptor {
1047 id: "run_key_hkcu",
1048 name: "Run Key (HKCU)",
1049 artifact_type: ArtifactType::RegistryKey,
1050 hive: Some(HiveTarget::NtUser),
1051 key_path: r"Software\Microsoft\Windows\CurrentVersion\Run",
1052 value_name: None,
1053 file_path: None,
1054 scope: DataScope::User,
1055 os_scope: OsScope::All,
1056 decoder: Decoder::Identity,
1057 meaning: "Per-user autostart programs executed at every logon without elevation. \
1058 Lower-privilege than HKLM Run — writable by the user account itself, \
1059 making it a common unprivileged persistence location that survives password resets.",
1060 mitre_techniques: &["T1547.001"],
1061 fields: RUN_KEY_FIELDS,
1062 retention: None,
1063 triage_priority: TriagePriority::High,
1064 related_artifacts: &["run_key_hklm_run", "startup_folder_user"],
1065 sources: &[
1066 "https://attack.mitre.org/techniques/T1547/001/",
1067 "https://learn.microsoft.com/en-us/windows/win32/setupapi/run-and-runonce-registry-keys",
1068 "https://windowsir.blogspot.com/2013/01/run-mru.html",
1069 ],
1070};
1071
1072pub static RUN_KEY_HKCU_RUNONCE: ArtifactDescriptor = ArtifactDescriptor {
1074 id: "run_key_hkcu_once",
1075 name: "RunOnce Key (HKCU)",
1076 artifact_type: ArtifactType::RegistryKey,
1077 hive: Some(HiveTarget::NtUser),
1078 key_path: r"Software\Microsoft\Windows\CurrentVersion\RunOnce",
1079 value_name: None,
1080 file_path: None,
1081 scope: DataScope::User,
1082 os_scope: OsScope::All,
1083 decoder: Decoder::Identity,
1084 meaning: "Per-user one-time autostart, deleted after first execution",
1085 mitre_techniques: &["T1547.001"],
1086 fields: RUN_KEY_FIELDS,
1087 retention: None,
1088 triage_priority: TriagePriority::High,
1089 related_artifacts: &[],
1090 sources: &[
1091 "https://attack.mitre.org/techniques/T1547/001/",
1092 "https://learn.microsoft.com/en-us/windows/win32/setupapi/run-and-runonce-registry-keys",
1093 ],
1094};
1095
1096pub static RUN_KEY_HKLM_RUNONCE: ArtifactDescriptor = ArtifactDescriptor {
1098 id: "run_key_hklm_once",
1099 name: "RunOnce Key (HKLM)",
1100 artifact_type: ArtifactType::RegistryKey,
1101 hive: Some(HiveTarget::HklmSoftware),
1102 key_path: r"Microsoft\Windows\CurrentVersion\RunOnce",
1103 value_name: None,
1104 file_path: None,
1105 scope: DataScope::System,
1106 os_scope: OsScope::All,
1107 decoder: Decoder::Identity,
1108 meaning: "System-wide one-time autostart, deleted after first execution",
1109 mitre_techniques: &["T1547.001"],
1110 fields: RUN_KEY_FIELDS,
1111 retention: None,
1112 triage_priority: TriagePriority::High,
1113 related_artifacts: &[],
1114 sources: &[
1115 "https://attack.mitre.org/techniques/T1547/001/",
1116 "https://learn.microsoft.com/en-us/windows/win32/setupapi/run-and-runonce-registry-keys",
1117 ],
1118};
1119
1120static IFEO_FIELDS: &[FieldSchema] = &[FieldSchema {
1123 name: "debugger",
1124 value_type: ValueType::Text,
1125 description: "Debugger path that hijacks the target process launch",
1126 is_uid_component: false,
1127}];
1128
1129pub static IFEO_DEBUGGER: ArtifactDescriptor = ArtifactDescriptor {
1134 id: "ifeo_debugger",
1135 name: "IFEO Debugger Hijack",
1136 artifact_type: ArtifactType::RegistryValue,
1137 hive: Some(HiveTarget::HklmSoftware),
1138 key_path: r"Microsoft\Windows NT\CurrentVersion\Image File Execution Options",
1139 value_name: Some("Debugger"),
1140 file_path: None,
1141 scope: DataScope::System,
1142 os_scope: OsScope::All,
1143 decoder: Decoder::Identity,
1144 meaning: "Redirects target-process launch to an attacker-controlled binary",
1145 mitre_techniques: &["T1546.012"],
1146 fields: IFEO_FIELDS,
1147 retention: None,
1148 triage_priority: TriagePriority::Medium,
1149 related_artifacts: &[],
1150 sources: &[
1151 "https://attack.mitre.org/techniques/T1546/012/",
1152 "https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/enabling-postmortem-debugging",
1153 "https://www.sans.org/blog/malware-persistence-without-the-windows-registry/",
1154 ],
1155};
1156
1157pub static USERASSIST_FOLDER: ArtifactDescriptor = ArtifactDescriptor {
1163 id: "userassist_folder",
1164 name: "UserAssist (Folder)",
1165 artifact_type: ArtifactType::RegistryValue,
1166 hive: Some(HiveTarget::NtUser),
1167 key_path: r"Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist\{F4E57C4B-2036-45F0-A9AB-443BCFE33D9F}\Count",
1168 value_name: None,
1169 file_path: None,
1170 scope: DataScope::User,
1171 os_scope: OsScope::Win7Plus,
1172 decoder: Decoder::Rot13NameWithBinaryValue(USERASSIST_BINARY_FIELDS),
1173 meaning: "Folder navigation history with access counts and timestamps",
1174 mitre_techniques: &["T1083"],
1175 fields: USERASSIST_FIELDS,
1176 retention: None,
1177 triage_priority: TriagePriority::High,
1178 related_artifacts: &[],
1179 sources: &[
1180 "https://attack.mitre.org/techniques/T1083/",
1181 "https://www.sans.org/blog/computer-forensic-artifacts-windows-7-userassist/",
1182 "https://windowsir.blogspot.com/2004/02/userassist.html",
1183 "http://windowsir.blogspot.com/2007/09/more-on-userassist-keys.html",
1184 "https://www.magnetforensics.com/blog/artifact-profile-userassist/",
1185 ],
1186};
1187
1188static SHELLBAGS_FIELDS: &[FieldSchema] = &[FieldSchema {
1191 name: "indices",
1192 value_type: ValueType::List,
1193 description: "MRU order of accessed shell folder slots",
1194 is_uid_component: false,
1195}];
1196
1197pub static SHELLBAGS_USER: ArtifactDescriptor = ArtifactDescriptor {
1202 id: "shellbags_user",
1203 name: "ShellBags (User)",
1204 artifact_type: ArtifactType::RegistryKey,
1205 hive: Some(HiveTarget::UsrClass),
1206 key_path: r"Local Settings\Software\Microsoft\Windows\Shell\Bags",
1207 value_name: None,
1208 file_path: None,
1209 scope: DataScope::User,
1210 os_scope: OsScope::Win7Plus,
1211 decoder: Decoder::MruListEx,
1212 meaning: "Folder access history; persists paths even after folder deletion",
1213 mitre_techniques: &["T1083", "T1005"],
1214 fields: SHELLBAGS_FIELDS,
1215 retention: None,
1216 triage_priority: TriagePriority::High,
1217 related_artifacts: &[],
1218 sources: &[
1219 "https://attack.mitre.org/techniques/T1083/",
1220 "https://attack.mitre.org/techniques/T1005/",
1221 "https://www.sans.org/blog/shell-bag-forensics/",
1222 "https://windowsir.blogspot.com/2009/07/shellbag-analysis.html",
1223 "https://ericzimmerman.github.io/#!index.md",
1224 "https://www.sans.org/white-papers/34545/",
1225 "https://www.magnetforensics.com/blog/forensic-analysis-of-windows-shellbags/",
1226 ],
1227};
1228
1229static AMCACHE_FIELDS: &[FieldSchema] = &[
1232 FieldSchema {
1233 name: "file_id",
1234 value_type: ValueType::Text,
1235 description: "Volume GUID + MFT file reference (unique file identity)",
1236 is_uid_component: true,
1237 },
1238 FieldSchema {
1239 name: "sha1",
1240 value_type: ValueType::Text,
1241 description: "SHA1 of the first 31.25 MB (0000-prefixed)",
1242 is_uid_component: false,
1243 },
1244];
1245
1246pub static AMCACHE_APP_FILE: ArtifactDescriptor = ArtifactDescriptor {
1248 id: "amcache_app_file",
1249 name: "Amcache InventoryApplicationFile",
1250 artifact_type: ArtifactType::RegistryKey,
1251 hive: Some(HiveTarget::Amcache),
1252 key_path: r"Root\InventoryApplicationFile",
1253 value_name: None,
1254 file_path: None,
1255 scope: DataScope::System,
1256 os_scope: OsScope::Win8Plus,
1257 decoder: Decoder::Identity,
1258 meaning: "Program execution evidence with file hash; persists after binary deletion",
1259 mitre_techniques: &["T1218", "T1204.002"],
1260 fields: AMCACHE_FIELDS,
1261 retention: None,
1262 triage_priority: TriagePriority::High,
1263 related_artifacts: &["shimcache", "prefetch_dir", "srum_app_resource"],
1264 sources: &[
1265 "https://attack.mitre.org/techniques/T1218/",
1266 "https://attack.mitre.org/techniques/T1204/002/",
1267 "https://www.sans.org/blog/new-amcache-hve-in-windows-8-1-update-1/",
1268 "https://www.sansforensics.com/blog/amcache-hive-forensics/",
1269 "https://www.researchgate.net/publication/317258237_Leveraging_the_Windows_Amcachehve_File_in_Forensic_Investigations",
1270 "https://www.magnetforensics.com/blog/shimcache-vs-amcache-key-windows-forensic-artifacts/",
1271 ],
1272};
1273
1274static SHIMCACHE_FIELDS: &[FieldSchema] = &[FieldSchema {
1277 name: "raw",
1278 value_type: ValueType::Bytes,
1279 description: "Raw AppCompatCache binary blob (parsed by shimcache module)",
1280 is_uid_component: false,
1281}];
1282
1283pub static SHIMCACHE: ArtifactDescriptor = ArtifactDescriptor {
1289 id: "shimcache",
1290 name: "ShimCache (AppCompatCache)",
1291 artifact_type: ArtifactType::RegistryValue,
1292 hive: Some(HiveTarget::HklmSystem),
1293 key_path: r"CurrentControlSet\Control\Session Manager\AppCompatCache",
1294 value_name: Some("AppCompatCache"),
1295 file_path: None,
1296 scope: DataScope::System,
1297 os_scope: OsScope::All,
1298 decoder: Decoder::Identity,
1299 meaning: "Executable metadata cache; presence proves binary existed on disk",
1300 mitre_techniques: &["T1218", "T1059"],
1301 fields: SHIMCACHE_FIELDS,
1302 retention: Some("written at clean shutdown only; lost on crash/hard-power-off"),
1303 triage_priority: TriagePriority::Critical,
1304 related_artifacts: &["amcache_app_file", "prefetch_dir", "bam_user"],
1305 sources: &[
1306 "https://attack.mitre.org/techniques/T1218/",
1307 "https://attack.mitre.org/techniques/T1059/",
1308 "https://www.sans.org/blog/digital-forensics-shimcache/",
1309 "https://redcanary.com/blog/threat-detection/appcompatcache/",
1310 "https://www.sans.org/blog/mass-triage-part-4-processing-returned-files-appcache-shimcache/",
1311 "https://www.magnetforensics.com/blog/shimcache-vs-amcache-key-windows-forensic-artifacts/",
1312 ],
1313};
1314
1315static BAM_FIELDS: &[FieldSchema] = &[FieldSchema {
1318 name: "last_exec",
1319 value_type: ValueType::Timestamp,
1320 description: "FILETIME of last background execution",
1321 is_uid_component: false,
1322}];
1323
1324pub static BAM_USER: ArtifactDescriptor = ArtifactDescriptor {
1329 id: "bam_user",
1330 name: "BAM (Background Activity Moderator)",
1331 artifact_type: ArtifactType::RegistryValue,
1332 hive: Some(HiveTarget::HklmSystem),
1333 key_path: r"CurrentControlSet\Services\bam\State\UserSettings",
1334 value_name: None,
1335 file_path: None,
1336 scope: DataScope::Mixed,
1337 os_scope: OsScope::Win10Plus,
1338 decoder: Decoder::FiletimeAt { offset: 0 },
1339 meaning: "Last execution time of background/UWP processes per-user SID",
1340 mitre_techniques: &["T1059", "T1204"],
1341 fields: BAM_FIELDS,
1342 retention: Some("~7 days rolling window"),
1343 triage_priority: TriagePriority::Critical,
1344 related_artifacts: &["dam_user", "shimcache", "prefetch_dir"],
1345 sources: &[
1346 "https://attack.mitre.org/techniques/T1059/",
1347 "https://attack.mitre.org/techniques/T1204/",
1348 "https://www.sans.org/blog/background-activity-moderator-bam-forensics/",
1349 "https://www.13cubed.com/downloads/windows10_forensics_cheat_sheet.pdf",
1350 "https://forensafe.com/blogs/bam.html",
1351 "https://github.com/Psmths/windows-forensic-artifacts/blob/main/execution/bam-dam.md",
1352 ],
1353};
1354
1355static DAM_FIELDS: &[FieldSchema] = &[FieldSchema {
1356 name: "last_exec",
1357 value_type: ValueType::Timestamp,
1358 description: "FILETIME of last desktop application execution",
1359 is_uid_component: false,
1360}];
1361
1362pub static DAM_USER: ArtifactDescriptor = ArtifactDescriptor {
1364 id: "dam_user",
1365 name: "DAM (Desktop Activity Moderator)",
1366 artifact_type: ArtifactType::RegistryValue,
1367 hive: Some(HiveTarget::HklmSystem),
1368 key_path: r"CurrentControlSet\Services\dam\State\UserSettings",
1369 value_name: None,
1370 file_path: None,
1371 scope: DataScope::Mixed,
1372 os_scope: OsScope::Win10Plus,
1373 decoder: Decoder::FiletimeAt { offset: 0 },
1374 meaning: "Last execution time of desktop applications per-user SID",
1375 mitre_techniques: &["T1059", "T1204"],
1376 fields: DAM_FIELDS,
1377 retention: Some("~7 days rolling window"),
1378 triage_priority: TriagePriority::Critical,
1379 related_artifacts: &["bam_user", "shimcache"],
1380 sources: &[
1381 "https://attack.mitre.org/techniques/T1059/",
1382 "https://attack.mitre.org/techniques/T1204/",
1383 "https://www.sans.org/blog/background-activity-moderator-bam-forensics/",
1384 "https://forensafe.com/blogs/bam.html",
1385 "https://github.com/Psmths/windows-forensic-artifacts/blob/main/execution/bam-dam.md",
1386 ],
1387};
1388
1389static SAM_FIELDS: &[FieldSchema] = &[FieldSchema {
1392 name: "username",
1393 value_type: ValueType::Text,
1394 description: "Local account username (sub-key name)",
1395 is_uid_component: true,
1396}];
1397
1398pub static SAM_USERS: ArtifactDescriptor = ArtifactDescriptor {
1403 id: "sam_users",
1404 name: "SAM User Accounts",
1405 artifact_type: ArtifactType::RegistryKey,
1406 hive: Some(HiveTarget::HklmSam),
1407 key_path: r"SAM\Domains\Account\Users\Names",
1408 value_name: None,
1409 file_path: None,
1410 scope: DataScope::System,
1411 os_scope: OsScope::All,
1412 decoder: Decoder::Identity,
1413 meaning: "Local Windows accounts; F/V records contain login counts and NTLM hash metadata",
1414 mitre_techniques: &["T1003.002", "T1087.001"],
1415 fields: SAM_FIELDS,
1416 retention: None,
1417 triage_priority: TriagePriority::Critical,
1418 related_artifacts: &["lsa_secrets", "dcc2_cache"],
1419 sources: &[
1420 "https://attack.mitre.org/techniques/T1003/002/",
1421 "https://attack.mitre.org/techniques/T1087/001/",
1422 "https://www.sans.org/blog/windows-credential-storage-for-penetration-testers/",
1423 "https://windowsir.blogspot.com/2010/11/recovering-passwords.html",
1424 "http://windowsir.blogspot.com/2013/07/howto-determine-users-on-system.html",
1425 ],
1426};
1427
1428static LSA_FIELDS: &[FieldSchema] = &[FieldSchema {
1431 name: "secret_name",
1432 value_type: ValueType::Text,
1433 description: "LSA secret key name (e.g. _SC_*, DPAPI_SYSTEM, DefaultPassword)",
1434 is_uid_component: true,
1435}];
1436
1437pub static LSA_SECRETS: ArtifactDescriptor = ArtifactDescriptor {
1439 id: "lsa_secrets",
1440 name: "LSA Secrets",
1441 artifact_type: ArtifactType::RegistryKey,
1442 hive: Some(HiveTarget::HklmSecurity),
1443 key_path: r"Policy\Secrets",
1444 value_name: None,
1445 file_path: None,
1446 scope: DataScope::System,
1447 os_scope: OsScope::All,
1448 decoder: Decoder::Identity,
1449 meaning: "Encrypted service credentials, auto-logon passwords, and DPAPI master key",
1450 mitre_techniques: &["T1003.004", "T1552.002"],
1451 fields: LSA_FIELDS,
1452 retention: None,
1453 triage_priority: TriagePriority::Critical,
1454 related_artifacts: &["sam_users", "dpapi_system_masterkey", "dcc2_cache"],
1455 sources: &[
1456 "https://attack.mitre.org/techniques/T1003/004/",
1457 "https://attack.mitre.org/techniques/T1552/002/",
1458 "https://www.sans.org/blog/lsa-secrets/",
1459 ],
1460};
1461
1462static DCC2_FIELDS: &[FieldSchema] = &[FieldSchema {
1463 name: "slot_name",
1464 value_type: ValueType::Text,
1465 description: "Cache slot name (NL$1 through NL$25)",
1466 is_uid_component: true,
1467}];
1468
1469pub static DCC2_CACHE: ArtifactDescriptor = ArtifactDescriptor {
1474 id: "dcc2_cache",
1475 name: "Domain Cached Credentials 2 (DCC2)",
1476 artifact_type: ArtifactType::RegistryKey,
1477 hive: Some(HiveTarget::HklmSecurity),
1478 key_path: r"Cache",
1479 value_name: None,
1480 file_path: None,
1481 scope: DataScope::System,
1482 os_scope: OsScope::All,
1483 decoder: Decoder::Identity,
1484 meaning: "MS-Cache v2 (PBKDF2-SHA1) hashes enabling offline domain logon",
1485 mitre_techniques: &["T1003.005"],
1486 fields: DCC2_FIELDS,
1487 retention: None,
1488 triage_priority: TriagePriority::Critical,
1489 related_artifacts: &[],
1490 sources: &[
1491 "https://attack.mitre.org/techniques/T1003/005/",
1492 "https://www.sans.org/blog/windows-credential-storage-for-penetration-testers/",
1493 ],
1494};
1495
1496static TYPED_URLS_TIME_FIELDS: &[FieldSchema] = &[FieldSchema {
1499 name: "timestamp",
1500 value_type: ValueType::Timestamp,
1501 description: "FILETIME when the URL slot was typed",
1502 is_uid_component: false,
1503}];
1504
1505pub static TYPED_URLS_TIME: ArtifactDescriptor = ArtifactDescriptor {
1507 id: "typed_urls_time",
1508 name: "TypedURLsTime (IE/Edge)",
1509 artifact_type: ArtifactType::RegistryKey,
1510 hive: Some(HiveTarget::NtUser),
1511 key_path: r"Software\Microsoft\Internet Explorer\TypedURLsTime",
1512 value_name: None,
1513 file_path: None,
1514 scope: DataScope::User,
1515 os_scope: OsScope::All,
1516 decoder: Decoder::FiletimeAt { offset: 0 },
1517 meaning: "Timestamps of URLs typed into IE/Edge address bar (paired with TypedURLs)",
1518 mitre_techniques: &["T1071.001"],
1519 fields: TYPED_URLS_TIME_FIELDS,
1520 retention: None,
1521 triage_priority: TriagePriority::Medium,
1522 related_artifacts: &[],
1523 sources: &[
1524 "https://attack.mitre.org/techniques/T1071/001/",
1525 "https://www.sans.org/blog/digital-forensics-windows-registry-forensics-part-6-internet-explorer-user-typed-urls/",
1526 ],
1527};
1528
1529static MRU_RECENT_DOCS_FIELDS: &[FieldSchema] = &[FieldSchema {
1532 name: "indices",
1533 value_type: ValueType::List,
1534 description: "MRUListEx order indices of recently accessed documents",
1535 is_uid_component: false,
1536}];
1537
1538pub static MRU_RECENT_DOCS: ArtifactDescriptor = ArtifactDescriptor {
1540 id: "mru_recent_docs",
1541 name: "MRU RecentDocs",
1542 artifact_type: ArtifactType::RegistryKey,
1543 hive: Some(HiveTarget::NtUser),
1544 key_path: r"Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs",
1545 value_name: None,
1546 file_path: None,
1547 scope: DataScope::User,
1548 os_scope: OsScope::All,
1549 decoder: Decoder::MruListEx,
1550 meaning: "Most-recently-used documents list (MRUListEx order of shell32 items)",
1551 mitre_techniques: &["T1005", "T1083"],
1552 fields: MRU_RECENT_DOCS_FIELDS,
1553 retention: None,
1554 triage_priority: TriagePriority::Medium,
1555 related_artifacts: &[],
1556 sources: &[
1557 "https://attack.mitre.org/techniques/T1005/",
1558 "https://attack.mitre.org/techniques/T1083/",
1559 "https://windowsir.blogspot.com/2006/11/recent-docs-mru.html",
1560 "https://www.sans.org/blog/windows-mru-registry-keys/",
1561 "https://www.sans.org/blog/opensavemru-and-lastvisitedmru/",
1562 "https://forensics.wiki/opensavemru/",
1563 ],
1564};
1565
1566static USB_FIELDS: &[FieldSchema] = &[FieldSchema {
1569 name: "device_id",
1570 value_type: ValueType::Text,
1571 description: "USB device instance ID (VID&PID sub-key name)",
1572 is_uid_component: true,
1573}];
1574
1575pub static USB_ENUM: ArtifactDescriptor = ArtifactDescriptor {
1579 id: "usb_enum",
1580 name: "USB Device Enumeration (USBSTOR)",
1581 artifact_type: ArtifactType::RegistryKey,
1582 hive: Some(HiveTarget::HklmSystem),
1583 key_path: r"CurrentControlSet\Enum\USBSTOR",
1584 value_name: None,
1585 file_path: None,
1586 scope: DataScope::System,
1587 os_scope: OsScope::All,
1588 decoder: Decoder::Identity,
1589 meaning: "USB storage device connection history; persists after device removal",
1590 mitre_techniques: &["T1200", "T1052.001"],
1591 fields: USB_FIELDS,
1592 retention: None,
1593 triage_priority: TriagePriority::Medium,
1594 related_artifacts: &[],
1595 sources: &[
1596 "https://attack.mitre.org/techniques/T1200/",
1597 "https://attack.mitre.org/techniques/T1052/001/",
1598 "https://www.sans.org/blog/computer-forensic-artifacts-windows-7-usb-device-tracking/",
1599 "https://windowsir.blogspot.com/2013/07/usb-device-tracking-in-windows-7.html",
1600 "https://www.magnetforensics.com/blog/artifact-profile-usb-devices/",
1601 ],
1602};
1603
1604static MUICACHE_FIELDS: &[FieldSchema] = &[FieldSchema {
1607 name: "display_name",
1608 value_type: ValueType::Text,
1609 description: "Localized display name of the executed application",
1610 is_uid_component: false,
1611}];
1612
1613pub static MUICACHE: ArtifactDescriptor = ArtifactDescriptor {
1618 id: "muicache",
1619 name: "MUICache",
1620 artifact_type: ArtifactType::RegistryKey,
1621 hive: Some(HiveTarget::UsrClass),
1622 key_path: r"Local Settings\MuiCache",
1623 value_name: None,
1624 file_path: None,
1625 scope: DataScope::User,
1626 os_scope: OsScope::All,
1627 decoder: Decoder::Utf16Le,
1628 meaning: "Cached display names keyed by executable path; program execution evidence",
1629 mitre_techniques: &["T1059", "T1204.002"],
1630 fields: MUICACHE_FIELDS,
1631 retention: Some("persists until registry cleanup"),
1632 triage_priority: TriagePriority::Medium,
1633 related_artifacts: &[],
1634 sources: &[
1635 "https://attack.mitre.org/techniques/T1059/",
1636 "https://attack.mitre.org/techniques/T1204/002/",
1637 "https://windowsir.blogspot.com/2012/08/no-more-mr-nice-guy.html",
1638 "https://www.sans.org/blog/digital-forensics-windows-muicache/",
1639 "http://windowsir.blogspot.com/2005/12/mystery-of-muicachesolved.html",
1640 "https://www.magnetforensics.com/blog/forensic-analysis-of-muicache-files-in-windows/",
1641 "https://forensafe.com/blogs/muicache.html",
1642 ],
1643};
1644
1645static APPINIT_FIELDS: &[FieldSchema] = &[FieldSchema {
1648 name: "dll_list",
1649 value_type: ValueType::Text,
1650 description: "Comma/space-separated DLL paths injected into user32.dll consumers",
1651 is_uid_component: false,
1652}];
1653
1654pub static APPINIT_DLLS: ArtifactDescriptor = ArtifactDescriptor {
1658 id: "appinit_dlls",
1659 name: "AppInit_DLLs",
1660 artifact_type: ArtifactType::RegistryValue,
1661 hive: Some(HiveTarget::HklmSoftware),
1662 key_path: r"Microsoft\Windows NT\CurrentVersion\Windows",
1663 value_name: Some("AppInit_DLLs"),
1664 file_path: None,
1665 scope: DataScope::System,
1666 os_scope: OsScope::All,
1667 decoder: Decoder::Identity,
1668 meaning: "DLLs injected into every process that loads user32.dll",
1669 mitre_techniques: &["T1546.010"],
1670 fields: APPINIT_FIELDS,
1671 retention: None,
1672 triage_priority: TriagePriority::Medium,
1673 related_artifacts: &[],
1674 sources: &[
1675 "https://attack.mitre.org/techniques/T1546/010/",
1676 "https://learn.microsoft.com/en-us/windows/win32/dlls/registry-keys-for-appinit-dlls",
1677 ],
1678};
1679
1680static WINLOGON_FIELDS: &[FieldSchema] = &[FieldSchema {
1683 name: "userinit",
1684 value_type: ValueType::Text,
1685 description: "Comma-separated executables launched by Winlogon at logon",
1686 is_uid_component: false,
1687}];
1688
1689pub static WINLOGON_USERINIT: ArtifactDescriptor = ArtifactDescriptor {
1694 id: "winlogon_userinit",
1695 name: "Winlogon Userinit",
1696 artifact_type: ArtifactType::RegistryValue,
1697 hive: Some(HiveTarget::HklmSoftware),
1698 key_path: r"Microsoft\Windows NT\CurrentVersion\Winlogon",
1699 value_name: Some("Userinit"),
1700 file_path: None,
1701 scope: DataScope::System,
1702 os_scope: OsScope::All,
1703 decoder: Decoder::Identity,
1704 meaning: "Process(es) launched by Winlogon at logon; default is userinit.exe,",
1705 mitre_techniques: &["T1547.004"],
1706 fields: WINLOGON_FIELDS,
1707 retention: None,
1708 triage_priority: TriagePriority::High,
1709 related_artifacts: &[],
1710 sources: &[
1711 "https://attack.mitre.org/techniques/T1547/004/",
1712 "https://learn.microsoft.com/en-us/windows/win32/secauthn/winlogon-and-gina",
1713 ],
1714};
1715
1716static SCREENSAVER_FIELDS: &[FieldSchema] = &[FieldSchema {
1719 name: "path",
1720 value_type: ValueType::Text,
1721 description: "Path to the screensaver executable (.scr)",
1722 is_uid_component: false,
1723}];
1724
1725pub static SCREENSAVER_EXE: ArtifactDescriptor = ArtifactDescriptor {
1730 id: "screensaver_exe",
1731 name: "Screensaver Executable",
1732 artifact_type: ArtifactType::RegistryValue,
1733 hive: Some(HiveTarget::NtUser),
1734 key_path: r"Control Panel\Desktop",
1735 value_name: Some("SCRNSAVE.EXE"),
1736 file_path: None,
1737 scope: DataScope::User,
1738 os_scope: OsScope::All,
1739 decoder: Decoder::Identity,
1740 meaning: "Screensaver path; malicious .scr enables persistence on screen lock",
1741 mitre_techniques: &["T1546.002"],
1742 fields: SCREENSAVER_FIELDS,
1743 retention: None,
1744 triage_priority: TriagePriority::Medium,
1745 related_artifacts: &[],
1746 sources: &[
1747 "https://attack.mitre.org/techniques/T1546/002/",
1748 "https://www.sans.org/blog/screensaver-registry-key-for-persistence/",
1749 ],
1750};
1751
1752static PERSIST_CMD_FIELDS: &[FieldSchema] = &[FieldSchema {
1760 name: "command",
1761 value_type: ValueType::Text,
1762 description: "Command, DLL path, or executable registered for execution",
1763 is_uid_component: false,
1764}];
1765
1766static DLL_FIELDS: &[FieldSchema] = &[FieldSchema {
1768 name: "dll_path",
1769 value_type: ValueType::Text,
1770 description: "Path to the DLL registered for injection or loading",
1771 is_uid_component: false,
1772}];
1773
1774static DIR_ENTRY_FIELDS: &[FieldSchema] = &[FieldSchema {
1776 name: "entry_name",
1777 value_type: ValueType::Text,
1778 description: "Name of the file or shortcut present in this directory",
1779 is_uid_component: true,
1780}];
1781
1782static FILE_PATH_FIELDS: &[FieldSchema] = &[FieldSchema {
1784 name: "path",
1785 value_type: ValueType::Text,
1786 description: "Full path to the artifact file",
1787 is_uid_component: true,
1788}];
1789
1790pub static WINLOGON_SHELL: ArtifactDescriptor = ArtifactDescriptor {
1797 id: "winlogon_shell",
1798 name: "Winlogon Shell",
1799 artifact_type: ArtifactType::RegistryValue,
1800 hive: Some(HiveTarget::HklmSoftware),
1801 key_path: r"Microsoft\Windows NT\CurrentVersion\Winlogon",
1802 value_name: Some("Shell"),
1803 file_path: None,
1804 scope: DataScope::System,
1805 os_scope: OsScope::All,
1806 decoder: Decoder::Identity,
1807 meaning: "Windows shell process(es) launched by Winlogon; default is explorer.exe",
1808 mitre_techniques: &["T1547.004"],
1809 fields: PERSIST_CMD_FIELDS,
1810 retention: None,
1811 triage_priority: TriagePriority::High,
1812 related_artifacts: &[],
1813 sources: &[
1814 "https://attack.mitre.org/techniques/T1547/004/",
1815 "https://learn.microsoft.com/en-us/windows/win32/secauthn/winlogon-and-gina",
1816 ],
1817};
1818
1819pub static SERVICES_IMAGEPATH: ArtifactDescriptor = ArtifactDescriptor {
1824 id: "services_imagepath",
1825 name: "Services ImagePath",
1826 artifact_type: ArtifactType::RegistryKey,
1827 hive: Some(HiveTarget::HklmSystem),
1828 key_path: r"CurrentControlSet\Services",
1829 value_name: Some("ImagePath"),
1830 file_path: None,
1831 scope: DataScope::System,
1832 os_scope: OsScope::All,
1833 decoder: Decoder::Identity,
1834 meaning: "Executable path of a Windows service; auto-started services persist across reboots",
1835 mitre_techniques: &["T1543.003"],
1836 fields: PERSIST_CMD_FIELDS,
1837 retention: None,
1838 triage_priority: TriagePriority::High,
1839 related_artifacts: &[],
1840 sources: &[
1841 "https://attack.mitre.org/techniques/T1543/003/",
1842 "https://learn.microsoft.com/en-us/windows/win32/services/service-control-manager",
1843 "https://redcanary.com/threat-detection-report/techniques/t1543/",
1844 ],
1845};
1846
1847static ACTIVE_SETUP_FIELDS: &[FieldSchema] = &[FieldSchema {
1848 name: "stub_path",
1849 value_type: ValueType::Text,
1850 description: "StubPath command executed once per user at logon for new installs",
1851 is_uid_component: false,
1852}];
1853
1854pub static ACTIVE_SETUP_HKLM: ArtifactDescriptor = ArtifactDescriptor {
1859 id: "active_setup_hklm",
1860 name: "Active Setup (HKLM)",
1861 artifact_type: ArtifactType::RegistryKey,
1862 hive: Some(HiveTarget::HklmSoftware),
1863 key_path: r"Microsoft\Active Setup\Installed Components",
1864 value_name: Some("StubPath"),
1865 file_path: None,
1866 scope: DataScope::System,
1867 os_scope: OsScope::All,
1868 decoder: Decoder::Identity,
1869 meaning: "Per-user setup command executed by HKLM Active Setup; malicious StubPath = user-context persistence",
1870 mitre_techniques: &["T1547.014"],
1871 fields: ACTIVE_SETUP_FIELDS,
1872 retention: None,
1873 triage_priority: TriagePriority::High,
1874 related_artifacts: &[],
1875 sources: &[
1876 "https://attack.mitre.org/techniques/T1547/014/",
1877 "https://www.sans.org/blog/active-setup-registry-persistence/",
1878 ],
1879};
1880
1881pub static ACTIVE_SETUP_HKCU: ArtifactDescriptor = ArtifactDescriptor {
1885 id: "active_setup_hkcu",
1886 name: "Active Setup (HKCU)",
1887 artifact_type: ArtifactType::RegistryKey,
1888 hive: Some(HiveTarget::NtUser),
1889 key_path: r"Software\Microsoft\Active Setup\Installed Components",
1890 value_name: Some("Version"),
1891 file_path: None,
1892 scope: DataScope::User,
1893 os_scope: OsScope::All,
1894 decoder: Decoder::Identity,
1895 meaning: "User-side Active Setup version; mismatch with HKLM triggers StubPath re-execution",
1896 mitre_techniques: &["T1547.014"],
1897 fields: RUN_KEY_FIELDS,
1898 retention: None,
1899 triage_priority: TriagePriority::High,
1900 related_artifacts: &[],
1901 sources: &["https://attack.mitre.org/techniques/T1547/014/"],
1902};
1903
1904pub static COM_HIJACK_CLSID_HKCU: ArtifactDescriptor = ArtifactDescriptor {
1910 id: "com_hijack_clsid_hkcu",
1911 name: "COM Hijack CLSID (HKCU)",
1912 artifact_type: ArtifactType::RegistryKey,
1913 hive: Some(HiveTarget::UsrClass),
1914 key_path: r"CLSID",
1915 value_name: Some("InprocServer32"),
1916 file_path: None,
1917 scope: DataScope::User,
1918 os_scope: OsScope::Win7Plus,
1919 decoder: Decoder::Identity,
1920 meaning: "User-space CLSID registration overriding system COM server; no admin needed",
1921 mitre_techniques: &["T1546.015"],
1922 fields: DLL_FIELDS,
1923 retention: None,
1924 triage_priority: TriagePriority::Medium,
1925 related_artifacts: &[],
1926 sources: &[
1927 "https://attack.mitre.org/techniques/T1546/015/",
1928 "https://redcanary.com/threat-detection-report/techniques/t1546/",
1929 ],
1930};
1931
1932pub static APPCERT_DLLS: ArtifactDescriptor = ArtifactDescriptor {
1937 id: "appcert_dlls",
1938 name: "AppCertDlls",
1939 artifact_type: ArtifactType::RegistryKey,
1940 hive: Some(HiveTarget::HklmSystem),
1941 key_path: r"CurrentControlSet\Control\Session Manager\AppCertDlls",
1942 value_name: None,
1943 file_path: None,
1944 scope: DataScope::System,
1945 os_scope: OsScope::All,
1946 decoder: Decoder::Identity,
1947 meaning: "DLLs injected into every process that calls CreateProcess-family APIs",
1948 mitre_techniques: &["T1546.009"],
1949 fields: DLL_FIELDS,
1950 retention: None,
1951 triage_priority: TriagePriority::Medium,
1952 related_artifacts: &[],
1953 sources: &[
1954 "https://attack.mitre.org/techniques/T1546/009/",
1955 "https://learn.microsoft.com/en-us/windows/win32/devnotes/appcertdlls",
1956 ],
1957};
1958
1959static BOOT_EXECUTE_FIELDS: &[FieldSchema] = &[FieldSchema {
1960 name: "commands",
1961 value_type: ValueType::List,
1962 description: "Commands executed by Session Manager before Win32 subsystem starts",
1963 is_uid_component: false,
1964}];
1965
1966pub static BOOT_EXECUTE: ArtifactDescriptor = ArtifactDescriptor {
1971 id: "boot_execute",
1972 name: "Boot Execute",
1973 artifact_type: ArtifactType::RegistryValue,
1974 hive: Some(HiveTarget::HklmSystem),
1975 key_path: r"CurrentControlSet\Control\Session Manager",
1976 value_name: Some("BootExecute"),
1977 file_path: None,
1978 scope: DataScope::System,
1979 os_scope: OsScope::All,
1980 decoder: Decoder::MultiSz,
1981 meaning: "Native executables run by smss.exe at boot; executes before most security software",
1982 mitre_techniques: &["T1547.001"],
1983 fields: BOOT_EXECUTE_FIELDS,
1984 retention: None,
1985 triage_priority: TriagePriority::High,
1986 related_artifacts: &[],
1987 sources: &[
1988 "https://attack.mitre.org/techniques/T1547/001/",
1989 "https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/boot-time-global-flag-settings",
1990 ],
1991};
1992
1993pub static LSA_SECURITY_PKGS: ArtifactDescriptor = ArtifactDescriptor {
1998 id: "lsa_security_pkgs",
1999 name: "LSA Security Packages",
2000 artifact_type: ArtifactType::RegistryValue,
2001 hive: Some(HiveTarget::HklmSystem),
2002 key_path: r"CurrentControlSet\Control\Lsa",
2003 value_name: Some("Security Packages"),
2004 file_path: None,
2005 scope: DataScope::System,
2006 os_scope: OsScope::All,
2007 decoder: Decoder::MultiSz,
2008 meaning: "Security Support Providers loaded into LSASS; malicious SSP = persistent LSASS credential access",
2009 mitre_techniques: &["T1547.005"],
2010 fields: BOOT_EXECUTE_FIELDS,
2011 retention: None,
2012 triage_priority: TriagePriority::High,
2013 related_artifacts: &[],
2014 sources: &[
2015 "https://attack.mitre.org/techniques/T1547/005/",
2016 "https://learn.microsoft.com/en-us/windows/win32/secauthn/lsa-authentication",
2017 ],
2018};
2019
2020pub static LSA_AUTH_PKGS: ArtifactDescriptor = ArtifactDescriptor {
2022 id: "lsa_auth_pkgs",
2023 name: "LSA Authentication Packages",
2024 artifact_type: ArtifactType::RegistryValue,
2025 hive: Some(HiveTarget::HklmSystem),
2026 key_path: r"CurrentControlSet\Control\Lsa",
2027 value_name: Some("Authentication Packages"),
2028 file_path: None,
2029 scope: DataScope::System,
2030 os_scope: OsScope::All,
2031 decoder: Decoder::MultiSz,
2032 meaning: "Authentication packages loaded by LSASS; extra DLLs intercept logon credentials",
2033 mitre_techniques: &["T1547.002"],
2034 fields: BOOT_EXECUTE_FIELDS,
2035 retention: None,
2036 triage_priority: TriagePriority::High,
2037 related_artifacts: &[],
2038 sources: &[
2039 "https://attack.mitre.org/techniques/T1547/002/",
2040 "https://attack.mitre.org/techniques/T1547/005/",
2041 "https://learn.microsoft.com/en-us/windows/win32/secauthn/lsa-authentication",
2042 ],
2043};
2044
2045pub static PRINT_MONITORS: ArtifactDescriptor = ArtifactDescriptor {
2049 id: "print_monitors",
2050 name: "Print Monitors",
2051 artifact_type: ArtifactType::RegistryKey,
2052 hive: Some(HiveTarget::HklmSystem),
2053 key_path: r"CurrentControlSet\Control\Print\Monitors",
2054 value_name: Some("Driver"),
2055 file_path: None,
2056 scope: DataScope::System,
2057 os_scope: OsScope::All,
2058 decoder: Decoder::Identity,
2059 meaning: "DLL loaded into spoolsv.exe (SYSTEM); extra monitors = SYSTEM persistence",
2060 mitre_techniques: &["T1547.010"],
2061 fields: DLL_FIELDS,
2062 retention: None,
2063 triage_priority: TriagePriority::Medium,
2064 related_artifacts: &[],
2065 sources: &[
2066 "https://attack.mitre.org/techniques/T1547/010/",
2067 "https://learn.microsoft.com/en-us/windows-hardware/drivers/print/print-monitor",
2068 ],
2069};
2070
2071pub static TIME_PROVIDERS: ArtifactDescriptor = ArtifactDescriptor {
2073 id: "time_providers",
2074 name: "W32Time Time Provider DLLs",
2075 artifact_type: ArtifactType::RegistryKey,
2076 hive: Some(HiveTarget::HklmSystem),
2077 key_path: r"CurrentControlSet\Services\W32Time\TimeProviders",
2078 value_name: Some("DllName"),
2079 file_path: None,
2080 scope: DataScope::System,
2081 os_scope: OsScope::All,
2082 decoder: Decoder::Identity,
2083 meaning: "DLLs loaded by the Windows Time service; malicious entry = SYSTEM persistence",
2084 mitre_techniques: &["T1547.003"],
2085 fields: DLL_FIELDS,
2086 retention: None,
2087 triage_priority: TriagePriority::Medium,
2088 related_artifacts: &[],
2089 sources: &[
2090 "https://attack.mitre.org/techniques/T1547/003/",
2091 "https://learn.microsoft.com/en-us/windows/win32/sysinfo/time-provider",
2092 ],
2093};
2094
2095pub static NETSH_HELPER_DLLS: ArtifactDescriptor = ArtifactDescriptor {
2097 id: "netsh_helper_dlls",
2098 name: "Netsh Helper DLLs",
2099 artifact_type: ArtifactType::RegistryKey,
2100 hive: Some(HiveTarget::HklmSoftware),
2101 key_path: r"Microsoft\NetSh",
2102 value_name: None,
2103 file_path: None,
2104 scope: DataScope::System,
2105 os_scope: OsScope::All,
2106 decoder: Decoder::Identity,
2107 meaning: "DLLs loaded whenever netsh.exe is invoked; attacker DLL runs in user's netsh context",
2108 mitre_techniques: &["T1546.007"],
2109 fields: DLL_FIELDS,
2110 retention: None,
2111 triage_priority: TriagePriority::Medium,
2112 related_artifacts: &[],
2113 sources: &[
2114 "https://attack.mitre.org/techniques/T1546/007/",
2115 "https://learn.microsoft.com/en-us/windows/win32/netmgmt/network-management-functions",
2116 ],
2117};
2118
2119static BHO_FIELDS: &[FieldSchema] = &[FieldSchema {
2120 name: "clsid",
2121 value_type: ValueType::Text,
2122 description: "CLSID of the Browser Helper Object (sub-key name)",
2123 is_uid_component: true,
2124}];
2125
2126pub static BROWSER_HELPER_OBJECTS: ArtifactDescriptor = ArtifactDescriptor {
2131 id: "browser_helper_objects",
2132 name: "Internet Explorer Browser Helper Objects",
2133 artifact_type: ArtifactType::RegistryKey,
2134 hive: Some(HiveTarget::HklmSoftware),
2135 key_path: r"Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects",
2136 value_name: None,
2137 file_path: None,
2138 scope: DataScope::System,
2139 os_scope: OsScope::All,
2140 decoder: Decoder::Identity,
2141 meaning: "COM components auto-loaded into IE; can intercept browsing and steal credentials",
2142 mitre_techniques: &["T1176"],
2143 fields: BHO_FIELDS,
2144 retention: None,
2145 triage_priority: TriagePriority::Medium,
2146 related_artifacts: &[],
2147 sources: &[
2148 "https://attack.mitre.org/techniques/T1176/",
2149 "https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa753582(v=vs.85)",
2150 ],
2151};
2152
2153pub static STARTUP_FOLDER_USER: ArtifactDescriptor = ArtifactDescriptor {
2157 id: "startup_folder_user",
2158 name: "User Startup Folder",
2159 artifact_type: ArtifactType::Directory,
2160 hive: None,
2161 key_path: "",
2162 value_name: None,
2163 file_path: Some(r"C:\Users\*\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"),
2164 scope: DataScope::User,
2165 os_scope: OsScope::All,
2166 decoder: Decoder::Identity,
2167 meaning: "Executables and LNKs here run at user logon; no admin required",
2168 mitre_techniques: &["T1547.001"],
2169 fields: DIR_ENTRY_FIELDS,
2170 retention: None,
2171 triage_priority: TriagePriority::Medium,
2172 related_artifacts: &[],
2173 sources: &[
2174 "https://attack.mitre.org/techniques/T1547/001/",
2175 "https://learn.microsoft.com/en-us/windows/win32/shell/csidl",
2176 ],
2177};
2178
2179pub static STARTUP_FOLDER_SYSTEM: ArtifactDescriptor = ArtifactDescriptor {
2181 id: "startup_folder_system",
2182 name: "System Startup Folder",
2183 artifact_type: ArtifactType::Directory,
2184 hive: None,
2185 key_path: "",
2186 value_name: None,
2187 file_path: Some(r"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp"),
2188 scope: DataScope::System,
2189 os_scope: OsScope::All,
2190 decoder: Decoder::Identity,
2191 meaning: "Executables and LNKs run for every user at logon; requires admin to plant",
2192 mitre_techniques: &["T1547.001"],
2193 fields: DIR_ENTRY_FIELDS,
2194 retention: None,
2195 triage_priority: TriagePriority::Medium,
2196 related_artifacts: &[],
2197 sources: &[
2198 "https://attack.mitre.org/techniques/T1547/001/",
2199 "https://learn.microsoft.com/en-us/windows/win32/shell/csidl",
2200 ],
2201};
2202
2203pub static SCHEDULED_TASKS_DIR: ArtifactDescriptor = ArtifactDescriptor {
2208 id: "scheduled_tasks_dir",
2209 name: "Scheduled Tasks Directory",
2210 artifact_type: ArtifactType::Directory,
2211 hive: None,
2212 key_path: "",
2213 value_name: None,
2214 file_path: Some(r"C:\Windows\System32\Tasks"),
2215 scope: DataScope::System,
2216 os_scope: OsScope::Win7Plus,
2217 decoder: Decoder::Identity,
2218 meaning: "XML task definitions; malicious tasks can run at boot, logon, or arbitrary intervals",
2219 mitre_techniques: &["T1053.005"],
2220 fields: DIR_ENTRY_FIELDS,
2221 retention: None,
2222 triage_priority: TriagePriority::High,
2223 related_artifacts: &[],
2224 sources: &[
2225 "https://attack.mitre.org/techniques/T1053/005/",
2226 "https://learn.microsoft.com/en-us/windows/win32/taskschd/task-scheduler-start-page",
2227 "https://redcanary.com/threat-detection-report/techniques/t1053/",
2228 ],
2229};
2230
2231pub static WDIGEST_CACHING: ArtifactDescriptor = ArtifactDescriptor {
2236 id: "wdigest_caching",
2237 name: "WDigest UseLogonCredential",
2238 artifact_type: ArtifactType::RegistryValue,
2239 hive: Some(HiveTarget::HklmSystem),
2240 key_path: r"CurrentControlSet\Control\SecurityProviders\WDigest",
2241 value_name: Some("UseLogonCredential"),
2242 file_path: None,
2243 scope: DataScope::System,
2244 os_scope: OsScope::All,
2245 decoder: Decoder::DwordLe,
2246 meaning:
2247 "1 = cleartext creds in LSASS; attackers set this before Mimikatz to harvest passwords",
2248 mitre_techniques: &["T1003.001"],
2249 fields: RUN_KEY_FIELDS,
2250 retention: None,
2251 triage_priority: TriagePriority::Medium,
2252 related_artifacts: &[],
2253 sources: &[
2254 "https://attack.mitre.org/techniques/T1003/001/",
2255 "https://redcanary.com/threat-detection-report/techniques/t1003/",
2256 ],
2257};
2258
2259pub static WORDWHEEL_QUERY: ArtifactDescriptor = ArtifactDescriptor {
2263 id: "wordwheel_query",
2264 name: "WordWheelQuery (Explorer Search)",
2265 artifact_type: ArtifactType::RegistryKey,
2266 hive: Some(HiveTarget::NtUser),
2267 key_path: r"Software\Microsoft\Windows\CurrentVersion\Explorer\WordWheelQuery",
2268 value_name: None,
2269 file_path: None,
2270 scope: DataScope::User,
2271 os_scope: OsScope::Win7Plus,
2272 decoder: Decoder::MruListEx,
2273 meaning:
2274 "Search terms entered into Windows Explorer search bar; reveals attacker reconnaissance",
2275 mitre_techniques: &["T1083"],
2276 fields: MRU_RECENT_DOCS_FIELDS,
2277 retention: None,
2278 triage_priority: TriagePriority::Medium,
2279 related_artifacts: &[],
2280 sources: &[
2281 "https://attack.mitre.org/techniques/T1083/",
2282 "https://windowsir.blogspot.com/2012/08/wordwheelquery.html",
2283 ],
2284};
2285
2286pub static OPENSAVE_MRU: ArtifactDescriptor = ArtifactDescriptor {
2291 id: "opensave_mru",
2292 name: "OpenSaveMRU (Common Dialog)",
2293 artifact_type: ArtifactType::RegistryKey,
2294 hive: Some(HiveTarget::NtUser),
2295 key_path: r"Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\OpenSaveMRU",
2296 value_name: None,
2297 file_path: None,
2298 scope: DataScope::User,
2299 os_scope: OsScope::All,
2300 decoder: Decoder::MruListEx,
2301 meaning: "Paths of files opened or saved via Win32 common dialog boxes; per-extension history",
2302 mitre_techniques: &["T1083"],
2303 fields: MRU_RECENT_DOCS_FIELDS,
2304 retention: None,
2305 triage_priority: TriagePriority::Medium,
2306 related_artifacts: &[],
2307 sources: &[
2308 "https://attack.mitre.org/techniques/T1083/",
2309 "https://windowsir.blogspot.com/2006/11/recent-docs-mru.html",
2310 "https://www.sans.org/blog/opensavemru-and-lastvisitedmru/",
2311 "https://forensics.wiki/opensavemru/",
2312 ],
2313};
2314
2315pub static LASTVISITED_MRU: ArtifactDescriptor = ArtifactDescriptor {
2317 id: "lastvisited_mru",
2318 name: "LastVisitedMRU (Common Dialog)",
2319 artifact_type: ArtifactType::RegistryKey,
2320 hive: Some(HiveTarget::NtUser),
2321 key_path: r"Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\LastVisitedMRU",
2322 value_name: None,
2323 file_path: None,
2324 scope: DataScope::User,
2325 os_scope: OsScope::All,
2326 decoder: Decoder::MruListEx,
2327 meaning: "Application + last-used folder from common dialog; reveals programs accessing files",
2328 mitre_techniques: &["T1083"],
2329 fields: MRU_RECENT_DOCS_FIELDS,
2330 retention: None,
2331 triage_priority: TriagePriority::Medium,
2332 related_artifacts: &[],
2333 sources: &[
2334 "https://attack.mitre.org/techniques/T1083/",
2335 "https://windowsir.blogspot.com/2006/11/recent-docs-mru.html",
2336 "https://www.sans.org/blog/opensavemru-and-lastvisitedmru/",
2337 ],
2338};
2339
2340pub static PREFETCH_DIR: ArtifactDescriptor = ArtifactDescriptor {
2345 id: "prefetch_dir",
2346 name: "Prefetch Files Directory",
2347 artifact_type: ArtifactType::Directory,
2348 hive: None,
2349 key_path: "",
2350 value_name: None,
2351 file_path: Some(r"C:\Windows\Prefetch"),
2352 scope: DataScope::System,
2353 os_scope: OsScope::All,
2354 decoder: Decoder::Identity,
2355 meaning: "Binary .pf files recording 30-day program execution history with timestamps",
2356 mitre_techniques: &["T1204.002"],
2357 fields: DIR_ENTRY_FIELDS,
2358 retention: Some("128 entries; oldest evicted"),
2359 triage_priority: TriagePriority::High,
2360 related_artifacts: &["shimcache", "amcache_app_file", "bam_user"],
2361 sources: &[
2362 "https://attack.mitre.org/techniques/T1204/002/",
2363 "https://www.sans.org/blog/computer-forensic-artifacts-windows-7-prefetch-files/",
2364 "https://13cubed.com/downloads/Windows_Forensic_Analysis_Poster.pdf",
2365 "https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/application-verifier",
2366 "https://isc.sans.edu/diary/Forensic+Value+of+Prefetch/29168",
2367 "https://www.magnetforensics.com/blog/forensic-analysis-of-prefetch-files-in-windows/",
2368 ],
2369};
2370
2371static SRUM_FIELDS: &[FieldSchema] = &[
2372 FieldSchema {
2373 name: "app_name",
2374 value_type: ValueType::Text,
2375 description: "Application executable path or service name",
2376 is_uid_component: true,
2377 },
2378 FieldSchema {
2379 name: "user_sid",
2380 value_type: ValueType::Text,
2381 description: "SID of the user who ran the application",
2382 is_uid_component: false,
2383 },
2384];
2385
2386pub static SRUM_DB: ArtifactDescriptor = ArtifactDescriptor {
2392 id: "srum_db",
2393 name: "SRUM Database (SRUDB.dat)",
2394 artifact_type: ArtifactType::File,
2395 hive: None,
2396 key_path: "",
2397 value_name: None,
2398 file_path: Some(r"C:\Windows\System32\sru\SRUDB.dat"),
2399 scope: DataScope::System,
2400 os_scope: OsScope::Win8Plus,
2401 decoder: Decoder::Identity,
2402 meaning:
2403 "Per-app CPU, network, and energy usage records; execution timeline survives log clearing",
2404 mitre_techniques: &["T1204.002"],
2405 fields: SRUM_FIELDS,
2406 retention: Some("~30 days"),
2407 triage_priority: TriagePriority::Critical,
2408 related_artifacts: &[],
2409 sources: &[
2410 "https://attack.mitre.org/techniques/T1204/002/",
2411 "https://www.sans.org/white-papers/36660/",
2412 "https://www.sans.org/blog/srum-forensics/",
2413 "https://www.magnetforensics.com/blog/srum-forensic-analysis-of-windows-system-resource-utilization-monitor/",
2414 "https://github.com/MarkBaggett/srum-dump",
2415 ],
2416};
2417
2418pub static WINDOWS_TIMELINE: ArtifactDescriptor = ArtifactDescriptor {
2423 id: "windows_timeline",
2424 name: "Windows Timeline (ActivitiesCache.db)",
2425 artifact_type: ArtifactType::File,
2426 hive: None,
2427 key_path: "",
2428 value_name: None,
2429 file_path: Some(r"C:\Users\*\AppData\Local\ConnectedDevicesPlatform\*\ActivitiesCache.db"),
2430 scope: DataScope::User,
2431 os_scope: OsScope::Win10Plus,
2432 decoder: Decoder::Identity,
2433 meaning:
2434 "Application activity timeline including focus time, file access, and clipboard events",
2435 mitre_techniques: &["T1059", "T1204.002"],
2436 fields: SRUM_FIELDS,
2437 retention: Some("~30 days"),
2438 triage_priority: TriagePriority::Medium,
2439 related_artifacts: &[],
2440 sources: &[
2441 "https://attack.mitre.org/techniques/T1059/",
2442 "https://attack.mitre.org/techniques/T1204/002/",
2443 "https://www.sans.org/blog/windows-10-timeline-forensic-artifacts/",
2444 "https://aboutdfir.com/windows-10-timeline/",
2445 "http://windowsir.blogspot.com/2019/11/activitescachedb-vs-ntuserdat.html",
2446 "https://kacos2000.github.io/WindowsTimeline/",
2447 ],
2448};
2449
2450pub static POWERSHELL_HISTORY: ArtifactDescriptor = ArtifactDescriptor {
2455 id: "powershell_history",
2456 name: "PowerShell PSReadLine History",
2457 artifact_type: ArtifactType::File,
2458 hive: None,
2459 key_path: "",
2460 value_name: None,
2461 file_path: Some(
2462 r"C:\Users\*\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt",
2463 ),
2464 scope: DataScope::User,
2465 os_scope: OsScope::Win10Plus,
2466 decoder: Decoder::Identity,
2467 meaning: "Line-by-line PowerShell interactive command history; attackers often clear this",
2468 mitre_techniques: &["T1059.001", "T1552"],
2469 fields: FILE_PATH_FIELDS,
2470 retention: Some("4096 commands; oldest evicted when limit reached"),
2471 triage_priority: TriagePriority::High,
2472 related_artifacts: &[],
2473 sources: &[
2474 "https://attack.mitre.org/techniques/T1059/001/",
2475 "https://attack.mitre.org/techniques/T1552/",
2476 "https://www.sans.org/blog/powershell-forensics/",
2477 "https://redcanary.com/threat-detection-report/techniques/t1059.001/",
2478 "https://community.sophos.com/sophos-labs/b/blog/posts/powershell-command-history-forensics",
2479 ],
2480};
2481
2482pub static RECYCLE_BIN: ArtifactDescriptor = ArtifactDescriptor {
2487 id: "recycle_bin",
2488 name: "Recycle Bin ($I Metadata)",
2489 artifact_type: ArtifactType::Directory,
2490 hive: None,
2491 key_path: "",
2492 value_name: None,
2493 file_path: Some(r"C:\$Recycle.Bin\*"),
2494 scope: DataScope::User,
2495 os_scope: OsScope::Win7Plus,
2496 decoder: Decoder::Identity,
2497 meaning: "$I files reveal original path and deletion time even after Recycle Bin is emptied",
2498 mitre_techniques: &["T1070.004", "T1083"],
2499 fields: DIR_ENTRY_FIELDS,
2500 retention: None,
2501 triage_priority: TriagePriority::Medium,
2502 related_artifacts: &[],
2503 sources: &[
2504 "https://attack.mitre.org/techniques/T1070/004/",
2505 "https://attack.mitre.org/techniques/T1083/",
2506 "https://www.sans.org/blog/digital-forensics-recycle-bin-forensics/",
2507 "https://windowsir.blogspot.com/2010/02/more-on-recycle-bin.html",
2508 "https://www.magnetforensics.com/blog/artifact-profile-recycle-bin/",
2509 "https://andreafortuna.org/2019/09/26/windows-forensics-analysis-of-recycle-bin-artifacts/",
2510 ],
2511};
2512
2513pub static THUMBCACHE: ArtifactDescriptor = ArtifactDescriptor {
2518 id: "thumbcache",
2519 name: "Explorer Thumbnail Cache",
2520 artifact_type: ArtifactType::Directory,
2521 hive: None,
2522 key_path: "",
2523 value_name: None,
2524 file_path: Some(r"C:\Users\*\AppData\Local\Microsoft\Windows\Explorer"),
2525 scope: DataScope::User,
2526 os_scope: OsScope::Win7Plus,
2527 decoder: Decoder::Identity,
2528 meaning: "Cached thumbnails including deleted files; proves files were viewed via Explorer",
2529 mitre_techniques: &["T1083"],
2530 fields: DIR_ENTRY_FIELDS,
2531 retention: None,
2532 triage_priority: TriagePriority::Medium,
2533 related_artifacts: &[],
2534 sources: &[
2535 "https://attack.mitre.org/techniques/T1083/",
2536 "https://www.sans.org/blog/thumbnail-cache-forensics/",
2537 "https://www.nirsoft.net/utils/thumbcache_viewer.html",
2538 "https://www.pentestpartners.com/security-blog/thumbnail-forensics-dfir-techniques-for-analysing-windows-thumbcache/",
2539 "https://thumbcacheviewer.github.io/",
2540 "https://forensics.wiki/windows_thumbcache/",
2541 ],
2542};
2543
2544pub static SEARCH_DB_USER: ArtifactDescriptor = ArtifactDescriptor {
2549 id: "search_db_user",
2550 name: "Windows Search Database (Windows.db)",
2551 artifact_type: ArtifactType::File,
2552 hive: None,
2553 key_path: "",
2554 value_name: None,
2555 file_path: Some(r"C:\ProgramData\Microsoft\Search\Data\Applications\Windows\Windows.edb"),
2556 scope: DataScope::System,
2557 os_scope: OsScope::All,
2558 decoder: Decoder::Identity,
2559 meaning:
2560 "ESE database of indexed file metadata; reveals filenames and content even after deletion",
2561 mitre_techniques: &["T1083"],
2562 fields: FILE_PATH_FIELDS,
2563 retention: None,
2564 triage_priority: TriagePriority::Medium,
2565 related_artifacts: &[],
2566 sources: &[
2567 "https://attack.mitre.org/techniques/T1083/",
2568 "https://www.sans.org/blog/windows-search-index-forensics/",
2569 "https://learn.microsoft.com/en-us/windows/win32/search/windows-search",
2570 "https://cyber.aon.com/aon_cyber_labs/windows-search-index-the-forensic-artifact-youve-been-searching-for/",
2571 ],
2572};
2573
2574static DPAPI_FIELDS: &[FieldSchema] = &[FieldSchema {
2577 name: "guid",
2578 value_type: ValueType::Text,
2579 description: "GUID filename of the DPAPI master key or credential blob",
2580 is_uid_component: true,
2581}];
2582
2583pub static DPAPI_MASTERKEY_USER: ArtifactDescriptor = ArtifactDescriptor {
2588 id: "dpapi_masterkey_user",
2589 name: "DPAPI User Master Keys",
2590 artifact_type: ArtifactType::Directory,
2591 hive: None,
2592 key_path: "",
2593 value_name: None,
2594 file_path: Some(r"C:\Users\*\AppData\Roaming\Microsoft\Protect\*"),
2595 scope: DataScope::User,
2596 os_scope: OsScope::All,
2597 decoder: Decoder::Identity,
2598 meaning: "Master keys protecting all DPAPI-encrypted user secrets (credentials, browser passwords, WiFi PSKs)",
2599 mitre_techniques: &["T1555.004"],
2600 fields: DPAPI_FIELDS,
2601 retention: None,
2602 triage_priority: TriagePriority::Critical,
2603 related_artifacts: &["dpapi_cred_user", "dpapi_credhist", "chrome_login_data"],
2604 sources: &[
2605 "https://attack.mitre.org/techniques/T1555/004/",
2606 "https://www.sans.org/blog/dpapi-forensics-credentials-stored-in-windows/",
2607 "https://posts.specterops.io/operational-guidance-for-offensive-user-dpapi-abuse-1fb7fac8b107",
2608 "https://www.sygnia.co/blog/the-downfall-of-dpapis-top-secret-weapon/",
2609 ],
2610};
2611
2612pub static DPAPI_CRED_USER: ArtifactDescriptor = ArtifactDescriptor {
2617 id: "dpapi_cred_user",
2618 name: "DPAPI Credential Blobs (Local)",
2619 artifact_type: ArtifactType::Directory,
2620 hive: None,
2621 key_path: "",
2622 value_name: None,
2623 file_path: Some(r"C:\Users\*\AppData\Local\Microsoft\Credentials"),
2624 scope: DataScope::User,
2625 os_scope: OsScope::All,
2626 decoder: Decoder::Identity,
2627 meaning:
2628 "DPAPI-encrypted credential blobs for network resources; decryptable with DPAPI master key",
2629 mitre_techniques: &["T1555.004"],
2630 fields: DPAPI_FIELDS,
2631 retention: None,
2632 triage_priority: TriagePriority::High,
2633 related_artifacts: &["dpapi_masterkey_user", "windows_vault_user"],
2634 sources: &[
2635 "https://attack.mitre.org/techniques/T1555/004/",
2636 "https://www.sans.org/blog/dpapi-forensics-credentials-stored-in-windows/",
2637 "https://posts.specterops.io/operational-guidance-for-offensive-user-dpapi-abuse-1fb7fac8b107",
2638 "https://www.sygnia.co/blog/the-downfall-of-dpapis-top-secret-weapon/",
2639 ],
2640};
2641
2642pub static DPAPI_CRED_ROAMING: ArtifactDescriptor = ArtifactDescriptor {
2644 id: "dpapi_cred_roaming",
2645 name: "DPAPI Credential Blobs (Roaming)",
2646 artifact_type: ArtifactType::Directory,
2647 hive: None,
2648 key_path: "",
2649 value_name: None,
2650 file_path: Some(r"C:\Users\*\AppData\Roaming\Microsoft\Credentials"),
2651 scope: DataScope::User,
2652 os_scope: OsScope::All,
2653 decoder: Decoder::Identity,
2654 meaning:
2655 "Roaming DPAPI credential blobs; same structure as Local, synced across domain machines",
2656 mitre_techniques: &["T1555.004"],
2657 fields: DPAPI_FIELDS,
2658 retention: None,
2659 triage_priority: TriagePriority::High,
2660 related_artifacts: &[],
2661 sources: &[
2662 "https://attack.mitre.org/techniques/T1555/004/",
2663 "https://www.sans.org/blog/dpapi-forensics-credentials-stored-in-windows/",
2664 "https://posts.specterops.io/operational-guidance-for-offensive-user-dpapi-abuse-1fb7fac8b107",
2665 ],
2666};
2667
2668static VAULT_FIELDS: &[FieldSchema] = &[
2669 FieldSchema {
2670 name: "policy_file",
2671 value_type: ValueType::Text,
2672 description: ".vpol policy file containing encryption key material",
2673 is_uid_component: false,
2674 },
2675 FieldSchema {
2676 name: "vcrd_file",
2677 value_type: ValueType::Text,
2678 description: ".vcrd credential file containing the encrypted credential",
2679 is_uid_component: true,
2680 },
2681];
2682
2683pub static WINDOWS_VAULT_USER: ArtifactDescriptor = ArtifactDescriptor {
2688 id: "windows_vault_user",
2689 name: "Windows Vault (User)",
2690 artifact_type: ArtifactType::Directory,
2691 hive: None,
2692 key_path: "",
2693 value_name: None,
2694 file_path: Some(r"C:\Users\*\AppData\Local\Microsoft\Vault"),
2695 scope: DataScope::User,
2696 os_scope: OsScope::Win7Plus,
2697 decoder: Decoder::Identity,
2698 meaning: "Per-user Credential Manager vault (.vpol + .vcrd); contains WEB and WINDOWS saved credentials",
2699 mitre_techniques: &["T1555.004"],
2700 fields: VAULT_FIELDS,
2701 retention: None,
2702 triage_priority: TriagePriority::Medium,
2703 related_artifacts: &[],
2704 sources: &[
2705 "https://attack.mitre.org/techniques/T1555/004/",
2706 "https://learn.microsoft.com/en-us/windows/win32/secauthn/credential-manager",
2707 "https://blog.digital-forensics.it/2016/01/windows-revaulting.html",
2708 ],
2709};
2710
2711pub static WINDOWS_VAULT_SYSTEM: ArtifactDescriptor = ArtifactDescriptor {
2713 id: "windows_vault_system",
2714 name: "Windows Vault (System)",
2715 artifact_type: ArtifactType::Directory,
2716 hive: None,
2717 key_path: "",
2718 value_name: None,
2719 file_path: Some(r"C:\ProgramData\Microsoft\Vault"),
2720 scope: DataScope::System,
2721 os_scope: OsScope::Win7Plus,
2722 decoder: Decoder::Identity,
2723 meaning: "System-level Windows Credential Manager vault; contains machine-scoped credentials",
2724 mitre_techniques: &["T1555.004"],
2725 fields: VAULT_FIELDS,
2726 retention: None,
2727 triage_priority: TriagePriority::Medium,
2728 related_artifacts: &[],
2729 sources: &[
2730 "https://attack.mitre.org/techniques/T1555/004/",
2731 "https://learn.microsoft.com/en-us/windows/win32/secauthn/credential-manager",
2732 "https://blog.digital-forensics.it/2016/01/windows-revaulting.html",
2733 ],
2734};
2735
2736static RDP_FIELDS: &[FieldSchema] = &[FieldSchema {
2737 name: "username_hint",
2738 value_type: ValueType::Text,
2739 description: "Last username used to connect to this RDP server",
2740 is_uid_component: false,
2741}];
2742
2743pub static RDP_CLIENT_SERVERS: ArtifactDescriptor = ArtifactDescriptor {
2748 id: "rdp_client_servers",
2749 name: "RDP Client Saved Servers",
2750 artifact_type: ArtifactType::RegistryKey,
2751 hive: Some(HiveTarget::NtUser),
2752 key_path: r"Software\Microsoft\Terminal Server Client\Servers",
2753 value_name: Some("UsernameHint"),
2754 file_path: None,
2755 scope: DataScope::User,
2756 os_scope: OsScope::All,
2757 decoder: Decoder::Identity,
2758 meaning:
2759 "Hostnames and usernames of previously-connected RDP servers; lateral movement evidence",
2760 mitre_techniques: &["T1021.001"],
2761 fields: RDP_FIELDS,
2762 retention: None,
2763 triage_priority: TriagePriority::Medium,
2764 related_artifacts: &[],
2765 sources: &[
2766 "https://attack.mitre.org/techniques/T1021/001/",
2767 "https://www.sans.org/blog/windows-rdp-forensics/",
2768 "https://forensafe.com/blogs/rdc.html",
2769 "https://www.magnetforensics.com/blog/rdp-artifacts-in-incident-response/",
2770 ],
2771};
2772
2773static RDP_MRU_FIELDS: &[FieldSchema] = &[FieldSchema {
2774 name: "server",
2775 value_type: ValueType::Text,
2776 description: "RDP server address from the most-recently-used list",
2777 is_uid_component: true,
2778}];
2779
2780pub static RDP_CLIENT_DEFAULT: ArtifactDescriptor = ArtifactDescriptor {
2782 id: "rdp_client_default",
2783 name: "RDP Client Default MRU",
2784 artifact_type: ArtifactType::RegistryKey,
2785 hive: Some(HiveTarget::NtUser),
2786 key_path: r"Software\Microsoft\Terminal Server Client\Default",
2787 value_name: None,
2788 file_path: None,
2789 scope: DataScope::User,
2790 os_scope: OsScope::All,
2791 decoder: Decoder::Identity,
2792 meaning:
2793 "MRU0-MRU9 ordered list of RDP server addresses; confirms specific hosts were targeted",
2794 mitre_techniques: &["T1021.001"],
2795 fields: RDP_MRU_FIELDS,
2796 retention: None,
2797 triage_priority: TriagePriority::Medium,
2798 related_artifacts: &[],
2799 sources: &[
2800 "https://attack.mitre.org/techniques/T1021/001/",
2801 "https://www.sans.org/blog/windows-rdp-forensics/",
2802 "https://forensafe.com/blogs/rdc.html",
2803 "https://www.magnetforensics.com/blog/rdp-artifacts-in-incident-response/",
2804 ],
2805};
2806
2807static NTDS_FIELDS: &[FieldSchema] = &[FieldSchema {
2808 name: "path",
2809 value_type: ValueType::Text,
2810 description: "Full path to the NTDS.dit file",
2811 is_uid_component: true,
2812}];
2813
2814pub static NTDS_DIT: ArtifactDescriptor = ArtifactDescriptor {
2819 id: "ntds_dit",
2820 name: "Active Directory Database (NTDS.dit)",
2821 artifact_type: ArtifactType::File,
2822 hive: None,
2823 key_path: "",
2824 value_name: None,
2825 file_path: Some(r"C:\Windows\NTDS\NTDS.dit"),
2826 scope: DataScope::System,
2827 os_scope: OsScope::All,
2828 decoder: Decoder::Identity,
2829 meaning: "Domain controller AD database; contains NTLM hashes for all domain accounts",
2830 mitre_techniques: &["T1003.003"],
2831 fields: NTDS_FIELDS,
2832 retention: None,
2833 triage_priority: TriagePriority::Critical,
2834 related_artifacts: &[],
2835 sources: &[
2836 "https://attack.mitre.org/techniques/T1003/003/",
2837 "https://www.sans.org/blog/protecting-ad-from-credential-theft/",
2838 ],
2839};
2840
2841static BROWSER_CRED_FIELDS: &[FieldSchema] = &[
2842 FieldSchema {
2843 name: "origin_url",
2844 value_type: ValueType::Text,
2845 description: "URL the credential is associated with",
2846 is_uid_component: true,
2847 },
2848 FieldSchema {
2849 name: "username_value",
2850 value_type: ValueType::Text,
2851 description: "Saved username",
2852 is_uid_component: false,
2853 },
2854];
2855
2856pub static CHROME_LOGIN_DATA: ArtifactDescriptor = ArtifactDescriptor {
2858 id: "chrome_login_data",
2859 name: "Chrome/Edge Login Data (SQLite)",
2860 artifact_type: ArtifactType::File,
2861 hive: None,
2862 key_path: "",
2863 value_name: None,
2864 file_path: Some(r"C:\Users\*\AppData\Local\Google\Chrome\User Data\Default\Login Data"),
2865 scope: DataScope::User,
2866 os_scope: OsScope::All,
2867 decoder: Decoder::Identity,
2868 meaning: "SQLite DB with DPAPI-encrypted passwords for saved Chrome/Edge credentials",
2869 mitre_techniques: &["T1555.003"],
2870 fields: BROWSER_CRED_FIELDS,
2871 retention: None,
2872 triage_priority: TriagePriority::Critical,
2873 related_artifacts: &["chrome_cookies", "dpapi_masterkey_user"],
2874 sources: &[
2875 "https://attack.mitre.org/techniques/T1555/003/",
2876 "https://redcanary.com/threat-detection-report/techniques/t1555/",
2877 "https://atropos4n6.com/windows/chrome-login-data-forensics/",
2878 "https://www.foxtonforensics.com/blog/post/analysing-chrome-login-data",
2879 ],
2880};
2881
2882static FIREFOX_CRED_FIELDS: &[FieldSchema] = &[FieldSchema {
2883 name: "hostname",
2884 value_type: ValueType::Text,
2885 description: "Hostname the Firefox credential is associated with",
2886 is_uid_component: true,
2887}];
2888
2889pub static FIREFOX_LOGINS: ArtifactDescriptor = ArtifactDescriptor {
2893 id: "firefox_logins",
2894 name: "Firefox logins.json",
2895 artifact_type: ArtifactType::File,
2896 hive: None,
2897 key_path: "",
2898 value_name: None,
2899 file_path: Some(r"C:\Users\*\AppData\Roaming\Mozilla\Firefox\Profiles\*\logins.json"),
2900 scope: DataScope::User,
2901 os_scope: OsScope::All,
2902 decoder: Decoder::Identity,
2903 meaning:
2904 "NSS3-encrypted Firefox saved credentials; decryptable with key4.db and master password",
2905 mitre_techniques: &["T1555.003"],
2906 fields: FIREFOX_CRED_FIELDS,
2907 retention: None,
2908 triage_priority: TriagePriority::Critical,
2909 related_artifacts: &[],
2910 sources: &[
2911 "https://attack.mitre.org/techniques/T1555/003/",
2912 "https://redcanary.com/threat-detection-report/techniques/t1555/",
2913 "https://atropos4n6.com/windows/chrome-login-data-forensics/",
2914 ],
2915};
2916
2917static WIFI_FIELDS: &[FieldSchema] = &[
2918 FieldSchema {
2919 name: "ssid",
2920 value_type: ValueType::Text,
2921 description: "WiFi network SSID (network name)",
2922 is_uid_component: true,
2923 },
2924 FieldSchema {
2925 name: "key_material",
2926 value_type: ValueType::Text,
2927 description: "Pre-shared key or 802.1X EAP credentials (may be DPAPI-encrypted)",
2928 is_uid_component: false,
2929 },
2930];
2931
2932pub static WIFI_PROFILES: ArtifactDescriptor = ArtifactDescriptor {
2937 id: "wifi_profiles",
2938 name: "Wireless Network Profiles (WLAN)",
2939 artifact_type: ArtifactType::Directory,
2940 hive: None,
2941 key_path: "",
2942 value_name: None,
2943 file_path: Some(r"C:\ProgramData\Microsoft\Wlansvc\Profiles\Interfaces"),
2944 scope: DataScope::System,
2945 os_scope: OsScope::All,
2946 decoder: Decoder::Identity,
2947 meaning: "XML profiles for previously joined WiFi networks; may contain plaintext PSKs",
2948 mitre_techniques: &["T1552.001"],
2949 fields: WIFI_FIELDS,
2950 retention: None,
2951 triage_priority: TriagePriority::Medium,
2952 related_artifacts: &[],
2953 sources: &[
2954 "https://attack.mitre.org/techniques/T1552/001/",
2955 "https://www.sans.org/blog/wireless-forensics/",
2956 "https://forensafe.com/blogs/winwirelessnetworks.html",
2957 ],
2958};
2959
2960static CRON_LINE_FIELDS: &[FieldSchema] = &[FieldSchema {
2968 name: "schedule_line",
2969 value_type: ValueType::Text,
2970 description: "Cron schedule expression and command, or shell script line",
2971 is_uid_component: false,
2972}];
2973
2974static SSH_KEY_FIELDS: &[FieldSchema] = &[FieldSchema {
2976 name: "public_key",
2977 value_type: ValueType::Text,
2978 description: "SSH public key entry (key-type base64 comment)",
2979 is_uid_component: true,
2980}];
2981
2982static ACCOUNT_FIELDS: &[FieldSchema] = &[
2984 FieldSchema {
2985 name: "username",
2986 value_type: ValueType::Text,
2987 description: "Account username",
2988 is_uid_component: true,
2989 },
2990 FieldSchema {
2991 name: "uid",
2992 value_type: ValueType::UnsignedInt,
2993 description: "Numeric user ID (0 = root)",
2994 is_uid_component: false,
2995 },
2996];
2997
2998static LOG_LINE_FIELDS: &[FieldSchema] = &[FieldSchema {
3000 name: "log_line",
3001 value_type: ValueType::Text,
3002 description: "Log line or structured journal entry",
3003 is_uid_component: false,
3004}];
3005
3006pub static LINUX_CRONTAB_SYSTEM: ArtifactDescriptor = ArtifactDescriptor {
3013 id: "linux_crontab_system",
3014 name: "System Crontab (/etc/crontab)",
3015 artifact_type: ArtifactType::File,
3016 hive: None,
3017 key_path: "",
3018 value_name: None,
3019 file_path: Some("/etc/crontab"),
3020 scope: DataScope::System,
3021 os_scope: OsScope::Linux,
3022 decoder: Decoder::Identity,
3023 meaning: "System-wide scheduled job definitions; user field allows cross-account execution",
3024 mitre_techniques: &["T1053.003"],
3025 fields: CRON_LINE_FIELDS,
3026 retention: None,
3027 triage_priority: TriagePriority::Medium,
3028 related_artifacts: &[],
3029 sources: &[
3030 "https://attack.mitre.org/techniques/T1053/003/",
3031 "https://www.sans.org/blog/linux-persistence-mechanisms/",
3032 "https://linux.die.net/man/5/crontab",
3033 "https://pberba.github.io/security/2022/01/30/linux-threat-hunting-for-persistence-systemd-timers-cron/",
3034 ],
3035};
3036
3037pub static LINUX_CRON_D: ArtifactDescriptor = ArtifactDescriptor {
3042 id: "linux_cron_d",
3043 name: "Cron Drop-in Directory (/etc/cron.d/)",
3044 artifact_type: ArtifactType::Directory,
3045 hive: None,
3046 key_path: "",
3047 value_name: None,
3048 file_path: Some("/etc/cron.d"),
3049 scope: DataScope::System,
3050 os_scope: OsScope::Linux,
3051 decoder: Decoder::Identity,
3052 meaning: "Drop-in cron files with full crontab format; easy to add without touching crontab",
3053 mitre_techniques: &["T1053.003"],
3054 fields: CRON_LINE_FIELDS,
3055 retention: None,
3056 triage_priority: TriagePriority::Medium,
3057 related_artifacts: &[],
3058 sources: &[
3059 "https://attack.mitre.org/techniques/T1053/003/",
3060 "https://www.sans.org/blog/linux-persistence-mechanisms/",
3061 "https://pberba.github.io/security/2022/01/30/linux-threat-hunting-for-persistence-systemd-timers-cron/",
3062 ],
3063};
3064
3065pub static LINUX_CRON_PERIODIC: ArtifactDescriptor = ArtifactDescriptor {
3070 id: "linux_cron_periodic",
3071 name: "Cron Periodic Directories (/etc/cron.{daily,hourly,weekly,monthly}/)",
3072 artifact_type: ArtifactType::Directory,
3073 hive: None,
3074 key_path: "",
3075 value_name: None,
3076 file_path: Some("/etc/cron.daily"),
3077 scope: DataScope::System,
3078 os_scope: OsScope::Linux,
3079 decoder: Decoder::Identity,
3080 meaning: "Shell scripts executed periodically by crond/anacron; no schedule syntax required",
3081 mitre_techniques: &["T1053.003"],
3082 fields: DIR_ENTRY_FIELDS,
3083 retention: None,
3084 triage_priority: TriagePriority::Medium,
3085 related_artifacts: &[],
3086 sources: &["https://attack.mitre.org/techniques/T1053/003/"],
3087};
3088
3089pub static LINUX_USER_CRONTAB: ArtifactDescriptor = ArtifactDescriptor {
3094 id: "linux_user_crontab",
3095 name: "Per-User Crontab Spool",
3096 artifact_type: ArtifactType::File,
3097 hive: None,
3098 key_path: "",
3099 value_name: None,
3100 file_path: Some("/var/spool/cron/crontabs/*"),
3101 scope: DataScope::User,
3102 os_scope: OsScope::Linux,
3103 decoder: Decoder::Identity,
3104 meaning: "Per-user scheduled jobs; attacker can set up recurring execution without admin",
3105 mitre_techniques: &["T1053.003"],
3106 fields: CRON_LINE_FIELDS,
3107 retention: None,
3108 triage_priority: TriagePriority::Medium,
3109 related_artifacts: &[],
3110 sources: &[
3111 "https://attack.mitre.org/techniques/T1053/003/",
3112 "https://www.sans.org/blog/linux-persistence-mechanisms/",
3113 "https://pberba.github.io/security/2022/01/30/linux-threat-hunting-for-persistence-systemd-timers-cron/",
3114 ],
3115};
3116
3117pub static LINUX_ANACRONTAB: ArtifactDescriptor = ArtifactDescriptor {
3122 id: "linux_anacrontab",
3123 name: "Anacrontab (/etc/anacrontab)",
3124 artifact_type: ArtifactType::File,
3125 hive: None,
3126 key_path: "",
3127 value_name: None,
3128 file_path: Some("/etc/anacrontab"),
3129 scope: DataScope::System,
3130 os_scope: OsScope::Linux,
3131 decoder: Decoder::Identity,
3132 meaning: "Deferred cron jobs for irregular uptime; period-based rather than time-based",
3133 mitre_techniques: &["T1053.003"],
3134 fields: CRON_LINE_FIELDS,
3135 retention: None,
3136 triage_priority: TriagePriority::Medium,
3137 related_artifacts: &[],
3138 sources: &[
3139 "https://attack.mitre.org/techniques/T1053/003/",
3140 "https://linux.die.net/man/8/anacron",
3141 ],
3142};
3143
3144pub static LINUX_SYSTEMD_SYSTEM_UNIT: ArtifactDescriptor = ArtifactDescriptor {
3152 id: "linux_systemd_system_unit",
3153 name: "systemd System Service Units",
3154 artifact_type: ArtifactType::Directory,
3155 hive: None,
3156 key_path: "",
3157 value_name: None,
3158 file_path: Some("/etc/systemd/system"),
3159 scope: DataScope::System,
3160 os_scope: OsScope::LinuxSystemd,
3161 decoder: Decoder::Identity,
3162 meaning:
3163 "Service definitions executed as root at boot; WantedBy=multi-user.target = auto-start",
3164 mitre_techniques: &["T1543.002"],
3165 fields: DIR_ENTRY_FIELDS,
3166 retention: None,
3167 triage_priority: TriagePriority::Medium,
3168 related_artifacts: &[],
3169 sources: &[
3170 "https://attack.mitre.org/techniques/T1543/002/",
3171 "https://www.sans.org/blog/linux-persistence-mechanisms/",
3172 "https://www.freedesktop.org/software/systemd/man/systemd.unit.html",
3173 "https://pberba.github.io/security/2022/01/30/linux-threat-hunting-for-persistence-systemd-timers-cron/",
3174 "https://www.elastic.co/security-labs/primer-on-persistence-mechanisms",
3175 ],
3176};
3177
3178pub static LINUX_SYSTEMD_USER_UNIT: ArtifactDescriptor = ArtifactDescriptor {
3183 id: "linux_systemd_user_unit",
3184 name: "systemd User Service Units",
3185 artifact_type: ArtifactType::Directory,
3186 hive: None,
3187 key_path: "",
3188 value_name: None,
3189 file_path: Some("~/.config/systemd/user"),
3190 scope: DataScope::User,
3191 os_scope: OsScope::LinuxSystemd,
3192 decoder: Decoder::Identity,
3193 meaning: "User-scope service definitions; executed without root on user login",
3194 mitre_techniques: &["T1543.002"],
3195 fields: DIR_ENTRY_FIELDS,
3196 retention: None,
3197 triage_priority: TriagePriority::Medium,
3198 related_artifacts: &[],
3199 sources: &[
3200 "https://attack.mitre.org/techniques/T1543/002/",
3201 "https://www.freedesktop.org/software/systemd/man/systemd.unit.html",
3202 "https://pberba.github.io/security/2022/01/30/linux-threat-hunting-for-persistence-systemd-timers-cron/",
3203 ],
3204};
3205
3206pub static LINUX_SYSTEMD_TIMER: ArtifactDescriptor = ArtifactDescriptor {
3211 id: "linux_systemd_timer",
3212 name: "systemd Timer Units",
3213 artifact_type: ArtifactType::Directory,
3214 hive: None,
3215 key_path: "",
3216 value_name: None,
3217 file_path: Some("/etc/systemd/system"),
3218 scope: DataScope::System,
3219 os_scope: OsScope::LinuxSystemd,
3220 decoder: Decoder::Identity,
3221 meaning: "Timer-based scheduled execution; malicious timers trigger services on a schedule",
3222 mitre_techniques: &["T1053.006"],
3223 fields: DIR_ENTRY_FIELDS,
3224 retention: None,
3225 triage_priority: TriagePriority::Medium,
3226 related_artifacts: &[],
3227 sources: &[
3228 "https://attack.mitre.org/techniques/T1053/006/",
3229 "https://www.freedesktop.org/software/systemd/man/systemd.timer.html",
3230 "https://pberba.github.io/security/2022/01/30/linux-threat-hunting-for-persistence-systemd-timers-cron/",
3231 ],
3232};
3233
3234pub static LINUX_RC_LOCAL: ArtifactDescriptor = ArtifactDescriptor {
3241 id: "linux_rc_local",
3242 name: "rc.local Startup Script",
3243 artifact_type: ArtifactType::File,
3244 hive: None,
3245 key_path: "",
3246 value_name: None,
3247 file_path: Some("/etc/rc.local"),
3248 scope: DataScope::System,
3249 os_scope: OsScope::Linux,
3250 decoder: Decoder::Identity,
3251 meaning: "Legacy boot-time script executed as root; simple and widely supported",
3252 mitre_techniques: &["T1037.004"],
3253 fields: CRON_LINE_FIELDS,
3254 retention: None,
3255 triage_priority: TriagePriority::Medium,
3256 related_artifacts: &[],
3257 sources: &[
3258 "https://attack.mitre.org/techniques/T1037/004/",
3259 "https://www.sans.org/blog/linux-persistence-mechanisms/",
3260 "https://pberba.github.io/security/2022/02/06/linux-threat-hunting-for-persistence-initialization-scripts-and-shell-configuration/",
3261 "https://www.elastic.co/security-labs/sequel-on-persistence-mechanisms",
3262 ],
3263};
3264
3265pub static LINUX_INIT_D: ArtifactDescriptor = ArtifactDescriptor {
3270 id: "linux_init_d",
3271 name: "SysV Init Scripts (/etc/init.d/)",
3272 artifact_type: ArtifactType::Directory,
3273 hive: None,
3274 key_path: "",
3275 value_name: None,
3276 file_path: Some("/etc/init.d"),
3277 scope: DataScope::System,
3278 os_scope: OsScope::Linux,
3279 decoder: Decoder::Identity,
3280 meaning: "SysV init scripts; malicious script here runs at boot across reboots",
3281 mitre_techniques: &["T1543.002"],
3282 fields: DIR_ENTRY_FIELDS,
3283 retention: None,
3284 triage_priority: TriagePriority::Medium,
3285 related_artifacts: &[],
3286 sources: &[
3287 "https://attack.mitre.org/techniques/T1543/002/",
3288 "https://attack.mitre.org/techniques/T1037/004/",
3289 "https://pberba.github.io/security/2022/02/06/linux-threat-hunting-for-persistence-initialization-scripts-and-shell-configuration/",
3290 ],
3291};
3292
3293pub static LINUX_BASHRC_USER: ArtifactDescriptor = ArtifactDescriptor {
3300 id: "linux_bashrc_user",
3301 name: "User ~/.bashrc",
3302 artifact_type: ArtifactType::File,
3303 hive: None,
3304 key_path: "",
3305 value_name: None,
3306 file_path: Some("~/.bashrc"),
3307 scope: DataScope::User,
3308 os_scope: OsScope::Linux,
3309 decoder: Decoder::Identity,
3310 meaning: "Sourced on every interactive bash session; persistent aliases, functions, or background processes",
3311 mitre_techniques: &["T1546.004"],
3312 fields: CRON_LINE_FIELDS,
3313 retention: None,
3314 triage_priority: TriagePriority::Medium,
3315 related_artifacts: &[],
3316 sources: &[
3317 "https://attack.mitre.org/techniques/T1546/004/",
3318 "https://www.sans.org/blog/linux-persistence-mechanisms/",
3319 "https://pberba.github.io/security/2022/02/06/linux-threat-hunting-for-persistence-initialization-scripts-and-shell-configuration/",
3320 "https://www.elastic.co/guide/en/security/current/bash-shell-profile-modification.html",
3321 ],
3322};
3323
3324pub static LINUX_BASH_PROFILE_USER: ArtifactDescriptor = ArtifactDescriptor {
3326 id: "linux_bash_profile_user",
3327 name: "User ~/.bash_profile",
3328 artifact_type: ArtifactType::File,
3329 hive: None,
3330 key_path: "",
3331 value_name: None,
3332 file_path: Some("~/.bash_profile"),
3333 scope: DataScope::User,
3334 os_scope: OsScope::Linux,
3335 decoder: Decoder::Identity,
3336 meaning: "Sourced on Bash login shells; runs at SSH login and console login",
3337 mitre_techniques: &["T1546.004"],
3338 fields: CRON_LINE_FIELDS,
3339 retention: None,
3340 triage_priority: TriagePriority::Medium,
3341 related_artifacts: &[],
3342 sources: &[
3343 "https://attack.mitre.org/techniques/T1546/004/",
3344 "https://pberba.github.io/security/2022/02/06/linux-threat-hunting-for-persistence-initialization-scripts-and-shell-configuration/",
3345 ],
3346};
3347
3348pub static LINUX_PROFILE_USER: ArtifactDescriptor = ArtifactDescriptor {
3350 id: "linux_profile_user",
3351 name: "User ~/.profile",
3352 artifact_type: ArtifactType::File,
3353 hive: None,
3354 key_path: "",
3355 value_name: None,
3356 file_path: Some("~/.profile"),
3357 scope: DataScope::User,
3358 os_scope: OsScope::Linux,
3359 decoder: Decoder::Identity,
3360 meaning: "POSIX login shell startup; sourced by sh, dash, and bash on login",
3361 mitre_techniques: &["T1546.004"],
3362 fields: CRON_LINE_FIELDS,
3363 retention: None,
3364 triage_priority: TriagePriority::Medium,
3365 related_artifacts: &[],
3366 sources: &[
3367 "https://attack.mitre.org/techniques/T1546/004/",
3368 "https://pberba.github.io/security/2022/02/06/linux-threat-hunting-for-persistence-initialization-scripts-and-shell-configuration/",
3369 ],
3370};
3371
3372pub static LINUX_ZSHRC_USER: ArtifactDescriptor = ArtifactDescriptor {
3374 id: "linux_zshrc_user",
3375 name: "User ~/.zshrc",
3376 artifact_type: ArtifactType::File,
3377 hive: None,
3378 key_path: "",
3379 value_name: None,
3380 file_path: Some("~/.zshrc"),
3381 scope: DataScope::User,
3382 os_scope: OsScope::Linux,
3383 decoder: Decoder::Identity,
3384 meaning: "Sourced on every interactive Zsh session; same persistence vector as .bashrc",
3385 mitre_techniques: &["T1546.004"],
3386 fields: CRON_LINE_FIELDS,
3387 retention: None,
3388 triage_priority: TriagePriority::Medium,
3389 related_artifacts: &[],
3390 sources: &[
3391 "https://attack.mitre.org/techniques/T1546/004/",
3392 "https://pberba.github.io/security/2022/02/06/linux-threat-hunting-for-persistence-initialization-scripts-and-shell-configuration/",
3393 ],
3394};
3395
3396pub static LINUX_PROFILE_SYSTEM: ArtifactDescriptor = ArtifactDescriptor {
3398 id: "linux_profile_system",
3399 name: "System /etc/profile",
3400 artifact_type: ArtifactType::File,
3401 hive: None,
3402 key_path: "",
3403 value_name: None,
3404 file_path: Some("/etc/profile"),
3405 scope: DataScope::System,
3406 os_scope: OsScope::Linux,
3407 decoder: Decoder::Identity,
3408 meaning: "System-wide login shell startup; modifications affect all users",
3409 mitre_techniques: &["T1546.004"],
3410 fields: CRON_LINE_FIELDS,
3411 retention: None,
3412 triage_priority: TriagePriority::Medium,
3413 related_artifacts: &[],
3414 sources: &[
3415 "https://attack.mitre.org/techniques/T1546/004/",
3416 "https://www.sans.org/blog/linux-persistence-mechanisms/",
3417 "https://pberba.github.io/security/2022/02/06/linux-threat-hunting-for-persistence-initialization-scripts-and-shell-configuration/",
3418 ],
3419};
3420
3421pub static LINUX_PROFILE_D: ArtifactDescriptor = ArtifactDescriptor {
3423 id: "linux_profile_d",
3424 name: "System /etc/profile.d/ Drop-ins",
3425 artifact_type: ArtifactType::Directory,
3426 hive: None,
3427 key_path: "",
3428 value_name: None,
3429 file_path: Some("/etc/profile.d"),
3430 scope: DataScope::System,
3431 os_scope: OsScope::Linux,
3432 decoder: Decoder::Identity,
3433 meaning: "Shell scripts sourced by /etc/profile for all users at login; drop-in persistence",
3434 mitre_techniques: &["T1546.004"],
3435 fields: DIR_ENTRY_FIELDS,
3436 retention: None,
3437 triage_priority: TriagePriority::Medium,
3438 related_artifacts: &[],
3439 sources: &[
3440 "https://attack.mitre.org/techniques/T1546/004/",
3441 "https://pberba.github.io/security/2022/02/06/linux-threat-hunting-for-persistence-initialization-scripts-and-shell-configuration/",
3442 ],
3443};
3444
3445pub static LINUX_LD_SO_PRELOAD: ArtifactDescriptor = ArtifactDescriptor {
3453 id: "linux_ld_so_preload",
3454 name: "Dynamic Linker Preload (/etc/ld.so.preload)",
3455 artifact_type: ArtifactType::File,
3456 hive: None,
3457 key_path: "",
3458 value_name: None,
3459 file_path: Some("/etc/ld.so.preload"),
3460 scope: DataScope::System,
3461 os_scope: OsScope::Linux,
3462 decoder: Decoder::Identity,
3463 meaning:
3464 "Libraries preloaded into EVERY process system-wide; standard rootkit hiding mechanism",
3465 mitre_techniques: &["T1574.006"],
3466 fields: CRON_LINE_FIELDS,
3467 retention: None,
3468 triage_priority: TriagePriority::Medium,
3469 related_artifacts: &[],
3470 sources: &[
3471 "https://attack.mitre.org/techniques/T1574/006/",
3472 "https://www.sans.org/blog/linux-persistence-mechanisms/",
3473 "https://www.wiz.io/blog/linux-rootkits-explained-part-1-dynamic-linker-hijacking",
3474 "https://www.sentinelone.com/labs/leveraging-ld_audit-to-beat-the-traditional-linux-library-preloading-technique/",
3475 ],
3476};
3477
3478pub static LINUX_LD_SO_CONF_D: ArtifactDescriptor = ArtifactDescriptor {
3483 id: "linux_ld_so_conf_d",
3484 name: "Linker Config Directory (/etc/ld.so.conf.d/)",
3485 artifact_type: ArtifactType::Directory,
3486 hive: None,
3487 key_path: "",
3488 value_name: None,
3489 file_path: Some("/etc/ld.so.conf.d"),
3490 scope: DataScope::System,
3491 os_scope: OsScope::Linux,
3492 decoder: Decoder::Identity,
3493 meaning:
3494 "Library search path config; malicious entry adds attacker directory to ldconfig paths",
3495 mitre_techniques: &["T1574.006"],
3496 fields: DIR_ENTRY_FIELDS,
3497 retention: None,
3498 triage_priority: TriagePriority::Medium,
3499 related_artifacts: &[],
3500 sources: &["https://attack.mitre.org/techniques/T1574/006/"],
3501};
3502
3503pub static LINUX_SSH_AUTHORIZED_KEYS: ArtifactDescriptor = ArtifactDescriptor {
3510 id: "linux_ssh_authorized_keys",
3511 name: "SSH authorized_keys",
3512 artifact_type: ArtifactType::File,
3513 hive: None,
3514 key_path: "",
3515 value_name: None,
3516 file_path: Some("~/.ssh/authorized_keys"),
3517 scope: DataScope::User,
3518 os_scope: OsScope::Linux,
3519 decoder: Decoder::Identity,
3520 meaning: "Public keys permitting passwordless SSH login; attacker key = permanent backdoor",
3521 mitre_techniques: &["T1098.004"],
3522 fields: SSH_KEY_FIELDS,
3523 retention: None,
3524 triage_priority: TriagePriority::High,
3525 related_artifacts: &[],
3526 sources: &[
3527 "https://attack.mitre.org/techniques/T1098/004/",
3528 "https://www.sans.org/blog/ssh-backdoors/",
3529 "https://sandflysecurity.com/blog/detecting-unauthorized-ssh-keys-in-linux/",
3530 ],
3531};
3532
3533pub static LINUX_PAM_D: ArtifactDescriptor = ArtifactDescriptor {
3541 id: "linux_pam_d",
3542 name: "PAM Configuration (/etc/pam.d/)",
3543 artifact_type: ArtifactType::Directory,
3544 hive: None,
3545 key_path: "",
3546 value_name: None,
3547 file_path: Some("/etc/pam.d"),
3548 scope: DataScope::System,
3549 os_scope: OsScope::Linux,
3550 decoder: Decoder::Identity,
3551 meaning: "PAM module configs per service; malicious module intercepts and logs all passwords",
3552 mitre_techniques: &["T1556.003"],
3553 fields: DIR_ENTRY_FIELDS,
3554 retention: None,
3555 triage_priority: TriagePriority::High,
3556 related_artifacts: &[],
3557 sources: &["https://attack.mitre.org/techniques/T1556/003/"],
3558};
3559
3560pub static LINUX_SUDOERS_D: ArtifactDescriptor = ArtifactDescriptor {
3565 id: "linux_sudoers_d",
3566 name: "Sudoers Drop-ins (/etc/sudoers.d/)",
3567 artifact_type: ArtifactType::Directory,
3568 hive: None,
3569 key_path: "",
3570 value_name: None,
3571 file_path: Some("/etc/sudoers.d"),
3572 scope: DataScope::System,
3573 os_scope: OsScope::Linux,
3574 decoder: Decoder::Identity,
3575 meaning:
3576 "Drop-in sudoers rules; NOPASSWD entries enable privilege escalation without credentials",
3577 mitre_techniques: &["T1548.003"],
3578 fields: DIR_ENTRY_FIELDS,
3579 retention: None,
3580 triage_priority: TriagePriority::High,
3581 related_artifacts: &[],
3582 sources: &["https://attack.mitre.org/techniques/T1548/003/"],
3583};
3584
3585pub static LINUX_MODULES_LOAD_D: ArtifactDescriptor = ArtifactDescriptor {
3590 id: "linux_modules_load_d",
3591 name: "Kernel Module Load Config (/etc/modules-load.d/)",
3592 artifact_type: ArtifactType::Directory,
3593 hive: None,
3594 key_path: "",
3595 value_name: None,
3596 file_path: Some("/etc/modules-load.d"),
3597 scope: DataScope::System,
3598 os_scope: OsScope::LinuxSystemd,
3599 decoder: Decoder::Identity,
3600 meaning: "Kernel modules auto-loaded at boot; rootkit module here = persistent kernel access",
3601 mitre_techniques: &["T1547.006"],
3602 fields: DIR_ENTRY_FIELDS,
3603 retention: None,
3604 triage_priority: TriagePriority::Medium,
3605 related_artifacts: &[],
3606 sources: &["https://attack.mitre.org/techniques/T1547/006/"],
3607};
3608
3609pub static LINUX_MOTD_D: ArtifactDescriptor = ArtifactDescriptor {
3614 id: "linux_motd_d",
3615 name: "Dynamic MOTD Scripts (/etc/update-motd.d/)",
3616 artifact_type: ArtifactType::Directory,
3617 hive: None,
3618 key_path: "",
3619 value_name: None,
3620 file_path: Some("/etc/update-motd.d"),
3621 scope: DataScope::System,
3622 os_scope: OsScope::LinuxDebian,
3623 decoder: Decoder::Identity,
3624 meaning: "Scripts run as root at SSH login for MOTD generation; covert execution vector",
3625 mitre_techniques: &["T1037.004"],
3626 fields: DIR_ENTRY_FIELDS,
3627 retention: None,
3628 triage_priority: TriagePriority::Medium,
3629 related_artifacts: &[],
3630 sources: &["https://attack.mitre.org/techniques/T1037/004/"],
3631};
3632
3633pub static LINUX_UDEV_RULES_D: ArtifactDescriptor = ArtifactDescriptor {
3639 id: "linux_udev_rules_d",
3640 name: "udev Rules (/etc/udev/rules.d/)",
3641 artifact_type: ArtifactType::Directory,
3642 hive: None,
3643 key_path: "",
3644 value_name: None,
3645 file_path: Some("/etc/udev/rules.d"),
3646 scope: DataScope::System,
3647 os_scope: OsScope::LinuxSystemd,
3648 decoder: Decoder::Identity,
3649 meaning: "Device event rules; RUN+= directive executes payload on device attach/detach",
3650 mitre_techniques: &["T1546"],
3651 fields: DIR_ENTRY_FIELDS,
3652 retention: None,
3653 triage_priority: TriagePriority::Medium,
3654 related_artifacts: &[],
3655 sources: &["https://attack.mitre.org/techniques/T1546/"],
3656};
3657
3658pub static LINUX_BASH_HISTORY: ArtifactDescriptor = ArtifactDescriptor {
3666 id: "linux_bash_history",
3667 name: "Bash History (~/.bash_history)",
3668 artifact_type: ArtifactType::File,
3669 hive: None,
3670 key_path: "",
3671 value_name: None,
3672 file_path: Some("~/.bash_history"),
3673 scope: DataScope::User,
3674 os_scope: OsScope::Linux,
3675 decoder: Decoder::Identity,
3676 meaning:
3677 "Interactive Bash command history; reveals lateral movement, exfil, and recon commands",
3678 mitre_techniques: &["T1059.004", "T1552"],
3679 fields: CRON_LINE_FIELDS,
3680 retention: Some("HISTSIZE limit; default 500-2000 commands"),
3681 triage_priority: TriagePriority::High,
3682 related_artifacts: &[],
3683 sources: &[
3684 "https://attack.mitre.org/techniques/T1059/004/",
3685 "https://attack.mitre.org/techniques/T1552/",
3686 ],
3687};
3688
3689pub static LINUX_ZSH_HISTORY: ArtifactDescriptor = ArtifactDescriptor {
3691 id: "linux_zsh_history",
3692 name: "Zsh History (~/.zsh_history)",
3693 artifact_type: ArtifactType::File,
3694 hive: None,
3695 key_path: "",
3696 value_name: None,
3697 file_path: Some("~/.zsh_history"),
3698 scope: DataScope::User,
3699 os_scope: OsScope::Linux,
3700 decoder: Decoder::Identity,
3701 meaning: "Interactive Zsh command history; extended format optionally includes timestamps",
3702 mitre_techniques: &["T1059.004", "T1552"],
3703 fields: CRON_LINE_FIELDS,
3704 retention: Some("HISTSIZE limit; default 500-2000 commands"),
3705 triage_priority: TriagePriority::High,
3706 related_artifacts: &[],
3707 sources: &[
3708 "https://attack.mitre.org/techniques/T1059/004/",
3709 "https://attack.mitre.org/techniques/T1552/",
3710 ],
3711};
3712
3713pub static LINUX_WTMP: ArtifactDescriptor = ArtifactDescriptor {
3718 id: "linux_wtmp",
3719 name: "Login History (/var/log/wtmp)",
3720 artifact_type: ArtifactType::File,
3721 hive: None,
3722 key_path: "",
3723 value_name: None,
3724 file_path: Some("/var/log/wtmp"),
3725 scope: DataScope::System,
3726 os_scope: OsScope::Linux,
3727 decoder: Decoder::Identity,
3728 meaning:
3729 "Binary record of all successful logins/logouts/reboots; evidence of valid-account abuse",
3730 mitre_techniques: &["T1078", "T1021.004"],
3731 fields: LOG_LINE_FIELDS,
3732 retention: Some("until rotated by logrotate"),
3733 triage_priority: TriagePriority::High,
3734 related_artifacts: &[],
3735 sources: &[
3736 "https://attack.mitre.org/techniques/T1078/",
3737 "https://attack.mitre.org/techniques/T1021/004/",
3738 "https://linux.die.net/man/5/wtmp",
3739 "https://www.sans.org/blog/linux-forensics-artifacts/",
3740 "https://bromiley.medium.com/torvalds-tuesday-logon-history-in-the-tmp-files-83530b2acc28",
3741 "https://sandflysecurity.com/blog/using-linux-utmpdump-for-forensics-and-detecting-log-file-tampering",
3742 ],
3743};
3744
3745pub static LINUX_BTMP: ArtifactDescriptor = ArtifactDescriptor {
3749 id: "linux_btmp",
3750 name: "Failed Login Attempts (/var/log/btmp)",
3751 artifact_type: ArtifactType::File,
3752 hive: None,
3753 key_path: "",
3754 value_name: None,
3755 file_path: Some("/var/log/btmp"),
3756 scope: DataScope::System,
3757 os_scope: OsScope::Linux,
3758 decoder: Decoder::Identity,
3759 meaning: "Binary record of failed authentication attempts; brute-force and credential-stuffing evidence",
3760 mitre_techniques: &["T1110"],
3761 fields: LOG_LINE_FIELDS,
3762 retention: Some("until rotated by logrotate"),
3763 triage_priority: TriagePriority::High,
3764 related_artifacts: &[],
3765 sources: &[
3766 "https://attack.mitre.org/techniques/T1110/",
3767 "https://linux.die.net/man/5/wtmp",
3768 "https://bromiley.medium.com/torvalds-tuesday-logon-history-in-the-tmp-files-83530b2acc28",
3769 "https://sandflysecurity.com/blog/using-linux-utmpdump-for-forensics-and-detecting-log-file-tampering",
3770 ],
3771};
3772
3773pub static LINUX_LASTLOG: ArtifactDescriptor = ArtifactDescriptor {
3778 id: "linux_lastlog",
3779 name: "Last Login Database (/var/log/lastlog)",
3780 artifact_type: ArtifactType::File,
3781 hive: None,
3782 key_path: "",
3783 value_name: None,
3784 file_path: Some("/var/log/lastlog"),
3785 scope: DataScope::System,
3786 os_scope: OsScope::Linux,
3787 decoder: Decoder::Identity,
3788 meaning: "Per-UID last-login record including source IP; never-logged-in vs recent entries",
3789 mitre_techniques: &["T1078"],
3790 fields: LOG_LINE_FIELDS,
3791 retention: None,
3792 triage_priority: TriagePriority::High,
3793 related_artifacts: &[],
3794 sources: &["https://attack.mitre.org/techniques/T1078/"],
3795};
3796
3797pub static LINUX_AUTH_LOG: ArtifactDescriptor = ArtifactDescriptor {
3802 id: "linux_auth_log",
3803 name: "Auth Log (/var/log/auth.log)",
3804 artifact_type: ArtifactType::File,
3805 hive: None,
3806 key_path: "",
3807 value_name: None,
3808 file_path: Some("/var/log/auth.log"),
3809 scope: DataScope::System,
3810 os_scope: OsScope::LinuxDebian,
3811 decoder: Decoder::Identity,
3812 meaning: "PAM auth events, SSH logins, sudo commands, su usage; primary lateral-movement log",
3813 mitre_techniques: &["T1078", "T1548.003"],
3814 fields: LOG_LINE_FIELDS,
3815 retention: Some("until rotated by logrotate"),
3816 triage_priority: TriagePriority::High,
3817 related_artifacts: &[],
3818 sources: &[
3819 "https://attack.mitre.org/techniques/T1078/",
3820 "https://attack.mitre.org/techniques/T1548/003/",
3821 ],
3822};
3823
3824pub static LINUX_JOURNAL_DIR: ArtifactDescriptor = ArtifactDescriptor {
3829 id: "linux_journal_dir",
3830 name: "systemd Journal (/var/log/journal/)",
3831 artifact_type: ArtifactType::Directory,
3832 hive: None,
3833 key_path: "",
3834 value_name: None,
3835 file_path: Some("/var/log/journal"),
3836 scope: DataScope::System,
3837 os_scope: OsScope::LinuxSystemd,
3838 decoder: Decoder::Identity,
3839 meaning:
3840 "Structured binary system journal; includes boot IDs, service crashes, and audit events",
3841 mitre_techniques: &["T1078", "T1059.004"],
3842 fields: DIR_ENTRY_FIELDS,
3843 retention: Some("50MB or 1 month default; configurable in journald.conf"),
3844 triage_priority: TriagePriority::High,
3845 related_artifacts: &[],
3846 sources: &[
3847 "https://attack.mitre.org/techniques/T1078/",
3848 "https://attack.mitre.org/techniques/T1059/004/",
3849 ],
3850};
3851
3852pub static LINUX_PASSWD: ArtifactDescriptor = ArtifactDescriptor {
3860 id: "linux_passwd",
3861 name: "User Account Database (/etc/passwd)",
3862 artifact_type: ArtifactType::File,
3863 hive: None,
3864 key_path: "",
3865 value_name: None,
3866 file_path: Some("/etc/passwd"),
3867 scope: DataScope::System,
3868 os_scope: OsScope::Linux,
3869 decoder: Decoder::Identity,
3870 meaning:
3871 "Local user enumeration; UID=0 duplicates or unusual shells indicate backdoor accounts",
3872 mitre_techniques: &["T1087.001", "T1136.001"],
3873 fields: ACCOUNT_FIELDS,
3874 retention: None,
3875 triage_priority: TriagePriority::Critical,
3876 related_artifacts: &[],
3877 sources: &[
3878 "https://attack.mitre.org/techniques/T1087/001/",
3879 "https://attack.mitre.org/techniques/T1136/001/",
3880 "https://linux.die.net/man/5/passwd",
3881 "https://bromiley.medium.com/torvalds-tuesday-user-accounts-597b4ca9dcaf",
3882 ],
3883};
3884
3885pub static LINUX_SHADOW: ArtifactDescriptor = ArtifactDescriptor {
3890 id: "linux_shadow",
3891 name: "Shadow Password File (/etc/shadow)",
3892 artifact_type: ArtifactType::File,
3893 hive: None,
3894 key_path: "",
3895 value_name: None,
3896 file_path: Some("/etc/shadow"),
3897 scope: DataScope::System,
3898 os_scope: OsScope::Linux,
3899 decoder: Decoder::Identity,
3900 meaning: "Password hashes for all local accounts; crackable offline once read",
3901 mitre_techniques: &["T1003.008"],
3902 fields: ACCOUNT_FIELDS,
3903 retention: None,
3904 triage_priority: TriagePriority::Critical,
3905 related_artifacts: &[],
3906 sources: &[
3907 "https://attack.mitre.org/techniques/T1003/008/",
3908 "https://www.sans.org/blog/linux-password-security/",
3909 "https://bromiley.medium.com/torvalds-tuesday-user-accounts-597b4ca9dcaf",
3910 ],
3911};
3912
3913pub static LINUX_SSH_PRIVATE_KEY: ArtifactDescriptor = ArtifactDescriptor {
3918 id: "linux_ssh_private_key",
3919 name: "SSH Private Keys (~/.ssh/id_*)",
3920 artifact_type: ArtifactType::File,
3921 hive: None,
3922 key_path: "",
3923 value_name: None,
3924 file_path: Some("~/.ssh/id_*"),
3925 scope: DataScope::User,
3926 os_scope: OsScope::Linux,
3927 decoder: Decoder::Identity,
3928 meaning:
3929 "Private key material for SSH authentication; unencrypted keys = immediate lateral movement",
3930 mitre_techniques: &["T1552.004"],
3931 fields: SSH_KEY_FIELDS,
3932 retention: None,
3933 triage_priority: TriagePriority::Critical,
3934 related_artifacts: &[],
3935 sources: &["https://attack.mitre.org/techniques/T1552/004/"],
3936};
3937
3938pub static LINUX_SSH_KNOWN_HOSTS: ArtifactDescriptor = ArtifactDescriptor {
3943 id: "linux_ssh_known_hosts",
3944 name: "SSH Known Hosts (~/.ssh/known_hosts)",
3945 artifact_type: ArtifactType::File,
3946 hive: None,
3947 key_path: "",
3948 value_name: None,
3949 file_path: Some("~/.ssh/known_hosts"),
3950 scope: DataScope::User,
3951 os_scope: OsScope::Linux,
3952 decoder: Decoder::Identity,
3953 meaning: "Previously-connected SSH server fingerprints; lateral movement destination history",
3954 mitre_techniques: &["T1021.004", "T1083"],
3955 fields: SSH_KEY_FIELDS,
3956 retention: None,
3957 triage_priority: TriagePriority::Medium,
3958 related_artifacts: &[],
3959 sources: &[
3960 "https://attack.mitre.org/techniques/T1021/004/",
3961 "https://attack.mitre.org/techniques/T1083/",
3962 ],
3963};
3964
3965pub static LINUX_GNUPG_PRIVATE: ArtifactDescriptor = ArtifactDescriptor {
3970 id: "linux_gnupg_private",
3971 name: "GnuPG Private Key Store (~/.gnupg/)",
3972 artifact_type: ArtifactType::Directory,
3973 hive: None,
3974 key_path: "",
3975 value_name: None,
3976 file_path: Some("~/.gnupg"),
3977 scope: DataScope::User,
3978 os_scope: OsScope::Linux,
3979 decoder: Decoder::Identity,
3980 meaning: "GnuPG private keys; enables message decryption and code-signing forgery",
3981 mitre_techniques: &["T1552.004"],
3982 fields: DPAPI_FIELDS,
3983 retention: None,
3984 triage_priority: TriagePriority::High,
3985 related_artifacts: &[],
3986 sources: &["https://attack.mitre.org/techniques/T1552/004/"],
3987};
3988
3989pub static LINUX_AWS_CREDENTIALS: ArtifactDescriptor = ArtifactDescriptor {
3994 id: "linux_aws_credentials",
3995 name: "AWS Credentials (~/.aws/credentials)",
3996 artifact_type: ArtifactType::File,
3997 hive: None,
3998 key_path: "",
3999 value_name: None,
4000 file_path: Some("~/.aws/credentials"),
4001 scope: DataScope::User,
4002 os_scope: OsScope::Linux,
4003 decoder: Decoder::Identity,
4004 meaning: "AWS long-term or temporary credentials; enables cloud infrastructure compromise",
4005 mitre_techniques: &["T1552.001"],
4006 fields: FILE_PATH_FIELDS,
4007 retention: None,
4008 triage_priority: TriagePriority::High,
4009 related_artifacts: &[],
4010 sources: &["https://attack.mitre.org/techniques/T1552/001/"],
4011};
4012
4013pub static LINUX_DOCKER_CONFIG: ArtifactDescriptor = ArtifactDescriptor {
4018 id: "linux_docker_config",
4019 name: "Docker Config (~/.docker/config.json)",
4020 artifact_type: ArtifactType::File,
4021 hive: None,
4022 key_path: "",
4023 value_name: None,
4024 file_path: Some("~/.docker/config.json"),
4025 scope: DataScope::User,
4026 os_scope: OsScope::Linux,
4027 decoder: Decoder::Identity,
4028 meaning: "Docker registry credentials; enables container image exfil or malicious image push",
4029 mitre_techniques: &["T1552.001"],
4030 fields: FILE_PATH_FIELDS,
4031 retention: None,
4032 triage_priority: TriagePriority::High,
4033 related_artifacts: &[],
4034 sources: &["https://attack.mitre.org/techniques/T1552/001/"],
4035};
4036
4037pub static LNK_FILES: ArtifactDescriptor = ArtifactDescriptor {
4042 id: "lnk_files",
4043 name: "LNK / Shell Link Recent Files",
4044 artifact_type: ArtifactType::Directory,
4045 hive: None,
4046 key_path: "",
4047 value_name: None,
4048 file_path: Some(r"%APPDATA%\Microsoft\Windows\Recent\"),
4049 scope: DataScope::User,
4050 os_scope: OsScope::Win7Plus,
4051 decoder: Decoder::Identity,
4052 meaning: "Shell Link (.lnk) files record target path, MAC timestamps, volume serial, and \
4053 NetBIOS host — evidence of file access even after target deletion. T1547.009.",
4054 mitre_techniques: &["T1547.009", "T1070.004"],
4055 fields: DIR_ENTRY_FIELDS,
4056 retention: None,
4057 triage_priority: TriagePriority::High,
4058 related_artifacts: &["jump_list_auto", "mru_recent_docs"],
4059 sources: &[
4060 "https://attack.mitre.org/techniques/T1547/009/",
4061 "https://attack.mitre.org/techniques/T1070/004/",
4062 ],
4063};
4064
4065pub static JUMP_LIST_AUTO: ArtifactDescriptor = ArtifactDescriptor {
4066 id: "jump_list_auto",
4067 name: "Jump Lists — AutomaticDestinations",
4068 artifact_type: ArtifactType::Directory,
4069 hive: None,
4070 key_path: "",
4071 value_name: None,
4072 file_path: Some(r"%APPDATA%\Microsoft\Windows\Recent\AutomaticDestinations\"),
4073 scope: DataScope::User,
4074 os_scope: OsScope::Win7Plus,
4075 decoder: Decoder::Identity,
4076 meaning: "OLE Compound Document storing per-AppID MRU lists; reveals recently opened files \
4077 for each application including timestamps and target metadata.",
4078 mitre_techniques: &["T1547.009", "T1070.004"],
4079 fields: DIR_ENTRY_FIELDS,
4080 retention: None,
4081 triage_priority: TriagePriority::High,
4082 related_artifacts: &["lnk_files", "mru_recent_docs"],
4083 sources: &[
4084 "https://attack.mitre.org/techniques/T1547/009/",
4085 "https://attack.mitre.org/techniques/T1070/004/",
4086 ],
4087};
4088
4089pub static JUMP_LIST_CUSTOM: ArtifactDescriptor = ArtifactDescriptor {
4090 id: "jump_list_custom",
4091 name: "Jump Lists — CustomDestinations",
4092 artifact_type: ArtifactType::Directory,
4093 hive: None,
4094 key_path: "",
4095 value_name: None,
4096 file_path: Some(r"%APPDATA%\Microsoft\Windows\Recent\CustomDestinations\"),
4097 scope: DataScope::User,
4098 os_scope: OsScope::Win7Plus,
4099 decoder: Decoder::Identity,
4100 meaning: "Application-pinned and custom jump list entries; may persist after file deletion, \
4101 revealing attacker-pinned tools or exfiltrated document access.",
4102 mitre_techniques: &["T1547.009", "T1070.004"],
4103 fields: DIR_ENTRY_FIELDS,
4104 retention: None,
4105 triage_priority: TriagePriority::High,
4106 related_artifacts: &["lnk_files", "jump_list_auto"],
4107 sources: &[
4108 "https://attack.mitre.org/techniques/T1547/009/",
4109 "https://attack.mitre.org/techniques/T1070/004/",
4110 ],
4111};
4112
4113pub static EVTX_DIR: ArtifactDescriptor = ArtifactDescriptor {
4114 id: "evtx_dir",
4115 name: "Windows Event Log Directory (EVTX)",
4116 artifact_type: ArtifactType::Directory,
4117 hive: None,
4118 key_path: "",
4119 value_name: None,
4120 file_path: Some(r"C:\Windows\System32\winevt\Logs\"),
4121 scope: DataScope::System,
4122 os_scope: OsScope::Win7Plus,
4123 decoder: Decoder::Identity,
4124 meaning: "Binary EVTX log files — Security.evtx (4624/4625/4688), System.evtx, \
4125 PowerShell/Operational.evtx. Primary execution, logon, and process-creation record.",
4126 mitre_techniques: &["T1070.001", "T1059.001"],
4127 fields: DIR_ENTRY_FIELDS,
4128 retention: Some("configurable; default ~20MB rolling per channel"),
4129 triage_priority: TriagePriority::Medium,
4130 related_artifacts: &[],
4131 sources: &[
4132 "https://attack.mitre.org/techniques/T1070/001/",
4133 "https://attack.mitre.org/techniques/T1059/001/",
4134 ],
4135};
4136
4137pub static USN_JOURNAL: ArtifactDescriptor = ArtifactDescriptor {
4138 id: "usn_journal",
4139 name: "USN Journal ($UsnJrnl:$J)",
4140 artifact_type: ArtifactType::File,
4141 hive: None,
4142 key_path: "",
4143 value_name: None,
4144 file_path: Some(r"\\.\C:\$Extend\$UsnJrnl:$J"),
4145 scope: DataScope::System,
4146 os_scope: OsScope::Win7Plus,
4147 decoder: Decoder::Identity,
4148 meaning: "NTFS change journal records file create/delete/rename operations with USN sequence \
4149 number; persists even after file deletion, proving prior file existence.",
4150 mitre_techniques: &["T1070.004", "T1059"],
4151 fields: DIR_ENTRY_FIELDS,
4152 retention: None,
4153 triage_priority: TriagePriority::Medium,
4154 related_artifacts: &[],
4155 sources: &[
4156 "https://attack.mitre.org/techniques/T1070/004/",
4157 "https://attack.mitre.org/techniques/T1059/",
4158 ],
4159};
4160
4161pub static WMI_MOF_DIR: ArtifactDescriptor = ArtifactDescriptor {
4164 id: "wmi_mof_dir",
4165 name: "WMI MOF Subscription Repository",
4166 artifact_type: ArtifactType::Directory,
4167 hive: None,
4168 key_path: "",
4169 value_name: None,
4170 file_path: Some(r"C:\Windows\System32\wbem\Repository\"),
4171 scope: DataScope::System,
4172 os_scope: OsScope::Win7Plus,
4173 decoder: Decoder::Identity,
4174 meaning: "WMI CIM repository stores EventFilter, EventConsumer, and FilterToConsumerBinding \
4175 objects; persistence survives reboots and is invisible to registry-only tools.",
4176 mitre_techniques: &["T1546.003"],
4177 fields: DIR_ENTRY_FIELDS,
4178 retention: None,
4179 triage_priority: TriagePriority::High,
4180 related_artifacts: &[],
4181 sources: &["https://attack.mitre.org/techniques/T1546/003/"],
4182};
4183
4184pub static BITS_DB: ArtifactDescriptor = ArtifactDescriptor {
4185 id: "bits_db",
4186 name: "BITS Job Queue Database",
4187 artifact_type: ArtifactType::Directory,
4188 hive: None,
4189 key_path: "",
4190 value_name: None,
4191 file_path: Some(r"C:\ProgramData\Microsoft\Network\Downloader\"),
4192 scope: DataScope::System,
4193 os_scope: OsScope::Win7Plus,
4194 decoder: Decoder::Identity,
4195 meaning: "Background Intelligent Transfer Service queue DB (qmgr0.dat); records download \
4196 jobs including URL, destination, and command-to-notify — abused for stealthy malware staging.",
4197 mitre_techniques: &["T1197"],
4198 fields: DIR_ENTRY_FIELDS,
4199 retention: None,
4200 triage_priority: TriagePriority::High,
4201 related_artifacts: &[],
4202 sources: &[
4203 "https://attack.mitre.org/techniques/T1197/",
4204 ],
4205};
4206
4207static WMI_SUB_FIELDS: &[FieldSchema] = &[
4208 FieldSchema {
4209 name: "filter_name",
4210 description: "WMI EventFilter name",
4211 value_type: ValueType::Text,
4212 is_uid_component: true,
4213 },
4214 FieldSchema {
4215 name: "consumer_type",
4216 description: "Consumer type (Script/CommandLine)",
4217 value_type: ValueType::Text,
4218 is_uid_component: false,
4219 },
4220 FieldSchema {
4221 name: "consumer_value",
4222 description: "Script or command executed on trigger",
4223 value_type: ValueType::Text,
4224 is_uid_component: false,
4225 },
4226 FieldSchema {
4227 name: "query",
4228 description: "WQL query that triggers the subscription",
4229 value_type: ValueType::Text,
4230 is_uid_component: false,
4231 },
4232];
4233
4234pub static WMI_SUBSCRIPTIONS: ArtifactDescriptor = ArtifactDescriptor {
4235 id: "wmi_subscriptions",
4236 name: "WMI Event Subscriptions (Registry)",
4237 artifact_type: ArtifactType::RegistryKey,
4238 hive: Some(HiveTarget::HklmSoftware),
4239 key_path: r"Microsoft\WBEM\ESS\//./root/subscription",
4240 value_name: None,
4241 file_path: None,
4242 scope: DataScope::System,
4243 os_scope: OsScope::Win7Plus,
4244 decoder: Decoder::MultiSz,
4245 meaning: "Registry-side index of WMI subscriptions; cross-reference with MOF repository for \
4246 complete picture of WMI-based persistence.",
4247 mitre_techniques: &["T1546.003"],
4248 fields: WMI_SUB_FIELDS,
4249 retention: None,
4250 triage_priority: TriagePriority::High,
4251 related_artifacts: &[],
4252 sources: &["https://attack.mitre.org/techniques/T1546/003/"],
4253};
4254
4255pub static LOGON_SCRIPTS: ArtifactDescriptor = ArtifactDescriptor {
4256 id: "logon_scripts",
4257 name: "Logon Scripts (UserInitMprLogonScript)",
4258 artifact_type: ArtifactType::RegistryValue,
4259 hive: Some(HiveTarget::NtUser),
4260 key_path: r"Environment",
4261 value_name: Some("UserInitMprLogonScript"),
4262 file_path: None,
4263 scope: DataScope::User,
4264 os_scope: OsScope::Win7Plus,
4265 decoder: Decoder::Identity,
4266 meaning: "Script executed at logon via WinLogon; per-user value allowing unprivileged \
4267 persistence that survives password resets.",
4268 mitre_techniques: &["T1037.001"],
4269 fields: PERSIST_CMD_FIELDS,
4270 retention: None,
4271 triage_priority: TriagePriority::Medium,
4272 related_artifacts: &[],
4273 sources: &["https://attack.mitre.org/techniques/T1037/001/"],
4274};
4275
4276pub static WINSOCK_LSP: ArtifactDescriptor = ArtifactDescriptor {
4277 id: "winsock_lsp",
4278 name: "Winsock Layered Service Provider",
4279 artifact_type: ArtifactType::RegistryKey,
4280 hive: Some(HiveTarget::HklmSystem),
4281 key_path: r"CurrentControlSet\Services\WinSock2\Parameters\Protocol_Catalog9",
4282 value_name: None,
4283 file_path: None,
4284 scope: DataScope::System,
4285 os_scope: OsScope::Win7Plus,
4286 decoder: Decoder::Identity,
4287 meaning: "LSP DLLs intercept all Winsock traffic; malicious LSPs can log credentials from \
4288 plaintext protocols. Rare but high-signal indicator of network interception.",
4289 mitre_techniques: &["T1547.010"],
4290 fields: DLL_FIELDS,
4291 retention: None,
4292 triage_priority: TriagePriority::Medium,
4293 related_artifacts: &[],
4294 sources: &["https://attack.mitre.org/techniques/T1547/010/"],
4295};
4296
4297pub static APPSHIM_DB: ArtifactDescriptor = ArtifactDescriptor {
4298 id: "appshim_db",
4299 name: "Application Shim Database",
4300 artifact_type: ArtifactType::Directory,
4301 hive: None,
4302 key_path: "",
4303 value_name: None,
4304 file_path: Some(r"C:\Windows\apppatch\Custom\"),
4305 scope: DataScope::System,
4306 os_scope: OsScope::Win7Plus,
4307 decoder: Decoder::Identity,
4308 meaning: "Custom SDB shim databases; attackers inject shims to redirect API calls, \
4309 disable security checks, or load malicious DLLs without modifying the target binary.",
4310 mitre_techniques: &["T1546.011"],
4311 fields: DIR_ENTRY_FIELDS,
4312 retention: None,
4313 triage_priority: TriagePriority::Medium,
4314 related_artifacts: &[],
4315 sources: &["https://attack.mitre.org/techniques/T1546/011/"],
4316};
4317
4318pub static PASSWORD_FILTER_DLL: ArtifactDescriptor = ArtifactDescriptor {
4319 id: "password_filter_dll",
4320 name: "Password Filter DLL (Notification Packages)",
4321 artifact_type: ArtifactType::RegistryValue,
4322 hive: Some(HiveTarget::HklmSystem),
4323 key_path: r"CurrentControlSet\Control\Lsa",
4324 value_name: Some("Notification Packages"),
4325 file_path: None,
4326 scope: DataScope::System,
4327 os_scope: OsScope::Win7Plus,
4328 decoder: Decoder::MultiSz,
4329 meaning: "DLLs registered here receive cleartext passwords during every password change; \
4330 malicious filter captures and exfiltrates credentials.",
4331 mitre_techniques: &["T1556.002"],
4332 fields: DLL_FIELDS,
4333 retention: None,
4334 triage_priority: TriagePriority::Medium,
4335 related_artifacts: &[],
4336 sources: &["https://attack.mitre.org/techniques/T1556/002/"],
4337};
4338
4339pub static OFFICE_NORMAL_DOTM: ArtifactDescriptor = ArtifactDescriptor {
4340 id: "office_normal_dotm",
4341 name: "Office Normal Template (Normal.dotm)",
4342 artifact_type: ArtifactType::File,
4343 hive: None,
4344 key_path: "",
4345 value_name: None,
4346 file_path: Some(r"%APPDATA%\Microsoft\Templates\Normal.dotm"),
4347 scope: DataScope::User,
4348 os_scope: OsScope::Win7Plus,
4349 decoder: Decoder::Identity,
4350 meaning: "Global Word template auto-loaded on every document open; malicious macros \
4351 embedded here achieve persistence across all Word sessions.",
4352 mitre_techniques: &["T1137.001"],
4353 fields: FILE_PATH_FIELDS,
4354 retention: None,
4355 triage_priority: TriagePriority::High,
4356 related_artifacts: &[],
4357 sources: &["https://attack.mitre.org/techniques/T1137/001/"],
4358};
4359
4360pub static POWERSHELL_PROFILE_ALL: ArtifactDescriptor = ArtifactDescriptor {
4361 id: "powershell_profile_all",
4362 name: "PowerShell All-Users Profile (profile.ps1)",
4363 artifact_type: ArtifactType::File,
4364 hive: None,
4365 key_path: "",
4366 value_name: None,
4367 file_path: Some(r"C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1"),
4368 scope: DataScope::System,
4369 os_scope: OsScope::Win7Plus,
4370 decoder: Decoder::Identity,
4371 meaning: "System-wide PowerShell profile executed for every user on every PS session start; \
4372 SYSTEM-writable, provides privileged persistence without registry modification.",
4373 mitre_techniques: &["T1546.013"],
4374 fields: PERSIST_CMD_FIELDS,
4375 retention: None,
4376 triage_priority: TriagePriority::High,
4377 related_artifacts: &[],
4378 sources: &["https://attack.mitre.org/techniques/T1546/013/"],
4379};
4380
4381pub static DPAPI_SYSTEM_MASTERKEY: ArtifactDescriptor = ArtifactDescriptor {
4384 id: "dpapi_system_masterkey",
4385 name: "DPAPI System Master Key",
4386 artifact_type: ArtifactType::Directory,
4387 hive: None,
4388 key_path: "",
4389 value_name: None,
4390 file_path: Some(r"C:\Windows\System32\Microsoft\Protect\S-1-5-18\User\"),
4391 scope: DataScope::System,
4392 os_scope: OsScope::Win7Plus,
4393 decoder: Decoder::Identity,
4394 meaning: "DPAPI master keys for the SYSTEM account; used to decrypt SYSTEM-scope secrets \
4395 such as LSA secrets, service credentials, and scheduled task credentials.",
4396 mitre_techniques: &["T1555.004"],
4397 fields: FILE_PATH_FIELDS,
4398 retention: None,
4399 triage_priority: TriagePriority::Critical,
4400 related_artifacts: &["lsa_secrets", "dpapi_masterkey_user"],
4401 sources: &["https://attack.mitre.org/techniques/T1555/004/"],
4402};
4403
4404pub static DPAPI_CREDHIST: ArtifactDescriptor = ArtifactDescriptor {
4405 id: "dpapi_credhist",
4406 name: "DPAPI CREDHIST File",
4407 artifact_type: ArtifactType::File,
4408 hive: None,
4409 key_path: "",
4410 value_name: None,
4411 file_path: Some(r"%APPDATA%\Microsoft\Protect\CREDHIST"),
4412 scope: DataScope::User,
4413 os_scope: OsScope::Win7Plus,
4414 decoder: Decoder::Identity,
4415 meaning: "Chain of previous DPAPI master key derivation entries; enables decryption of \
4416 secrets encrypted with old passwords after a password change.",
4417 mitre_techniques: &["T1555.004"],
4418 fields: FILE_PATH_FIELDS,
4419 retention: None,
4420 triage_priority: TriagePriority::High,
4421 related_artifacts: &["dpapi_masterkey_user"],
4422 sources: &["https://attack.mitre.org/techniques/T1555/004/"],
4423};
4424
4425pub static CHROME_COOKIES: ArtifactDescriptor = ArtifactDescriptor {
4426 id: "chrome_cookies",
4427 name: "Chrome/Edge Cookies (SQLite)",
4428 artifact_type: ArtifactType::File,
4429 hive: None,
4430 key_path: "",
4431 value_name: None,
4432 file_path: Some(r"%LOCALAPPDATA%\Google\Chrome\User Data\Default\Network\Cookies"),
4433 scope: DataScope::User,
4434 os_scope: OsScope::Win7Plus,
4435 decoder: Decoder::Identity,
4436 meaning: "SQLite database of browser session/authentication cookies; adversaries can replay \
4437 these to bypass MFA and impersonate authenticated sessions (pass-the-cookie).",
4438 mitre_techniques: &["T1539", "T1185"],
4439 fields: FILE_PATH_FIELDS,
4440 retention: None,
4441 triage_priority: TriagePriority::High,
4442 related_artifacts: &["chrome_login_data"],
4443 sources: &[
4444 "https://attack.mitre.org/techniques/T1539/",
4445 "https://attack.mitre.org/techniques/T1185/",
4446 ],
4447};
4448
4449pub static EDGE_WEBCACHE: ArtifactDescriptor = ArtifactDescriptor {
4450 id: "edge_webcache",
4451 name: "IE/Edge Legacy WebCacheV01.dat",
4452 artifact_type: ArtifactType::Directory,
4453 hive: None,
4454 key_path: "",
4455 value_name: None,
4456 file_path: Some(r"%LOCALAPPDATA%\Microsoft\Windows\INetCache\"),
4457 scope: DataScope::User,
4458 os_scope: OsScope::Win7Plus,
4459 decoder: Decoder::Identity,
4460 meaning: "ESE database recording all IE/Edge Legacy web history, downloads, and cached \
4461 content; reveals browsing patterns and potential data exfiltration URLs.",
4462 mitre_techniques: &["T1539", "T1217"],
4463 fields: FILE_PATH_FIELDS,
4464 retention: None,
4465 triage_priority: TriagePriority::Low,
4466 related_artifacts: &[],
4467 sources: &[
4468 "https://attack.mitre.org/techniques/T1539/",
4469 "https://attack.mitre.org/techniques/T1217/",
4470 ],
4471};
4472
4473pub static VPN_RAS_PHONEBOOK: ArtifactDescriptor = ArtifactDescriptor {
4474 id: "vpn_ras_phonebook",
4475 name: "VPN Credentials — RAS Phonebook",
4476 artifact_type: ArtifactType::File,
4477 hive: None,
4478 key_path: "",
4479 value_name: None,
4480 file_path: Some(r"%APPDATA%\Microsoft\Network\Connections\Pbk\rasphone.pbk"),
4481 scope: DataScope::User,
4482 os_scope: OsScope::Win7Plus,
4483 decoder: Decoder::Identity,
4484 meaning: "Plain-text INI phonebook storing VPN connection entries including server address \
4485 and saved credential references; reveals network pivoting paths.",
4486 mitre_techniques: &["T1552.001"],
4487 fields: FILE_PATH_FIELDS,
4488 retention: None,
4489 triage_priority: TriagePriority::Low,
4490 related_artifacts: &[],
4491 sources: &["https://attack.mitre.org/techniques/T1552/001/"],
4492};
4493
4494pub static WINDOWS_HELLO_NGC: ArtifactDescriptor = ArtifactDescriptor {
4495 id: "windows_hello_ngc",
4496 name: "Windows Hello / NGC Folder",
4497 artifact_type: ArtifactType::Directory,
4498 hive: None,
4499 key_path: "",
4500 value_name: None,
4501 file_path: Some(r"C:\Windows\ServiceProfiles\LocalService\AppData\Roaming\Microsoft\Ngc\"),
4502 scope: DataScope::System,
4503 os_scope: OsScope::Win10Plus,
4504 decoder: Decoder::Identity,
4505 meaning: "Stores Windows Hello credential provider keys (PIN protectors, biometric keys); \
4506 compromise reveals authentication material bypassing traditional password forensics.",
4507 mitre_techniques: &["T1555"],
4508 fields: FILE_PATH_FIELDS,
4509 retention: None,
4510 triage_priority: TriagePriority::High,
4511 related_artifacts: &[],
4512 sources: &["https://attack.mitre.org/techniques/T1555/"],
4513};
4514
4515pub static USER_CERT_PRIVATE_KEY: ArtifactDescriptor = ArtifactDescriptor {
4516 id: "user_cert_private_key",
4517 name: "User Certificate Private Keys",
4518 artifact_type: ArtifactType::Directory,
4519 hive: None,
4520 key_path: "",
4521 value_name: None,
4522 file_path: Some(r"%APPDATA%\Microsoft\SystemCertificates\My\"),
4523 scope: DataScope::User,
4524 os_scope: OsScope::Win7Plus,
4525 decoder: Decoder::Identity,
4526 meaning: "DPAPI-protected user certificate private keys for code signing, S/MIME, and \
4527 smart-card emulation; exfiltration enables impersonation and signing of malicious artifacts.",
4528 mitre_techniques: &["T1552.004"],
4529 fields: FILE_PATH_FIELDS,
4530 retention: None,
4531 triage_priority: TriagePriority::High,
4532 related_artifacts: &[],
4533 sources: &[
4534 "https://attack.mitre.org/techniques/T1552/004/",
4535 ],
4536};
4537
4538pub static MACHINE_CERT_STORE: ArtifactDescriptor = ArtifactDescriptor {
4539 id: "machine_cert_store",
4540 name: "Machine Certificate Private Keys",
4541 artifact_type: ArtifactType::Directory,
4542 hive: None,
4543 key_path: "",
4544 value_name: None,
4545 file_path: Some(r"C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\"),
4546 scope: DataScope::System,
4547 os_scope: OsScope::Win7Plus,
4548 decoder: Decoder::Identity,
4549 meaning: "Machine-scope RSA private keys protected by DPAPI SYSTEM; used for TLS mutual \
4550 auth, code signing, and IPSec — high-value credential exfiltration target.",
4551 mitre_techniques: &["T1552.004"],
4552 fields: FILE_PATH_FIELDS,
4553 retention: None,
4554 triage_priority: TriagePriority::High,
4555 related_artifacts: &[],
4556 sources: &["https://attack.mitre.org/techniques/T1552/004/"],
4557};
4558
4559pub static LINUX_AT_QUEUE: ArtifactDescriptor = ArtifactDescriptor {
4562 id: "linux_at_queue",
4563 name: "AT Job Queue (/var/spool/at/)",
4564 artifact_type: ArtifactType::Directory,
4565 hive: None,
4566 key_path: "",
4567 value_name: None,
4568 file_path: Some("/var/spool/at/"),
4569 scope: DataScope::System,
4570 os_scope: OsScope::Linux,
4571 decoder: Decoder::Identity,
4572 meaning: "One-shot delayed execution jobs from the `at` command; each file contains a shell \
4573 script to run at a specified time, used for stealthy one-shot persistence.",
4574 mitre_techniques: &["T1053.001"],
4575 fields: CRON_LINE_FIELDS,
4576 retention: None,
4577 triage_priority: TriagePriority::Medium,
4578 related_artifacts: &[],
4579 sources: &["https://attack.mitre.org/techniques/T1053/001/"],
4580};
4581
4582pub static LINUX_SSHD_CONFIG: ArtifactDescriptor = ArtifactDescriptor {
4583 id: "linux_sshd_config",
4584 name: "SSH Daemon Configuration (/etc/ssh/sshd_config)",
4585 artifact_type: ArtifactType::File,
4586 hive: None,
4587 key_path: "",
4588 value_name: None,
4589 file_path: Some("/etc/ssh/sshd_config"),
4590 scope: DataScope::System,
4591 os_scope: OsScope::Linux,
4592 decoder: Decoder::Identity,
4593 meaning: "SSH server config; look for unauthorized AuthorizedKeysFile overrides, \
4594 ForceCommand bypass, PermitRootLogin yes, or AllowUsers modifications.",
4595 mitre_techniques: &["T1098.004", "T1021.004"],
4596 fields: PERSIST_CMD_FIELDS,
4597 retention: None,
4598 triage_priority: TriagePriority::Medium,
4599 related_artifacts: &[],
4600 sources: &[
4601 "https://attack.mitre.org/techniques/T1098/004/",
4602 "https://attack.mitre.org/techniques/T1021/004/",
4603 ],
4604};
4605
4606pub static LINUX_ETC_GROUP: ArtifactDescriptor = ArtifactDescriptor {
4607 id: "linux_etc_group",
4608 name: "Group Accounts (/etc/group)",
4609 artifact_type: ArtifactType::File,
4610 hive: None,
4611 key_path: "",
4612 value_name: None,
4613 file_path: Some("/etc/group"),
4614 scope: DataScope::System,
4615 os_scope: OsScope::Linux,
4616 decoder: Decoder::Identity,
4617 meaning: "Group membership database; cross-reference with /etc/passwd and sudo log to \
4618 detect unauthorized group additions (e.g., added to `sudo` or `docker` group).",
4619 mitre_techniques: &["T1087.001", "T1078.003"],
4620 fields: ACCOUNT_FIELDS,
4621 retention: None,
4622 triage_priority: TriagePriority::Medium,
4623 related_artifacts: &[],
4624 sources: &[
4625 "https://attack.mitre.org/techniques/T1087/001/",
4626 "https://attack.mitre.org/techniques/T1078/003/",
4627 ],
4628};
4629
4630pub static LINUX_GNOME_KEYRING: ArtifactDescriptor = ArtifactDescriptor {
4631 id: "linux_gnome_keyring",
4632 name: "GNOME Keyring (keyrings/)",
4633 artifact_type: ArtifactType::Directory,
4634 hive: None,
4635 key_path: "",
4636 value_name: None,
4637 file_path: Some("~/.local/share/keyrings/"),
4638 scope: DataScope::User,
4639 os_scope: OsScope::Linux,
4640 decoder: Decoder::Identity,
4641 meaning: "GNOME keyring stores WiFi PSK, SSH passphrases, web service passwords, and \
4642 browser master passwords encrypted with user login credential.",
4643 mitre_techniques: &["T1555.003"],
4644 fields: FILE_PATH_FIELDS,
4645 retention: None,
4646 triage_priority: TriagePriority::Critical,
4647 related_artifacts: &[],
4648 sources: &["https://attack.mitre.org/techniques/T1555/003/"],
4649};
4650
4651pub static LINUX_KDE_KWALLET: ArtifactDescriptor = ArtifactDescriptor {
4652 id: "linux_kde_kwallet",
4653 name: "KDE KWallet (kwalletd/)",
4654 artifact_type: ArtifactType::Directory,
4655 hive: None,
4656 key_path: "",
4657 value_name: None,
4658 file_path: Some("~/.local/share/kwalletd/"),
4659 scope: DataScope::User,
4660 os_scope: OsScope::Linux,
4661 decoder: Decoder::Identity,
4662 meaning: "KDE wallet encrypted credential store; stores passwords, SSH keys, and browser \
4663 credentials for KDE applications.",
4664 mitre_techniques: &["T1555.003"],
4665 fields: FILE_PATH_FIELDS,
4666 retention: None,
4667 triage_priority: TriagePriority::Critical,
4668 related_artifacts: &[],
4669 sources: &["https://attack.mitre.org/techniques/T1555/003/"],
4670};
4671
4672pub static LINUX_CHROME_LOGIN_LINUX: ArtifactDescriptor = ArtifactDescriptor {
4673 id: "linux_chrome_login_linux",
4674 name: "Chrome/Chromium Login Data (Linux)",
4675 artifact_type: ArtifactType::File,
4676 hive: None,
4677 key_path: "",
4678 value_name: None,
4679 file_path: Some("~/.config/google-chrome/Default/Login Data"),
4680 scope: DataScope::User,
4681 os_scope: OsScope::Linux,
4682 decoder: Decoder::Identity,
4683 meaning: "SQLite database of saved Chrome passwords on Linux; encryption key stored in \
4684 GNOME Keyring or plaintext depending on configuration.",
4685 mitre_techniques: &["T1555.003"],
4686 fields: FILE_PATH_FIELDS,
4687 retention: None,
4688 triage_priority: TriagePriority::Critical,
4689 related_artifacts: &[],
4690 sources: &["https://attack.mitre.org/techniques/T1555/003/"],
4691};
4692
4693pub static LINUX_FIREFOX_LOGINS_LINUX: ArtifactDescriptor = ArtifactDescriptor {
4694 id: "linux_firefox_logins_linux",
4695 name: "Firefox logins.json (Linux)",
4696 artifact_type: ArtifactType::File,
4697 hive: None,
4698 key_path: "",
4699 value_name: None,
4700 file_path: Some("~/.mozilla/firefox/"),
4701 scope: DataScope::User,
4702 os_scope: OsScope::Linux,
4703 decoder: Decoder::Identity,
4704 meaning:
4705 "JSON-encoded saved Firefox credentials protected by NSS (key4.db); \
4706 can be decrypted with master password or via memory forensics of the Firefox process.",
4707 mitre_techniques: &["T1555.003"],
4708 fields: FILE_PATH_FIELDS,
4709 retention: None,
4710 triage_priority: TriagePriority::Critical,
4711 related_artifacts: &[],
4712 sources: &["https://attack.mitre.org/techniques/T1555/003/"],
4713};
4714
4715pub static LINUX_UTMP: ArtifactDescriptor = ArtifactDescriptor {
4716 id: "linux_utmp",
4717 name: "Current Login Sessions (/run/utmp)",
4718 artifact_type: ArtifactType::File,
4719 hive: None,
4720 key_path: "",
4721 value_name: None,
4722 file_path: Some("/run/utmp"),
4723 scope: DataScope::System,
4724 os_scope: OsScope::Linux,
4725 decoder: Decoder::Identity,
4726 meaning: "Binary utmp records of currently logged-in users; cross-reference with wtmp \
4727 to detect sessions not present in persistent logs (anti-forensics via utmp wiper).",
4728 mitre_techniques: &["T1078"],
4729 fields: LOG_LINE_FIELDS,
4730 retention: None,
4731 triage_priority: TriagePriority::Medium,
4732 related_artifacts: &[],
4733 sources: &[
4734 "https://attack.mitre.org/techniques/T1078/",
4735 "https://linux.die.net/man/5/utmp",
4736 "https://www.sans.org/blog/linux-forensics-artifacts/",
4737 "https://bromiley.medium.com/torvalds-tuesday-logon-history-in-the-tmp-files-83530b2acc28",
4738 "https://sandflysecurity.com/blog/using-linux-utmpdump-for-forensics-and-detecting-log-file-tampering",
4739 ],
4740};
4741
4742pub static LINUX_GCP_CREDENTIALS: ArtifactDescriptor = ArtifactDescriptor {
4743 id: "linux_gcp_credentials",
4744 name: "GCP Application Default Credentials",
4745 artifact_type: ArtifactType::Directory,
4746 hive: None,
4747 key_path: "",
4748 value_name: None,
4749 file_path: Some("~/.config/gcloud/"),
4750 scope: DataScope::User,
4751 os_scope: OsScope::Linux,
4752 decoder: Decoder::Identity,
4753 meaning: "GCP access tokens and service account keys stored by gcloud CLI; \
4754 exfiltration enables cloud resource takeover without password.",
4755 mitre_techniques: &["T1552.001"],
4756 fields: FILE_PATH_FIELDS,
4757 retention: None,
4758 triage_priority: TriagePriority::High,
4759 related_artifacts: &[],
4760 sources: &["https://attack.mitre.org/techniques/T1552/001/"],
4761};
4762
4763pub static LINUX_AZURE_CREDENTIALS: ArtifactDescriptor = ArtifactDescriptor {
4764 id: "linux_azure_credentials",
4765 name: "Azure CLI Credentials (~/.azure/)",
4766 artifact_type: ArtifactType::Directory,
4767 hive: None,
4768 key_path: "",
4769 value_name: None,
4770 file_path: Some("~/.azure/"),
4771 scope: DataScope::User,
4772 os_scope: OsScope::Linux,
4773 decoder: Decoder::Identity,
4774 meaning: "Azure CLI access tokens and service principal credentials; \
4775 msal_token_cache.json contains active OAuth tokens enabling lateral movement in Azure.",
4776 mitre_techniques: &["T1552.001"],
4777 fields: FILE_PATH_FIELDS,
4778 retention: None,
4779 triage_priority: TriagePriority::High,
4780 related_artifacts: &[],
4781 sources: &[
4782 "https://attack.mitre.org/techniques/T1552/001/",
4783 ],
4784};
4785
4786pub static LINUX_KUBE_CONFIG: ArtifactDescriptor = ArtifactDescriptor {
4787 id: "linux_kube_config",
4788 name: "Kubernetes Config (~/.kube/config)",
4789 artifact_type: ArtifactType::File,
4790 hive: None,
4791 key_path: "",
4792 value_name: None,
4793 file_path: Some("~/.kube/config"),
4794 scope: DataScope::User,
4795 os_scope: OsScope::Linux,
4796 decoder: Decoder::Identity,
4797 meaning: "kubectl cluster credentials including bearer tokens, client certificates, \
4798 and cluster API endpoints; enables full cluster takeover if exfiltrated.",
4799 mitre_techniques: &["T1552.001"],
4800 fields: FILE_PATH_FIELDS,
4801 retention: None,
4802 triage_priority: TriagePriority::High,
4803 related_artifacts: &[],
4804 sources: &["https://attack.mitre.org/techniques/T1552/001/"],
4805};
4806
4807pub static LINUX_GIT_CREDENTIALS: ArtifactDescriptor = ArtifactDescriptor {
4808 id: "linux_git_credentials",
4809 name: "Git Credential Store (~/.git-credentials)",
4810 artifact_type: ArtifactType::File,
4811 hive: None,
4812 key_path: "",
4813 value_name: None,
4814 file_path: Some("~/.git-credentials"),
4815 scope: DataScope::User,
4816 os_scope: OsScope::Linux,
4817 decoder: Decoder::Identity,
4818 meaning: "Plaintext git credential store: URL + username + PAT/password per line; \
4819 personal access tokens here can access source repositories and CI/CD pipelines.",
4820 mitre_techniques: &["T1552.001"],
4821 fields: FILE_PATH_FIELDS,
4822 retention: None,
4823 triage_priority: TriagePriority::High,
4824 related_artifacts: &[],
4825 sources: &["https://attack.mitre.org/techniques/T1552/001/"],
4826};
4827
4828pub static LINUX_NETRC: ArtifactDescriptor = ArtifactDescriptor {
4829 id: "linux_netrc",
4830 name: "Netrc Credential File (~/.netrc)",
4831 artifact_type: ArtifactType::File,
4832 hive: None,
4833 key_path: "",
4834 value_name: None,
4835 file_path: Some("~/.netrc"),
4836 scope: DataScope::User,
4837 os_scope: OsScope::Linux,
4838 decoder: Decoder::Identity,
4839 meaning: "Auto-authentication file for ftp, curl, and legacy tools; stores plaintext \
4840 hostname/login/password triplets, often forgotten and highly sensitive.",
4841 mitre_techniques: &["T1552.001"],
4842 fields: FILE_PATH_FIELDS,
4843 retention: None,
4844 triage_priority: TriagePriority::Medium,
4845 related_artifacts: &[],
4846 sources: &["https://attack.mitre.org/techniques/T1552/001/"],
4847};
4848
4849pub static LINUX_ETC_ENVIRONMENT: ArtifactDescriptor = ArtifactDescriptor {
4853 id: "linux_etc_environment",
4854 name: "System Environment Variables (/etc/environment)",
4855 artifact_type: ArtifactType::File,
4856 hive: None,
4857 key_path: "",
4858 value_name: None,
4859 file_path: Some("/etc/environment"),
4860 scope: DataScope::System,
4861 os_scope: OsScope::Linux,
4862 decoder: Decoder::Identity,
4863 meaning:
4864 "System-wide environment variable definitions loaded for every login session and \
4865 PAM-based authentication. Attackers inject PATH hijacks or LD_PRELOAD values here \
4866 to redirect binary execution system-wide without modifying shell configuration files.",
4867 mitre_techniques: &["T1546.004"],
4868 fields: PERSIST_CMD_FIELDS,
4869 retention: None,
4870 triage_priority: TriagePriority::Medium,
4871 related_artifacts: &[],
4872 sources: &[
4873 "https://attack.mitre.org/techniques/T1546/004/",
4874 "https://linux.die.net/man/7/environ",
4875 ],
4876};
4877
4878pub static LINUX_XDG_AUTOSTART_USER: ArtifactDescriptor = ArtifactDescriptor {
4879 id: "linux_xdg_autostart_user",
4880 name: "XDG User Autostart (.desktop files)",
4881 artifact_type: ArtifactType::Directory,
4882 hive: None,
4883 key_path: "",
4884 value_name: None,
4885 file_path: Some("~/.config/autostart/"),
4886 scope: DataScope::User,
4887 os_scope: OsScope::Linux,
4888 decoder: Decoder::Identity,
4889 meaning: "Per-user XDG autostart .desktop files executed when a desktop session starts \
4890 (GNOME/KDE/XFCE). Exec= field runs arbitrary commands at GUI login without \
4891 root privileges — frequently overlooked by server-focused forensic checklists.",
4892 mitre_techniques: &["T1547.014"],
4893 fields: PERSIST_CMD_FIELDS,
4894 retention: None,
4895 triage_priority: TriagePriority::Medium,
4896 related_artifacts: &[],
4897 sources: &[
4898 "https://attack.mitre.org/techniques/T1547/014/",
4899 "https://specifications.freedesktop.org/autostart-spec/autostart-spec-latest.html",
4900 ],
4901};
4902
4903pub static LINUX_XDG_AUTOSTART_SYSTEM: ArtifactDescriptor = ArtifactDescriptor {
4904 id: "linux_xdg_autostart_system",
4905 name: "XDG System Autostart (.desktop files)",
4906 artifact_type: ArtifactType::Directory,
4907 hive: None,
4908 key_path: "",
4909 value_name: None,
4910 file_path: Some("/etc/xdg/autostart/"),
4911 scope: DataScope::System,
4912 os_scope: OsScope::Linux,
4913 decoder: Decoder::Identity,
4914 meaning:
4915 "System-wide XDG autostart .desktop entries executed for all users at desktop session \
4916 start. Provides privileged persistence targeting all GUI logins on a workstation.",
4917 mitre_techniques: &["T1547.014"],
4918 fields: PERSIST_CMD_FIELDS,
4919 retention: None,
4920 triage_priority: TriagePriority::Medium,
4921 related_artifacts: &[],
4922 sources: &[
4923 "https://attack.mitre.org/techniques/T1547/014/",
4924 "https://specifications.freedesktop.org/autostart-spec/autostart-spec-latest.html",
4925 ],
4926};
4927
4928pub static LINUX_NETWORKMANAGER_DISPATCHER: ArtifactDescriptor = ArtifactDescriptor {
4929 id: "linux_networkmanager_dispatcher",
4930 name: "NetworkManager Dispatcher Scripts",
4931 artifact_type: ArtifactType::Directory,
4932 hive: None,
4933 key_path: "",
4934 value_name: None,
4935 file_path: Some("/etc/NetworkManager/dispatcher.d/"),
4936 scope: DataScope::System,
4937 os_scope: OsScope::Linux,
4938 decoder: Decoder::Identity,
4939 meaning: "Scripts executed by NetworkManager when network interfaces change state (up/down). \
4940 Provides network-event-triggered persistence — scripts fire on VPN connect, \
4941 WiFi association, or interface cycling, making detection harder than at-boot persistence.",
4942 mitre_techniques: &["T1547.013"],
4943 fields: PERSIST_CMD_FIELDS,
4944 retention: None,
4945 triage_priority: TriagePriority::Medium,
4946 related_artifacts: &[],
4947 sources: &[
4948 "https://attack.mitre.org/techniques/T1547/013/",
4949 "https://networkmanager.dev/docs/api/latest/NetworkManager-dispatcher.html",
4950 ],
4951};
4952
4953pub static LINUX_APT_HOOKS: ArtifactDescriptor = ArtifactDescriptor {
4954 id: "linux_apt_hooks",
4955 name: "APT Package Manager Hook Scripts",
4956 artifact_type: ArtifactType::Directory,
4957 hive: None,
4958 key_path: "",
4959 value_name: None,
4960 file_path: Some("/etc/apt/apt.conf.d/"),
4961 scope: DataScope::System,
4962 os_scope: OsScope::LinuxDebian,
4963 decoder: Decoder::Identity,
4964 meaning: "APT configuration snippets that can define DPkg::Pre-Install-Pkgs, \
4965 DPkg::Post-Invoke, or APT::Update::Post-Invoke hooks; execute as root during \
4966 every package install or update — long-lived trigger-based privilege persistence.",
4967 mitre_techniques: &["T1546.004"],
4968 fields: PERSIST_CMD_FIELDS,
4969 retention: None,
4970 triage_priority: TriagePriority::Medium,
4971 related_artifacts: &[],
4972 sources: &[
4973 "https://attack.mitre.org/techniques/T1546/004/",
4974 "https://attack.mitre.org/techniques/T1546/016/",
4975 "https://wiki.debian.org/DpkgTriggers",
4976 ],
4977};
4978
4979pub static JUMP_LIST_SYSTEM: ArtifactDescriptor = ArtifactDescriptor {
4982 id: "jump_list_system",
4983 name: "Jump Lists — System AutomaticDestinations",
4984 artifact_type: ArtifactType::Directory,
4985 hive: None,
4986 key_path: "",
4987 value_name: None,
4988 file_path: Some(r"C:\ProgramData\Microsoft\Windows\Recent\AutomaticDestinations\"),
4989 scope: DataScope::System,
4990 os_scope: OsScope::Win7Plus,
4991 decoder: Decoder::Identity,
4992 meaning: "System-scope jump lists shared across all users; distinct from per-user \
4993 %APPDATA% copies. Each .automaticDestinations-ms is an OLE CFB containing \
4994 a DestList stream (AppID → target MRU) plus embedded LNK blocks.",
4995 mitre_techniques: &["T1547.009", "T1070.004"],
4996 fields: DIR_ENTRY_FIELDS,
4997 retention: None,
4998 triage_priority: TriagePriority::High,
4999 related_artifacts: &["jump_list_auto", "jump_list_custom"],
5000 sources: &[
5001 "https://attack.mitre.org/techniques/T1547/009/",
5002 "https://attack.mitre.org/techniques/T1070/004/",
5003 "https://www.sans.org/blog/computer-forensics-windows-7-jump-lists/",
5004 "https://windowsir.blogspot.com/2011/05/jump-lists-in-win7.html",
5005 "https://github.com/EricZimmerman/JLECmd",
5006 "https://forensics.wiki/jump_lists/",
5007 ],
5008};
5009
5010pub static LNK_FILES_OFFICE: ArtifactDescriptor = ArtifactDescriptor {
5011 id: "lnk_files_office",
5012 name: "Office Recent LNK Files",
5013 artifact_type: ArtifactType::Directory,
5014 hive: None,
5015 key_path: "",
5016 value_name: None,
5017 file_path: Some(r"%APPDATA%\Microsoft\Office\Recent\"),
5018 scope: DataScope::User,
5019 os_scope: OsScope::Win7Plus,
5020 decoder: Decoder::Identity,
5021 meaning: "Office-specific shell link files created for every document opened via Office. \
5022 Separate from Windows Recent; survives clearing of Windows Recent Items. \
5023 Reveals document access including network shares and USB paths.",
5024 mitre_techniques: &["T1547.009", "T1070.004"],
5025 fields: DIR_ENTRY_FIELDS,
5026 retention: None,
5027 triage_priority: TriagePriority::High,
5028 related_artifacts: &["lnk_files", "mru_recent_docs"],
5029 sources: &[
5030 "https://attack.mitre.org/techniques/T1547/009/",
5031 "https://attack.mitre.org/techniques/T1070/004/",
5032 "https://www.sans.org/blog/lnk-files-analysis-in-windows/",
5033 "https://windowsir.blogspot.com/2009/01/lnk-files-are-your-friends.html",
5034 "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/",
5035 "https://www.magnetforensics.com/blog/forensic-analysis-of-lnk-files/",
5036 "https://forensics.wiki/lnk/",
5037 ],
5038};
5039
5040static PREFETCH_FIELDS: &[FieldSchema] = &[
5041 FieldSchema {
5042 name: "executable_name",
5043 description: "Name of the prefetched executable (up to 29 chars)",
5044 value_type: ValueType::Text,
5045 is_uid_component: true,
5046 },
5047 FieldSchema {
5048 name: "run_count",
5049 description: "Number of times the executable has run",
5050 value_type: ValueType::UnsignedInt,
5051 is_uid_component: false,
5052 },
5053 FieldSchema {
5054 name: "last_run_time",
5055 description: "Most recent execution timestamp (FILETIME)",
5056 value_type: ValueType::Timestamp,
5057 is_uid_component: false,
5058 },
5059 FieldSchema {
5060 name: "previous_run_times",
5061 description: "Up to 7 prior execution timestamps (Win 8+)",
5062 value_type: ValueType::Text,
5063 is_uid_component: false,
5064 },
5065 FieldSchema {
5066 name: "volume_path",
5067 description: "Volume device path at time of execution",
5068 value_type: ValueType::Text,
5069 is_uid_component: false,
5070 },
5071 FieldSchema {
5072 name: "referenced_files",
5073 description: "DLLs and files loaded during first 10 seconds",
5074 value_type: ValueType::Text,
5075 is_uid_component: false,
5076 },
5077 FieldSchema {
5078 name: "prefetch_hash",
5079 description: "8-hex path hash appended to filename",
5080 value_type: ValueType::Text,
5081 is_uid_component: true,
5082 },
5083];
5084
5085pub static PREFETCH_FILE: ArtifactDescriptor = ArtifactDescriptor {
5086 id: "prefetch_file",
5087 name: "Prefetch File (.pf)",
5088 artifact_type: ArtifactType::File,
5089 hive: None,
5090 key_path: "",
5091 value_name: None,
5092 file_path: Some(r"C:\Windows\Prefetch\*.pf"),
5093 scope: DataScope::System,
5094 os_scope: OsScope::Win7Plus,
5095 decoder: Decoder::Identity,
5096 meaning: "Binary execution record: executable name, 8-run-timestamp history (Win8+), \
5097 run count, path hash, and referenced DLL list. Win10+ files are MAM-compressed \
5098 (4-byte magic 0x4D 0x41 0x4D 0x04) — decompress with xpress_huff before parsing. \
5099 Versions: v17 (XP), v23 (Vista/7), v26 (Win8), v30/v31 (Win10+).",
5100 mitre_techniques: &["T1059", "T1070.004"],
5101 fields: PREFETCH_FIELDS,
5102 retention: Some("128 entries; oldest evicted"),
5103 triage_priority: TriagePriority::High,
5104 related_artifacts: &[
5105 "shimcache",
5106 "amcache_app_file",
5107 "evtx_security",
5108 "srum_app_resource",
5109 ],
5110 sources: &[
5111 "https://attack.mitre.org/techniques/T1059/",
5112 "https://attack.mitre.org/techniques/T1070/004/",
5113 "https://www.sans.org/blog/computer-forensic-artifacts-windows-7-prefetch-files/",
5114 "https://13cubed.com/downloads/Windows_Forensic_Analysis_Poster.pdf",
5115 "https://isc.sans.edu/diary/Forensic+Value+of+Prefetch/29168",
5116 "https://www.magnetforensics.com/blog/forensic-analysis-of-prefetch-files-in-windows/",
5117 ],
5118};
5119
5120static SRUM_NET_FIELDS: &[FieldSchema] = &[
5121 FieldSchema {
5122 name: "app_id",
5123 description: "Application identifier (path or service name)",
5124 value_type: ValueType::Text,
5125 is_uid_component: true,
5126 },
5127 FieldSchema {
5128 name: "user_id",
5129 description: "SID of the user account",
5130 value_type: ValueType::Text,
5131 is_uid_component: true,
5132 },
5133 FieldSchema {
5134 name: "timestamp",
5135 description: "ESE column TimeStamp (UTC)",
5136 value_type: ValueType::Timestamp,
5137 is_uid_component: false,
5138 },
5139 FieldSchema {
5140 name: "bytes_sent",
5141 description: "Total bytes sent by this app in the interval",
5142 value_type: ValueType::UnsignedInt,
5143 is_uid_component: false,
5144 },
5145 FieldSchema {
5146 name: "bytes_received",
5147 description: "Total bytes received by this app in the interval",
5148 value_type: ValueType::UnsignedInt,
5149 is_uid_component: false,
5150 },
5151 FieldSchema {
5152 name: "interface_luid",
5153 description: "Network interface LUID",
5154 value_type: ValueType::UnsignedInt,
5155 is_uid_component: false,
5156 },
5157];
5158
5159pub static SRUM_NETWORK_USAGE: ArtifactDescriptor = ArtifactDescriptor {
5160 id: "srum_network_usage",
5161 name: "SRUM Network Data Usage Table",
5162 artifact_type: ArtifactType::File,
5163 hive: None,
5164 key_path: "",
5165 value_name: None,
5166 file_path: Some(r"C:\Windows\System32\sru\SRUDB.dat:{973F5D5C-1D90-11D3-AE08-00A0C90F57DA}"),
5167 scope: DataScope::System,
5168 os_scope: OsScope::Win8Plus,
5169 decoder: Decoder::Identity,
5170 meaning:
5171 "ESE table {973F5D5C-1D90-11D3-AE08-00A0C90F57DA} records per-app bytes sent/received \
5172 per network interface per hour. ~30-day retention. Proves data exfiltration volume \
5173 even after log deletion; correlate AppId + UserId + BytesSent for exfil attribution.",
5174 mitre_techniques: &["T1049", "T1048"],
5175 fields: SRUM_NET_FIELDS,
5176 retention: Some("~30 days"),
5177 triage_priority: TriagePriority::Critical,
5178 related_artifacts: &["evtx_security", "srum_app_resource", "prefetch_file"],
5179 sources: &[
5180 "https://attack.mitre.org/techniques/T1049/",
5181 "https://attack.mitre.org/techniques/T1048/",
5182 "https://www.sans.org/white-papers/36660/",
5183 "https://www.sans.org/blog/srum-forensics/",
5184 "https://www.magnetforensics.com/blog/srum-forensic-analysis-of-windows-system-resource-utilization-monitor/",
5185 ],
5186};
5187
5188static SRUM_APP_FIELDS: &[FieldSchema] = &[
5189 FieldSchema {
5190 name: "app_id",
5191 description: "Application path or service name",
5192 value_type: ValueType::Text,
5193 is_uid_component: true,
5194 },
5195 FieldSchema {
5196 name: "user_id",
5197 description: "SID of the user account",
5198 value_type: ValueType::Text,
5199 is_uid_component: true,
5200 },
5201 FieldSchema {
5202 name: "timestamp",
5203 description: "Interval timestamp (UTC)",
5204 value_type: ValueType::Timestamp,
5205 is_uid_component: false,
5206 },
5207 FieldSchema {
5208 name: "foreground_cpu_time",
5209 description: "CPU time used in foreground (100ns units)",
5210 value_type: ValueType::UnsignedInt,
5211 is_uid_component: false,
5212 },
5213 FieldSchema {
5214 name: "background_cpu_time",
5215 description: "CPU time used in background (100ns units)",
5216 value_type: ValueType::UnsignedInt,
5217 is_uid_component: false,
5218 },
5219 FieldSchema {
5220 name: "foreground_cycles",
5221 description: "CPU cycle count in foreground",
5222 value_type: ValueType::UnsignedInt,
5223 is_uid_component: false,
5224 },
5225 FieldSchema {
5226 name: "background_cycles",
5227 description: "CPU cycle count in background",
5228 value_type: ValueType::UnsignedInt,
5229 is_uid_component: false,
5230 },
5231];
5232
5233pub static SRUM_APP_RESOURCE: ArtifactDescriptor = ArtifactDescriptor {
5234 id: "srum_app_resource",
5235 name: "SRUM Application Resource Usage Table",
5236 artifact_type: ArtifactType::File,
5237 hive: None,
5238 key_path: "",
5239 value_name: None,
5240 file_path: Some(r"C:\Windows\System32\sru\SRUDB.dat:{D10CA2FE-6FCF-4F6D-848E-B2E99266FA89}"),
5241 scope: DataScope::System,
5242 os_scope: OsScope::Win8Plus,
5243 decoder: Decoder::Identity,
5244 meaning: "ESE table {D10CA2FE-6FCF-4F6D-848E-B2E99266FA89} records per-app CPU cycles \
5245 (foreground + background) per hour per user. Proves execution even without Prefetch \
5246 or Event Log entries — CPU cycles are non-zero only if the process actually ran.",
5247 mitre_techniques: &["T1059", "T1070.004"],
5248 fields: SRUM_APP_FIELDS,
5249 retention: Some("~30 days"),
5250 triage_priority: TriagePriority::Critical,
5251 related_artifacts: &["srum_network_usage", "prefetch_file", "evtx_security"],
5252 sources: &[
5253 "https://attack.mitre.org/techniques/T1059/",
5254 "https://attack.mitre.org/techniques/T1070/004/",
5255 "https://www.sans.org/white-papers/36660/",
5256 "https://www.sans.org/blog/srum-forensics/",
5257 "https://www.magnetforensics.com/blog/srum-forensic-analysis-of-windows-system-resource-utilization-monitor/",
5258 ],
5259};
5260
5261static SRUM_ENERGY_FIELDS: &[FieldSchema] = &[
5262 FieldSchema {
5263 name: "app_id",
5264 description: "Application path",
5265 value_type: ValueType::Text,
5266 is_uid_component: true,
5267 },
5268 FieldSchema {
5269 name: "user_id",
5270 description: "SID of the user account",
5271 value_type: ValueType::Text,
5272 is_uid_component: true,
5273 },
5274 FieldSchema {
5275 name: "timestamp",
5276 description: "Interval timestamp (UTC)",
5277 value_type: ValueType::Timestamp,
5278 is_uid_component: false,
5279 },
5280 FieldSchema {
5281 name: "charge_level",
5282 description: "Battery charge level at sample time",
5283 value_type: ValueType::UnsignedInt,
5284 is_uid_component: false,
5285 },
5286 FieldSchema {
5287 name: "designed_capacity",
5288 description: "Battery designed capacity (mWh)",
5289 value_type: ValueType::UnsignedInt,
5290 is_uid_component: false,
5291 },
5292 FieldSchema {
5293 name: "full_charge_capacity",
5294 description: "Current full charge capacity (mWh)",
5295 value_type: ValueType::UnsignedInt,
5296 is_uid_component: false,
5297 },
5298];
5299
5300pub static SRUM_ENERGY_USAGE: ArtifactDescriptor = ArtifactDescriptor {
5301 id: "srum_energy_usage",
5302 name: "SRUM Energy Usage Table",
5303 artifact_type: ArtifactType::File,
5304 hive: None,
5305 key_path: "",
5306 value_name: None,
5307 file_path: Some(r"C:\Windows\System32\sru\SRUDB.dat:{FEE4E14F-02A9-4550-B5CE-5FA2DA202E37}"),
5308 scope: DataScope::System,
5309 os_scope: OsScope::Win8Plus,
5310 decoder: Decoder::Identity,
5311 meaning: "ESE table {FEE4E14F-02A9-4550-B5CE-5FA2DA202E37} records battery charge levels \
5312 at each sampling interval — enables timeline reconstruction of device on/off events \
5313 and correlates app activity with physical device presence.",
5314 mitre_techniques: &["T1059"],
5315 fields: SRUM_ENERGY_FIELDS,
5316 retention: Some("~30 days"),
5317 triage_priority: TriagePriority::High,
5318 related_artifacts: &[],
5319 sources: &[
5320 "https://attack.mitre.org/techniques/T1059/",
5321 "https://www.sans.org/white-papers/36660/",
5322 ],
5323};
5324
5325static SRUM_PUSH_FIELDS: &[FieldSchema] = &[
5326 FieldSchema {
5327 name: "app_id",
5328 description: "Application that received notification",
5329 value_type: ValueType::Text,
5330 is_uid_component: true,
5331 },
5332 FieldSchema {
5333 name: "user_id",
5334 description: "SID of the user account",
5335 value_type: ValueType::Text,
5336 is_uid_component: true,
5337 },
5338 FieldSchema {
5339 name: "timestamp",
5340 description: "Notification timestamp (UTC)",
5341 value_type: ValueType::Timestamp,
5342 is_uid_component: false,
5343 },
5344 FieldSchema {
5345 name: "notification_type",
5346 description: "WNS notification type code",
5347 value_type: ValueType::UnsignedInt,
5348 is_uid_component: false,
5349 },
5350 FieldSchema {
5351 name: "payload_size",
5352 description: "Notification payload size in bytes",
5353 value_type: ValueType::UnsignedInt,
5354 is_uid_component: false,
5355 },
5356];
5357
5358pub static SRUM_PUSH_NOTIFICATION: ArtifactDescriptor = ArtifactDescriptor {
5359 id: "srum_push_notification",
5360 name: "SRUM Push Notification Activity Table",
5361 artifact_type: ArtifactType::File,
5362 hive: None,
5363 key_path: "",
5364 value_name: None,
5365 file_path: Some(r"C:\Windows\System32\sru\SRUDB.dat:{D10CA2FE-6FCF-4F6D-848E-B2E99266FA86}"),
5366 scope: DataScope::System,
5367 os_scope: OsScope::Win10Plus,
5368 decoder: Decoder::Identity,
5369 meaning: "ESE table {D10CA2FE-6FCF-4F6D-848E-B2E99266FA86} records Windows Push Notification \
5370 (WNS) activity per app — reveals C2-style notification-triggered execution in \
5371 malicious UWP/PWA apps and confirms app network activity.",
5372 mitre_techniques: &["T1059"],
5373 fields: SRUM_PUSH_FIELDS,
5374 retention: Some("~30 days"),
5375 triage_priority: TriagePriority::High,
5376 related_artifacts: &[],
5377 sources: &[
5378 "https://attack.mitre.org/techniques/T1059/",
5379 "https://www.sans.org/white-papers/36660/",
5380 ],
5381};
5382
5383static EVTX_FIELDS: &[FieldSchema] = &[
5384 FieldSchema {
5385 name: "event_id",
5386 description: "Windows Event ID",
5387 value_type: ValueType::UnsignedInt,
5388 is_uid_component: true,
5389 },
5390 FieldSchema {
5391 name: "timestamp",
5392 description: "Event timestamp (UTC)",
5393 value_type: ValueType::Timestamp,
5394 is_uid_component: false,
5395 },
5396 FieldSchema {
5397 name: "computer",
5398 description: "Source computer name",
5399 value_type: ValueType::Text,
5400 is_uid_component: false,
5401 },
5402 FieldSchema {
5403 name: "subject_user_sid",
5404 description: "SID of the subject user",
5405 value_type: ValueType::Text,
5406 is_uid_component: false,
5407 },
5408 FieldSchema {
5409 name: "subject_user_name",
5410 description: "Username of the subject",
5411 value_type: ValueType::Text,
5412 is_uid_component: false,
5413 },
5414 FieldSchema {
5415 name: "message",
5416 description: "Full event message XML",
5417 value_type: ValueType::Text,
5418 is_uid_component: false,
5419 },
5420];
5421
5422pub static EVTX_SECURITY: ArtifactDescriptor = ArtifactDescriptor {
5423 id: "evtx_security",
5424 name: "Security Event Log (Security.evtx)",
5425 artifact_type: ArtifactType::File,
5426 hive: None,
5427 key_path: "",
5428 value_name: None,
5429 file_path: Some(r"C:\Windows\System32\winevt\Logs\Security.evtx"),
5430 scope: DataScope::System,
5431 os_scope: OsScope::Win7Plus,
5432 decoder: Decoder::Identity,
5433 meaning: "Primary security audit log. Key event IDs: 4624/4625 (logon success/fail), \
5434 4634/4647 (logoff), 4648 (explicit-cred logon), 4688/4689 (process create/exit), \
5435 4698/4702 (scheduled task create/modify), 4720/4732 (account create/group add), \
5436 1102 (audit log cleared — high-priority anti-forensics indicator).",
5437 mitre_techniques: &["T1070.001", "T1059", "T1078"],
5438 fields: EVTX_FIELDS,
5439 retention: Some("configurable; default ~20MB rolling per channel"),
5440 triage_priority: TriagePriority::Critical,
5441 related_artifacts: &[
5442 "srum_network_usage",
5443 "srum_app_resource",
5444 "prefetch_file",
5445 "shimcache",
5446 ],
5447 sources: &[
5448 "https://attack.mitre.org/techniques/T1070/001/",
5449 "https://attack.mitre.org/techniques/T1059/",
5450 "https://attack.mitre.org/techniques/T1078/",
5451 "https://www.sans.org/posters/windows-forensic-analysis/",
5452 "https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/basic-security-audit-policies",
5453 "https://www.13cubed.com/downloads/windows_event_log_cheat_sheet.pdf",
5454 "https://www.magnetforensics.com/blog/the-importance-of-powershell-logs-in-digital-forensics/",
5455 ],
5456};
5457
5458pub static EVTX_SYSTEM: ArtifactDescriptor = ArtifactDescriptor {
5459 id: "evtx_system",
5460 name: "System Event Log (System.evtx)",
5461 artifact_type: ArtifactType::File,
5462 hive: None,
5463 key_path: "",
5464 value_name: None,
5465 file_path: Some(r"C:\Windows\System32\winevt\Logs\System.evtx"),
5466 scope: DataScope::System,
5467 os_scope: OsScope::Win7Plus,
5468 decoder: Decoder::Identity,
5469 meaning:
5470 "System-level events. Key IDs: 7045 (service installed), 7036 (service state change), \
5471 6005/6006 (event log start/stop — boot/shutdown boundary), \
5472 104 (System log cleared). Service installation (7045) is a primary \
5473 lateral-movement and persistence indicator.",
5474 mitre_techniques: &["T1543.003", "T1070.001"],
5475 fields: EVTX_FIELDS,
5476 retention: Some("configurable; default ~20MB rolling per channel"),
5477 triage_priority: TriagePriority::High,
5478 related_artifacts: &["evtx_security", "scheduled_tasks_dir", "services_imagepath"],
5479 sources: &[
5480 "https://attack.mitre.org/techniques/T1543/003/",
5481 "https://attack.mitre.org/techniques/T1070/001/",
5482 "https://www.sans.org/posters/windows-forensic-analysis/",
5483 "https://learn.microsoft.com/en-us/windows/win32/eventlog/event-logging",
5484 ],
5485};
5486
5487pub static EVTX_POWERSHELL: ArtifactDescriptor = ArtifactDescriptor {
5488 id: "evtx_powershell",
5489 name: "PowerShell Operational Log",
5490 artifact_type: ArtifactType::File,
5491 hive: None,
5492 key_path: "",
5493 value_name: None,
5494 file_path: Some(
5495 r"C:\Windows\System32\winevt\Logs\Microsoft-Windows-PowerShell%4Operational.evtx",
5496 ),
5497 scope: DataScope::System,
5498 os_scope: OsScope::Win7Plus,
5499 decoder: Decoder::Identity,
5500 meaning:
5501 "PowerShell script execution telemetry. Event 4103 (module logging — pipeline output), \
5502 4104 (ScriptBlock logging — full script text including deobfuscated content). \
5503 4104 captures AMSI-deobfuscated scripts even when encoded; \
5504 highest-fidelity PS forensic source when enabled.",
5505 mitre_techniques: &["T1059.001", "T1027"],
5506 fields: EVTX_FIELDS,
5507 retention: Some("configurable; default ~20MB rolling per channel"),
5508 triage_priority: TriagePriority::High,
5509 related_artifacts: &[
5510 "evtx_security",
5511 "powershell_history",
5512 "powershell_profile_all",
5513 ],
5514 sources: &[
5515 "https://attack.mitre.org/techniques/T1059/001/",
5516 "https://attack.mitre.org/techniques/T1027/",
5517 "https://www.sans.org/blog/detecting-malicious-powershell/",
5518 "https://redcanary.com/threat-detection-report/techniques/t1059.001/",
5519 ],
5520};
5521
5522pub static EVTX_SYSMON: ArtifactDescriptor = ArtifactDescriptor {
5523 id: "evtx_sysmon",
5524 name: "Sysmon Operational Log",
5525 artifact_type: ArtifactType::File,
5526 hive: None,
5527 key_path: "",
5528 value_name: None,
5529 file_path: Some(r"C:\Windows\System32\winevt\Logs\Microsoft-Windows-Sysmon%4Operational.evtx"),
5530 scope: DataScope::System,
5531 os_scope: OsScope::Win7Plus,
5532 decoder: Decoder::Identity,
5533 meaning:
5534 "Sysmon telemetry (requires deployment). Event 1 (process create + hashes + cmdline), \
5535 3 (network connection), 7 (image load), 8 (CreateRemoteThread), \
5536 10 (ProcessAccess — LSASS reads), 11 (file create), 22 (DNS query). \
5537 Gold standard for EDR-quality forensics without commercial tooling.",
5538 mitre_techniques: &["T1059", "T1055", "T1003.001"],
5539 fields: EVTX_FIELDS,
5540 retention: Some("configurable; default ~20MB rolling per channel"),
5541 triage_priority: TriagePriority::Critical,
5542 related_artifacts: &["evtx_security", "prefetch_file", "srum_app_resource"],
5543 sources: &[
5544 "https://attack.mitre.org/techniques/T1059/",
5545 "https://attack.mitre.org/techniques/T1055/",
5546 "https://attack.mitre.org/techniques/T1003/001/",
5547 "https://learn.microsoft.com/en-us/sysinternals/downloads/sysmon",
5548 "https://www.sans.org/blog/threat-hunting-using-sysmon/",
5549 "https://www.thedfirspot.com/post/sysmon-when-visibility-is-key",
5550 ],
5551};
5552
5553pub static CATALOG: ForensicCatalog = ForensicCatalog::new(&[
5557 USERASSIST_EXE,
5558 USERASSIST_FOLDER,
5559 RUN_KEY_HKLM_RUN,
5560 RUN_KEY_HKCU_RUN,
5561 RUN_KEY_HKCU_RUNONCE,
5562 RUN_KEY_HKLM_RUNONCE,
5563 TYPED_URLS,
5564 TYPED_URLS_TIME,
5565 PCA_APPLAUNCH_DIC,
5566 IFEO_DEBUGGER,
5567 SHELLBAGS_USER,
5568 AMCACHE_APP_FILE,
5569 SHIMCACHE,
5570 BAM_USER,
5571 DAM_USER,
5572 SAM_USERS,
5573 LSA_SECRETS,
5574 DCC2_CACHE,
5575 MRU_RECENT_DOCS,
5576 USB_ENUM,
5577 MUICACHE,
5578 APPINIT_DLLS,
5579 WINLOGON_USERINIT,
5580 SCREENSAVER_EXE,
5581 WINLOGON_SHELL,
5583 SERVICES_IMAGEPATH,
5584 ACTIVE_SETUP_HKLM,
5585 ACTIVE_SETUP_HKCU,
5586 COM_HIJACK_CLSID_HKCU,
5587 APPCERT_DLLS,
5588 BOOT_EXECUTE,
5589 LSA_SECURITY_PKGS,
5590 LSA_AUTH_PKGS,
5591 PRINT_MONITORS,
5592 TIME_PROVIDERS,
5593 NETSH_HELPER_DLLS,
5594 BROWSER_HELPER_OBJECTS,
5595 STARTUP_FOLDER_USER,
5596 STARTUP_FOLDER_SYSTEM,
5597 SCHEDULED_TASKS_DIR,
5598 WDIGEST_CACHING,
5599 WORDWHEEL_QUERY,
5601 OPENSAVE_MRU,
5602 LASTVISITED_MRU,
5603 PREFETCH_DIR,
5604 SRUM_DB,
5605 WINDOWS_TIMELINE,
5606 POWERSHELL_HISTORY,
5607 RECYCLE_BIN,
5608 THUMBCACHE,
5609 SEARCH_DB_USER,
5610 DPAPI_MASTERKEY_USER,
5612 DPAPI_CRED_USER,
5613 DPAPI_CRED_ROAMING,
5614 WINDOWS_VAULT_USER,
5615 WINDOWS_VAULT_SYSTEM,
5616 RDP_CLIENT_SERVERS,
5617 RDP_CLIENT_DEFAULT,
5618 NTDS_DIT,
5619 CHROME_LOGIN_DATA,
5620 FIREFOX_LOGINS,
5621 WIFI_PROFILES,
5622 LINUX_CRONTAB_SYSTEM,
5624 LINUX_CRON_D,
5625 LINUX_CRON_PERIODIC,
5626 LINUX_USER_CRONTAB,
5627 LINUX_ANACRONTAB,
5628 LINUX_SYSTEMD_SYSTEM_UNIT,
5630 LINUX_SYSTEMD_USER_UNIT,
5631 LINUX_SYSTEMD_TIMER,
5632 LINUX_RC_LOCAL,
5634 LINUX_INIT_D,
5635 LINUX_BASHRC_USER,
5637 LINUX_BASH_PROFILE_USER,
5638 LINUX_PROFILE_USER,
5639 LINUX_ZSHRC_USER,
5640 LINUX_PROFILE_SYSTEM,
5641 LINUX_PROFILE_D,
5642 LINUX_LD_SO_PRELOAD,
5644 LINUX_LD_SO_CONF_D,
5645 LINUX_SSH_AUTHORIZED_KEYS,
5647 LINUX_PAM_D,
5649 LINUX_SUDOERS_D,
5650 LINUX_MODULES_LOAD_D,
5651 LINUX_MOTD_D,
5652 LINUX_UDEV_RULES_D,
5653 LINUX_BASH_HISTORY,
5655 LINUX_ZSH_HISTORY,
5656 LINUX_WTMP,
5657 LINUX_BTMP,
5658 LINUX_LASTLOG,
5659 LINUX_AUTH_LOG,
5660 LINUX_JOURNAL_DIR,
5661 LINUX_PASSWD,
5663 LINUX_SHADOW,
5664 LINUX_SSH_PRIVATE_KEY,
5665 LINUX_SSH_KNOWN_HOSTS,
5666 LINUX_GNUPG_PRIVATE,
5667 LINUX_AWS_CREDENTIALS,
5668 LINUX_DOCKER_CONFIG,
5669 LNK_FILES,
5671 JUMP_LIST_AUTO,
5672 JUMP_LIST_CUSTOM,
5673 EVTX_DIR,
5674 USN_JOURNAL,
5675 WMI_MOF_DIR,
5677 BITS_DB,
5678 WMI_SUBSCRIPTIONS,
5679 LOGON_SCRIPTS,
5680 WINSOCK_LSP,
5681 APPSHIM_DB,
5682 PASSWORD_FILTER_DLL,
5683 OFFICE_NORMAL_DOTM,
5684 POWERSHELL_PROFILE_ALL,
5685 DPAPI_SYSTEM_MASTERKEY,
5687 DPAPI_CREDHIST,
5688 CHROME_COOKIES,
5689 EDGE_WEBCACHE,
5690 VPN_RAS_PHONEBOOK,
5691 WINDOWS_HELLO_NGC,
5692 USER_CERT_PRIVATE_KEY,
5693 MACHINE_CERT_STORE,
5694 LINUX_AT_QUEUE,
5696 LINUX_SSHD_CONFIG,
5697 LINUX_ETC_GROUP,
5698 LINUX_GNOME_KEYRING,
5699 LINUX_KDE_KWALLET,
5700 LINUX_CHROME_LOGIN_LINUX,
5701 LINUX_FIREFOX_LOGINS_LINUX,
5702 LINUX_UTMP,
5703 LINUX_GCP_CREDENTIALS,
5704 LINUX_AZURE_CREDENTIALS,
5705 LINUX_KUBE_CONFIG,
5706 LINUX_GIT_CREDENTIALS,
5707 LINUX_NETRC,
5708 LINUX_ETC_ENVIRONMENT,
5710 LINUX_XDG_AUTOSTART_USER,
5711 LINUX_XDG_AUTOSTART_SYSTEM,
5712 LINUX_NETWORKMANAGER_DISPATCHER,
5713 LINUX_APT_HOOKS,
5714 JUMP_LIST_SYSTEM,
5716 LNK_FILES_OFFICE,
5717 PREFETCH_FILE,
5718 SRUM_NETWORK_USAGE,
5719 SRUM_APP_RESOURCE,
5720 SRUM_ENERGY_USAGE,
5721 SRUM_PUSH_NOTIFICATION,
5722 EVTX_SECURITY,
5723 EVTX_SYSTEM,
5724 EVTX_POWERSHELL,
5725 EVTX_SYSMON,
5726]);
5727
5728#[cfg(test)]
5731mod tests {
5732 use super::*;
5733
5734 #[test]
5737 fn filetime_zero_returns_none() {
5738 assert_eq!(filetime_to_iso8601(0), None);
5739 }
5740
5741 #[test]
5742 fn filetime_before_unix_epoch_returns_none() {
5743 assert_eq!(filetime_to_iso8601(1), None);
5745 }
5746
5747 #[test]
5748 fn filetime_unix_epoch_is_1970() {
5749 let ft: u64 = 116_444_736_000_000_000;
5751 assert_eq!(
5752 filetime_to_iso8601(ft),
5753 Some("1970-01-01T00:00:00Z".to_string())
5754 );
5755 }
5756
5757 #[test]
5758 fn filetime_known_date_2023() {
5759 let unix_ts: u64 = 1_673_778_600;
5763 let ft = unix_ts * 10_000_000 + 116_444_736_000_000_000;
5764 assert_eq!(
5765 filetime_to_iso8601(ft),
5766 Some("2023-01-15T10:30:00Z".to_string())
5767 );
5768 }
5769
5770 #[test]
5773 fn rot13_roundtrip() {
5774 let s = "Hello, World!";
5775 assert_eq!(rot13(&rot13(s)), s);
5776 }
5777
5778 #[test]
5779 fn rot13_known_value() {
5780 assert_eq!(rot13("URYYB"), "HELLO");
5781 }
5782
5783 #[test]
5784 fn rot13_numbers_unchanged() {
5785 assert_eq!(rot13("12345"), "12345");
5786 }
5787
5788 #[test]
5791 fn catalog_has_entries() {
5792 assert!(!CATALOG.list().is_empty());
5793 assert_eq!(CATALOG.list().len(), 151);
5794 }
5795
5796 #[test]
5797 fn catalog_by_id_userassist() {
5798 let desc = CATALOG.by_id("userassist_exe").unwrap();
5799 assert_eq!(desc.name, "UserAssist (EXE)");
5800 assert_eq!(desc.hive, Some(HiveTarget::NtUser));
5801 assert_eq!(desc.scope, DataScope::User);
5802 }
5803
5804 #[test]
5805 fn catalog_by_id_missing_returns_none() {
5806 assert!(CATALOG.by_id("nonexistent").is_none());
5807 }
5808
5809 #[test]
5810 fn catalog_filter_by_hive_ntuser() {
5811 let q = ArtifactQuery {
5812 hive: Some(HiveTarget::NtUser),
5813 ..Default::default()
5814 };
5815 let results = CATALOG.filter(&q);
5816 assert!(results.len() >= 2); assert!(results.iter().all(|d| d.hive == Some(HiveTarget::NtUser)));
5818 }
5819
5820 #[test]
5821 fn catalog_filter_by_scope_system() {
5822 let q = ArtifactQuery {
5823 scope: Some(DataScope::System),
5824 ..Default::default()
5825 };
5826 let results = CATALOG.filter(&q);
5827 assert!(results.iter().all(|d| d.scope == DataScope::System));
5828 }
5829
5830 #[test]
5831 fn catalog_filter_by_mitre_technique() {
5832 let q = ArtifactQuery {
5833 mitre_technique: Some("T1547.001"),
5834 ..Default::default()
5835 };
5836 let results = CATALOG.filter(&q);
5837 assert!(!results.is_empty());
5838 assert!(results
5839 .iter()
5840 .all(|d| d.mitre_techniques.contains(&"T1547.001")));
5841 }
5842
5843 #[test]
5844 fn catalog_filter_by_artifact_type_file() {
5845 let q = ArtifactQuery {
5846 artifact_type: Some(ArtifactType::File),
5847 ..Default::default()
5848 };
5849 let results = CATALOG.filter(&q);
5850 assert!(!results.is_empty());
5853 assert!(results.iter().any(|d| d.id == "pca_applaunch_dic"));
5855 }
5856
5857 #[test]
5858 fn catalog_filter_empty_query_returns_all() {
5859 let q = ArtifactQuery::default();
5860 assert_eq!(CATALOG.filter(&q).len(), CATALOG.list().len());
5861 }
5862
5863 #[test]
5864 fn catalog_filter_by_id() {
5865 let q = ArtifactQuery {
5866 id: Some("typed_urls"),
5867 ..Default::default()
5868 };
5869 let results = CATALOG.filter(&q);
5870 assert_eq!(results.len(), 1);
5871 assert_eq!(results[0].id, "typed_urls");
5872 }
5873
5874 #[test]
5875 fn catalog_filter_combined_scope_and_hive() {
5876 let q = ArtifactQuery {
5877 scope: Some(DataScope::User),
5878 hive: Some(HiveTarget::NtUser),
5879 ..Default::default()
5880 };
5881 let results = CATALOG.filter(&q);
5882 assert!(results.len() >= 2);
5883 }
5884
5885 #[test]
5888 fn decode_identity_utf8() {
5889 let rec = CATALOG
5890 .decode(&RUN_KEY_HKLM_RUN, "MyApp", b"C:\\Program Files\\app.exe")
5891 .unwrap();
5892 assert_eq!(rec.artifact_id, "run_key_hklm");
5893 assert_eq!(
5894 rec.fields,
5895 vec![(
5896 "value",
5897 ArtifactValue::Text("C:\\Program Files\\app.exe".to_string())
5898 )]
5899 );
5900 }
5901
5902 #[test]
5903 fn decode_identity_empty_raw() {
5904 let rec = CATALOG.decode(&RUN_KEY_HKLM_RUN, "", b"").unwrap();
5905 assert_eq!(
5906 rec.fields,
5907 vec![("value", ArtifactValue::Text(String::new()))]
5908 );
5909 }
5910
5911 #[test]
5912 fn decode_identity_invalid_utf8() {
5913 let err = CATALOG
5914 .decode(&RUN_KEY_HKLM_RUN, "", &[0xFF, 0xFE, 0x80])
5915 .unwrap_err();
5916 assert_eq!(err, DecodeError::InvalidUtf8);
5917 }
5918
5919 #[test]
5922 fn decode_userassist_valid() {
5923 let mut raw = vec![0u8; 72];
5929 raw[4..8].copy_from_slice(&5u32.to_le_bytes());
5930 raw[8..12].copy_from_slice(&3u32.to_le_bytes());
5931 raw[12..16].copy_from_slice(&10000u32.to_le_bytes());
5932 let ft: u64 = 1_673_778_600 * 10_000_000 + 116_444_736_000_000_000;
5933 raw[60..68].copy_from_slice(&ft.to_le_bytes());
5934
5935 let rot13_name = rot13("C:\\Program Files\\notepad.exe");
5936 let rec = CATALOG.decode(&USERASSIST_EXE, &rot13_name, &raw).unwrap();
5937
5938 assert_eq!(rec.artifact_id, "userassist_exe");
5939 assert_eq!(rec.scope, DataScope::User);
5940 assert_eq!(
5941 rec.fields[0],
5942 (
5943 "program",
5944 ArtifactValue::Text("C:\\Program Files\\notepad.exe".to_string())
5945 )
5946 );
5947 assert_eq!(rec.fields[1], ("run_count", ArtifactValue::UnsignedInt(5)));
5948 assert_eq!(
5949 rec.fields[2],
5950 ("focus_count", ArtifactValue::UnsignedInt(3))
5951 );
5952 assert_eq!(
5953 rec.fields[3],
5954 ("focus_duration_ms", ArtifactValue::UnsignedInt(10000))
5955 );
5956 assert_eq!(
5957 rec.fields[4],
5958 (
5959 "last_run",
5960 ArtifactValue::Timestamp("2023-01-15T10:30:00Z".to_string())
5961 )
5962 );
5963 assert_eq!(rec.timestamp, Some("2023-01-15T10:30:00Z".to_string()));
5964 }
5965
5966 #[test]
5967 fn decode_userassist_buffer_too_short() {
5968 let raw = vec![0u8; 16]; let err = CATALOG.decode(&USERASSIST_EXE, "test", &raw).unwrap_err();
5970 match err {
5971 DecodeError::FieldOutOfBounds { field, .. } => {
5972 assert_eq!(field, "last_run");
5973 }
5974 other => panic!("expected FieldOutOfBounds, got: {other:?}"),
5975 }
5976 }
5977
5978 #[test]
5979 fn decode_userassist_zero_filetime() {
5980 let raw = vec![0u8; 72];
5982 let rec = CATALOG.decode(&USERASSIST_EXE, "grfg", &raw).unwrap();
5983 assert_eq!(rec.fields[4], ("last_run", ArtifactValue::Null));
5984 assert_eq!(rec.timestamp, None);
5985 }
5986
5987 #[test]
5990 fn decode_pipe_delimited_from_name() {
5991 let rec = CATALOG
5992 .decode(
5993 &PCA_APPLAUNCH_DIC,
5994 r"C:\Windows\notepad.exe|2023-01-15 10:30:00",
5995 b"",
5996 )
5997 .unwrap();
5998 assert_eq!(rec.artifact_id, "pca_applaunch_dic");
5999 assert_eq!(
6000 rec.fields[0],
6001 (
6002 "exe_path",
6003 ArtifactValue::Text(r"C:\Windows\notepad.exe".to_string())
6004 )
6005 );
6006 assert_eq!(
6007 rec.fields[1],
6008 (
6009 "timestamp",
6010 ArtifactValue::Text("2023-01-15 10:30:00".to_string())
6011 )
6012 );
6013 }
6014
6015 #[test]
6016 fn decode_pipe_delimited_fewer_fields_than_schema() {
6017 let rec = CATALOG
6019 .decode(&PCA_APPLAUNCH_DIC, r"C:\app.exe", b"")
6020 .unwrap();
6021 assert_eq!(
6022 rec.fields[0],
6023 ("exe_path", ArtifactValue::Text(r"C:\app.exe".to_string()))
6024 );
6025 assert_eq!(rec.fields[1], ("timestamp", ArtifactValue::Null));
6027 }
6028
6029 #[test]
6030 fn decode_pipe_delimited_from_raw_when_name_empty() {
6031 let raw = b"C:\\tool.exe|2024-06-01";
6032 let rec = CATALOG.decode(&PCA_APPLAUNCH_DIC, "", raw).unwrap();
6033 assert_eq!(
6034 rec.fields[0],
6035 ("exe_path", ArtifactValue::Text("C:\\tool.exe".to_string()))
6036 );
6037 }
6038
6039 #[test]
6042 fn decode_dword_le() {
6043 static DWORD_DESC: ArtifactDescriptor = ArtifactDescriptor {
6045 id: "test_dword",
6046 name: "Test DWORD",
6047 artifact_type: ArtifactType::RegistryValue,
6048 hive: Some(HiveTarget::HklmSoftware),
6049 key_path: "Test",
6050 value_name: None,
6051 file_path: None,
6052 scope: DataScope::System,
6053 os_scope: OsScope::All,
6054 decoder: Decoder::DwordLe,
6055 meaning: "test",
6056 mitre_techniques: &[],
6057 fields: &[],
6058 retention: None,
6059 triage_priority: TriagePriority::Low,
6060 related_artifacts: &[],
6061 sources: &[],
6062 };
6063 let raw = 42u32.to_le_bytes();
6064 let rec = CATALOG.decode(&DWORD_DESC, "val", &raw).unwrap();
6065 assert_eq!(rec.fields, vec![("value", ArtifactValue::UnsignedInt(42))]);
6066 }
6067
6068 #[test]
6069 fn decode_dword_le_too_short() {
6070 static DWORD_DESC: ArtifactDescriptor = ArtifactDescriptor {
6071 id: "test_dword2",
6072 name: "Test DWORD 2",
6073 artifact_type: ArtifactType::RegistryValue,
6074 hive: Some(HiveTarget::HklmSoftware),
6075 key_path: "Test",
6076 value_name: None,
6077 file_path: None,
6078 scope: DataScope::System,
6079 os_scope: OsScope::All,
6080 decoder: Decoder::DwordLe,
6081 meaning: "test",
6082 mitre_techniques: &[],
6083 fields: &[],
6084 retention: None,
6085 triage_priority: TriagePriority::Low,
6086 related_artifacts: &[],
6087 sources: &[],
6088 };
6089 let err = CATALOG.decode(&DWORD_DESC, "v", &[1, 2]).unwrap_err();
6090 assert_eq!(
6091 err,
6092 DecodeError::BufferTooShort {
6093 expected: 4,
6094 actual: 2
6095 }
6096 );
6097 }
6098
6099 #[test]
6102 fn decode_utf16le() {
6103 static UTF16_DESC: ArtifactDescriptor = ArtifactDescriptor {
6104 id: "test_utf16",
6105 name: "Test UTF-16",
6106 artifact_type: ArtifactType::RegistryValue,
6107 hive: Some(HiveTarget::NtUser),
6108 key_path: "Test",
6109 value_name: None,
6110 file_path: None,
6111 scope: DataScope::User,
6112 os_scope: OsScope::All,
6113 decoder: Decoder::Utf16Le,
6114 meaning: "test",
6115 mitre_techniques: &[],
6116 fields: &[],
6117 retention: None,
6118 triage_priority: TriagePriority::Low,
6119 related_artifacts: &[],
6120 sources: &[],
6121 };
6122 let raw: &[u8] = &[0x48, 0x00, 0x69, 0x00, 0x00, 0x00];
6124 let rec = CATALOG.decode(&UTF16_DESC, "", raw).unwrap();
6125 assert_eq!(
6126 rec.fields,
6127 vec![("value", ArtifactValue::Text("Hi".to_string()))]
6128 );
6129 }
6130
6131 #[test]
6132 fn decode_utf16le_odd_length() {
6133 static UTF16_DESC: ArtifactDescriptor = ArtifactDescriptor {
6134 id: "test_utf16_odd",
6135 name: "Test UTF-16 odd",
6136 artifact_type: ArtifactType::RegistryValue,
6137 hive: Some(HiveTarget::NtUser),
6138 key_path: "Test",
6139 value_name: None,
6140 file_path: None,
6141 scope: DataScope::User,
6142 os_scope: OsScope::All,
6143 decoder: Decoder::Utf16Le,
6144 meaning: "test",
6145 mitre_techniques: &[],
6146 fields: &[],
6147 retention: None,
6148 triage_priority: TriagePriority::Low,
6149 related_artifacts: &[],
6150 sources: &[],
6151 };
6152 let err = CATALOG
6153 .decode(&UTF16_DESC, "", &[0x48, 0x00, 0x69])
6154 .unwrap_err();
6155 assert_eq!(err, DecodeError::InvalidUtf16);
6156 }
6157
6158 #[test]
6161 fn decode_multi_sz() {
6162 static MSZ_DESC: ArtifactDescriptor = ArtifactDescriptor {
6163 id: "test_msz",
6164 name: "Test MultiSz",
6165 artifact_type: ArtifactType::RegistryValue,
6166 hive: Some(HiveTarget::HklmSoftware),
6167 key_path: "Test",
6168 value_name: None,
6169 file_path: None,
6170 scope: DataScope::System,
6171 os_scope: OsScope::All,
6172 decoder: Decoder::MultiSz,
6173 meaning: "test",
6174 mitre_techniques: &[],
6175 fields: &[],
6176 retention: None,
6177 triage_priority: TriagePriority::Low,
6178 related_artifacts: &[],
6179 sources: &[],
6180 };
6181 let raw: &[u8] = &[
6183 0x41, 0x00, 0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, ];
6189 let rec = CATALOG.decode(&MSZ_DESC, "", raw).unwrap();
6190 assert_eq!(
6191 rec.fields,
6192 vec![(
6193 "values",
6194 ArtifactValue::List(vec![
6195 ArtifactValue::Text("AB".to_string()),
6196 ArtifactValue::Text("CD".to_string()),
6197 ])
6198 )]
6199 );
6200 }
6201
6202 #[test]
6203 fn decode_multi_sz_empty() {
6204 static MSZ_DESC: ArtifactDescriptor = ArtifactDescriptor {
6205 id: "test_msz_empty",
6206 name: "Test MultiSz empty",
6207 artifact_type: ArtifactType::RegistryValue,
6208 hive: Some(HiveTarget::HklmSoftware),
6209 key_path: "Test",
6210 value_name: None,
6211 file_path: None,
6212 scope: DataScope::System,
6213 os_scope: OsScope::All,
6214 decoder: Decoder::MultiSz,
6215 meaning: "test",
6216 mitre_techniques: &[],
6217 fields: &[],
6218 retention: None,
6219 triage_priority: TriagePriority::Low,
6220 related_artifacts: &[],
6221 sources: &[],
6222 };
6223 let rec = CATALOG.decode(&MSZ_DESC, "", &[]).unwrap();
6224 assert_eq!(rec.fields, vec![("values", ArtifactValue::List(vec![]))]);
6225 }
6226
6227 #[test]
6230 fn decode_mrulistex() {
6231 static MRU_DESC: ArtifactDescriptor = ArtifactDescriptor {
6232 id: "test_mru",
6233 name: "Test MRUListEx",
6234 artifact_type: ArtifactType::RegistryValue,
6235 hive: Some(HiveTarget::NtUser),
6236 key_path: "Test",
6237 value_name: None,
6238 file_path: None,
6239 scope: DataScope::User,
6240 os_scope: OsScope::All,
6241 decoder: Decoder::MruListEx,
6242 meaning: "test",
6243 mitre_techniques: &[],
6244 fields: &[],
6245 retention: None,
6246 triage_priority: TriagePriority::Low,
6247 related_artifacts: &[],
6248 sources: &[],
6249 };
6250 let mut raw = Vec::new();
6252 raw.extend_from_slice(&2u32.to_le_bytes());
6253 raw.extend_from_slice(&0u32.to_le_bytes());
6254 raw.extend_from_slice(&1u32.to_le_bytes());
6255 raw.extend_from_slice(&0xFFFF_FFFFu32.to_le_bytes());
6256 let rec = CATALOG.decode(&MRU_DESC, "", &raw).unwrap();
6257 assert_eq!(
6258 rec.fields,
6259 vec![(
6260 "indices",
6261 ArtifactValue::List(vec![
6262 ArtifactValue::UnsignedInt(2),
6263 ArtifactValue::UnsignedInt(0),
6264 ArtifactValue::UnsignedInt(1),
6265 ])
6266 )]
6267 );
6268 }
6269
6270 #[test]
6271 fn decode_mrulistex_empty() {
6272 static MRU_DESC: ArtifactDescriptor = ArtifactDescriptor {
6273 id: "test_mru_empty",
6274 name: "Test MRUListEx empty",
6275 artifact_type: ArtifactType::RegistryValue,
6276 hive: Some(HiveTarget::NtUser),
6277 key_path: "Test",
6278 value_name: None,
6279 file_path: None,
6280 scope: DataScope::User,
6281 os_scope: OsScope::All,
6282 decoder: Decoder::MruListEx,
6283 meaning: "test",
6284 mitre_techniques: &[],
6285 fields: &[],
6286 retention: None,
6287 triage_priority: TriagePriority::Low,
6288 related_artifacts: &[],
6289 sources: &[],
6290 };
6291 let rec = CATALOG.decode(&MRU_DESC, "", &[]).unwrap();
6292 assert_eq!(rec.fields, vec![("indices", ArtifactValue::List(vec![]))]);
6293 }
6294
6295 #[test]
6298 fn decode_filetime_at() {
6299 static FT_DESC: ArtifactDescriptor = ArtifactDescriptor {
6300 id: "test_ft",
6301 name: "Test FiletimeAt",
6302 artifact_type: ArtifactType::RegistryValue,
6303 hive: Some(HiveTarget::NtUser),
6304 key_path: "Test",
6305 value_name: None,
6306 file_path: None,
6307 scope: DataScope::User,
6308 os_scope: OsScope::All,
6309 decoder: Decoder::FiletimeAt { offset: 0 },
6310 meaning: "test",
6311 mitre_techniques: &[],
6312 fields: &[],
6313 retention: None,
6314 triage_priority: TriagePriority::Low,
6315 related_artifacts: &[],
6316 sources: &[],
6317 };
6318 let ft: u64 = 116_444_736_000_000_000; let raw = ft.to_le_bytes();
6320 let rec = CATALOG.decode(&FT_DESC, "", &raw).unwrap();
6321 assert_eq!(
6322 rec.fields,
6323 vec![(
6324 "timestamp",
6325 ArtifactValue::Timestamp("1970-01-01T00:00:00Z".to_string())
6326 )]
6327 );
6328 assert_eq!(rec.timestamp, Some("1970-01-01T00:00:00Z".to_string()));
6329 }
6330
6331 #[test]
6332 fn decode_filetime_at_buffer_too_short() {
6333 static FT_DESC: ArtifactDescriptor = ArtifactDescriptor {
6334 id: "test_ft_short",
6335 name: "Test FiletimeAt short",
6336 artifact_type: ArtifactType::RegistryValue,
6337 hive: Some(HiveTarget::NtUser),
6338 key_path: "Test",
6339 value_name: None,
6340 file_path: None,
6341 scope: DataScope::User,
6342 os_scope: OsScope::All,
6343 decoder: Decoder::FiletimeAt { offset: 4 },
6344 meaning: "test",
6345 mitre_techniques: &[],
6346 fields: &[],
6347 retention: None,
6348 triage_priority: TriagePriority::Low,
6349 related_artifacts: &[],
6350 sources: &[],
6351 };
6352 let err = CATALOG.decode(&FT_DESC, "", &[0; 8]).unwrap_err();
6353 assert_eq!(
6354 err,
6355 DecodeError::BufferTooShort {
6356 expected: 12,
6357 actual: 8
6358 }
6359 );
6360 }
6361
6362 #[test]
6365 fn uid_registry_with_name() {
6366 let rec = CATALOG
6367 .decode(&RUN_KEY_HKLM_RUN, "MyApp", b"cmd.exe")
6368 .unwrap();
6369 assert!(rec.uid.starts_with("winreg://HKLM\\SOFTWARE/"));
6370 assert!(rec.uid.contains("MyApp"));
6371 }
6372
6373 #[test]
6374 fn uid_file_artifact() {
6375 let rec = CATALOG.decode(&PCA_APPLAUNCH_DIC, "line1", b"").unwrap();
6376 assert!(rec.uid.starts_with("file://"));
6377 assert!(rec.uid.contains("AppLaunch.dic"));
6378 }
6379
6380 #[test]
6383 fn decode_error_display_buffer_too_short() {
6384 let e = DecodeError::BufferTooShort {
6385 expected: 8,
6386 actual: 4,
6387 };
6388 assert_eq!(e.to_string(), "buffer too short: need 8 bytes, got 4");
6389 }
6390
6391 #[test]
6392 fn decode_error_display_field_out_of_bounds() {
6393 let e = DecodeError::FieldOutOfBounds {
6394 field: "last_run",
6395 offset: 60,
6396 size: 8,
6397 buf_len: 16,
6398 };
6399 assert!(e.to_string().contains("last_run"));
6400 }
6401
6402 #[test]
6405 fn userassist_descriptor_has_correct_metadata() {
6406 assert_eq!(USERASSIST_EXE.id, "userassist_exe");
6407 assert_eq!(USERASSIST_EXE.hive, Some(HiveTarget::NtUser));
6408 assert_eq!(USERASSIST_EXE.scope, DataScope::User);
6409 assert_eq!(USERASSIST_EXE.os_scope, OsScope::Win7Plus);
6410 assert!(!USERASSIST_EXE.mitre_techniques.is_empty());
6411 assert!(!USERASSIST_EXE.fields.is_empty());
6412 assert!(USERASSIST_EXE.key_path.contains("UserAssist"));
6413 }
6414
6415 #[test]
6416 fn pca_descriptor_has_correct_metadata() {
6417 assert_eq!(PCA_APPLAUNCH_DIC.id, "pca_applaunch_dic");
6418 assert_eq!(PCA_APPLAUNCH_DIC.artifact_type, ArtifactType::File);
6419 assert_eq!(PCA_APPLAUNCH_DIC.hive, None);
6420 assert_eq!(PCA_APPLAUNCH_DIC.os_scope, OsScope::Win11_22H2);
6421 assert!(PCA_APPLAUNCH_DIC.file_path.is_some());
6422 }
6423
6424 #[test]
6425 fn run_key_descriptor_has_correct_metadata() {
6426 assert_eq!(RUN_KEY_HKLM_RUN.scope, DataScope::System);
6427 assert!(RUN_KEY_HKLM_RUN.mitre_techniques.contains(&"T1547.001"));
6428 }
6429
6430 #[test]
6433 fn decoded_record_has_default_confidence() {
6434 let rec = CATALOG.decode(&RUN_KEY_HKLM_RUN, "x", b"y").unwrap();
6435 assert!((rec.confidence - 1.0).abs() < f32::EPSILON);
6436 }
6437
6438 #[test]
6441 fn binary_record_exact_size_boundary() {
6442 static FIELDS: &[BinaryField] = &[BinaryField {
6444 name: "val",
6445 offset: 0,
6446 field_type: BinaryFieldType::U32Le,
6447 description: "test",
6448 }];
6449 static DESC: ArtifactDescriptor = ArtifactDescriptor {
6450 id: "test_exact",
6451 name: "Test exact",
6452 artifact_type: ArtifactType::RegistryValue,
6453 hive: Some(HiveTarget::HklmSoftware),
6454 key_path: "Test",
6455 value_name: None,
6456 file_path: None,
6457 scope: DataScope::System,
6458 os_scope: OsScope::All,
6459 decoder: Decoder::BinaryRecord(FIELDS),
6460 meaning: "test",
6461 mitre_techniques: &[],
6462 fields: &[],
6463 retention: None,
6464 triage_priority: TriagePriority::Low,
6465 related_artifacts: &[],
6466 sources: &[],
6467 };
6468 let raw = 99u32.to_le_bytes();
6469 let rec = CATALOG.decode(&DESC, "", &raw).unwrap();
6470 assert_eq!(rec.fields, vec![("val", ArtifactValue::UnsignedInt(99))]);
6471 }
6472
6473 #[test]
6474 fn binary_record_bytes_field() {
6475 static FIELDS: &[BinaryField] = &[BinaryField {
6476 name: "header",
6477 offset: 0,
6478 field_type: BinaryFieldType::Bytes { len: 4 },
6479 description: "test header",
6480 }];
6481 static DESC: ArtifactDescriptor = ArtifactDescriptor {
6482 id: "test_bytes",
6483 name: "Test bytes",
6484 artifact_type: ArtifactType::RegistryValue,
6485 hive: Some(HiveTarget::HklmSoftware),
6486 key_path: "Test",
6487 value_name: None,
6488 file_path: None,
6489 scope: DataScope::System,
6490 os_scope: OsScope::All,
6491 decoder: Decoder::BinaryRecord(FIELDS),
6492 meaning: "test",
6493 mitre_techniques: &[],
6494 fields: &[],
6495 retention: None,
6496 triage_priority: TriagePriority::Low,
6497 related_artifacts: &[],
6498 sources: &[],
6499 };
6500 let raw = [0xDE, 0xAD, 0xBE, 0xEF];
6501 let rec = CATALOG.decode(&DESC, "", &raw).unwrap();
6502 assert_eq!(
6503 rec.fields,
6504 vec![("header", ArtifactValue::Bytes(vec![0xDE, 0xAD, 0xBE, 0xEF]))]
6505 );
6506 }
6507}
6508
6509#[cfg(test)]
6512mod tests_new_descriptors {
6513 use super::*;
6514
6515 #[test]
6518 fn run_key_hkcu_run_metadata() {
6519 assert_eq!(RUN_KEY_HKCU_RUN.id, "run_key_hkcu");
6520 assert_eq!(RUN_KEY_HKCU_RUN.hive, Some(HiveTarget::NtUser));
6521 assert_eq!(RUN_KEY_HKCU_RUN.scope, DataScope::User);
6522 assert!(RUN_KEY_HKCU_RUN.mitre_techniques.contains(&"T1547.001"));
6523 assert!(RUN_KEY_HKCU_RUN.key_path.contains("Run"));
6524 }
6525
6526 #[test]
6527 fn run_key_hkcu_runonce_metadata() {
6528 assert_eq!(RUN_KEY_HKCU_RUNONCE.id, "run_key_hkcu_once");
6529 assert_eq!(RUN_KEY_HKCU_RUNONCE.hive, Some(HiveTarget::NtUser));
6530 assert_eq!(RUN_KEY_HKCU_RUNONCE.scope, DataScope::User);
6531 assert!(RUN_KEY_HKCU_RUNONCE.key_path.contains("RunOnce"));
6532 }
6533
6534 #[test]
6535 fn run_key_hklm_runonce_metadata() {
6536 assert_eq!(RUN_KEY_HKLM_RUNONCE.id, "run_key_hklm_once");
6537 assert_eq!(RUN_KEY_HKLM_RUNONCE.hive, Some(HiveTarget::HklmSoftware));
6538 assert_eq!(RUN_KEY_HKLM_RUNONCE.scope, DataScope::System);
6539 assert!(RUN_KEY_HKLM_RUNONCE.key_path.contains("RunOnce"));
6540 }
6541
6542 #[test]
6545 fn ifeo_debugger_metadata() {
6546 assert_eq!(IFEO_DEBUGGER.id, "ifeo_debugger");
6547 assert_eq!(IFEO_DEBUGGER.hive, Some(HiveTarget::HklmSoftware));
6548 assert_eq!(IFEO_DEBUGGER.scope, DataScope::System);
6549 assert!(IFEO_DEBUGGER.mitre_techniques.contains(&"T1546.012"));
6550 assert!(IFEO_DEBUGGER
6551 .key_path
6552 .contains("Image File Execution Options"));
6553 }
6554
6555 #[test]
6558 fn userassist_folder_metadata() {
6559 assert_eq!(USERASSIST_FOLDER.id, "userassist_folder");
6560 assert_eq!(USERASSIST_FOLDER.hive, Some(HiveTarget::NtUser));
6561 assert_eq!(USERASSIST_FOLDER.scope, DataScope::User);
6562 assert!(USERASSIST_FOLDER.key_path.contains("UserAssist"));
6563 }
6564
6565 #[test]
6568 fn shellbags_user_metadata() {
6569 assert_eq!(SHELLBAGS_USER.id, "shellbags_user");
6570 assert_eq!(SHELLBAGS_USER.hive, Some(HiveTarget::UsrClass));
6571 assert_eq!(SHELLBAGS_USER.scope, DataScope::User);
6572 assert!(SHELLBAGS_USER.mitre_techniques.contains(&"T1083"));
6573 assert!(SHELLBAGS_USER.key_path.contains("Shell"));
6574 }
6575
6576 #[test]
6579 fn amcache_app_file_metadata() {
6580 assert_eq!(AMCACHE_APP_FILE.id, "amcache_app_file");
6581 assert_eq!(AMCACHE_APP_FILE.hive, Some(HiveTarget::Amcache));
6582 assert_eq!(AMCACHE_APP_FILE.scope, DataScope::System);
6583 assert!(AMCACHE_APP_FILE.mitre_techniques.contains(&"T1218"));
6584 }
6585
6586 #[test]
6589 fn shimcache_metadata() {
6590 assert_eq!(SHIMCACHE.id, "shimcache");
6591 assert_eq!(SHIMCACHE.hive, Some(HiveTarget::HklmSystem));
6592 assert_eq!(SHIMCACHE.scope, DataScope::System);
6593 assert!(SHIMCACHE.mitre_techniques.contains(&"T1218"));
6594 assert!(SHIMCACHE.key_path.contains("AppCompatCache"));
6595 }
6596
6597 #[test]
6600 fn bam_user_metadata() {
6601 assert_eq!(BAM_USER.id, "bam_user");
6602 assert_eq!(BAM_USER.hive, Some(HiveTarget::HklmSystem));
6603 assert_eq!(BAM_USER.scope, DataScope::Mixed);
6604 assert_eq!(BAM_USER.os_scope, OsScope::Win10Plus);
6605 assert!(BAM_USER.key_path.contains("bam"));
6606 }
6607
6608 #[test]
6609 fn dam_user_metadata() {
6610 assert_eq!(DAM_USER.id, "dam_user");
6611 assert_eq!(DAM_USER.hive, Some(HiveTarget::HklmSystem));
6612 assert_eq!(DAM_USER.scope, DataScope::Mixed);
6613 assert_eq!(DAM_USER.os_scope, OsScope::Win10Plus);
6614 assert!(DAM_USER.key_path.contains("dam"));
6615 }
6616
6617 #[test]
6620 fn sam_users_metadata() {
6621 assert_eq!(SAM_USERS.id, "sam_users");
6622 assert_eq!(SAM_USERS.hive, Some(HiveTarget::HklmSam));
6623 assert_eq!(SAM_USERS.scope, DataScope::System);
6624 assert!(SAM_USERS.key_path.contains("Users"));
6625 assert!(SAM_USERS.mitre_techniques.contains(&"T1003.002"));
6626 }
6627
6628 #[test]
6631 fn lsa_secrets_metadata() {
6632 assert_eq!(LSA_SECRETS.id, "lsa_secrets");
6633 assert_eq!(LSA_SECRETS.hive, Some(HiveTarget::HklmSecurity));
6634 assert_eq!(LSA_SECRETS.scope, DataScope::System);
6635 assert!(LSA_SECRETS.key_path.contains("Secrets"));
6636 assert!(LSA_SECRETS.mitre_techniques.contains(&"T1003.004"));
6637 }
6638
6639 #[test]
6640 fn dcc2_cache_metadata() {
6641 assert_eq!(DCC2_CACHE.id, "dcc2_cache");
6642 assert_eq!(DCC2_CACHE.hive, Some(HiveTarget::HklmSecurity));
6643 assert_eq!(DCC2_CACHE.scope, DataScope::System);
6644 assert!(DCC2_CACHE.mitre_techniques.contains(&"T1003.005"));
6645 }
6646
6647 #[test]
6650 fn typed_urls_time_metadata() {
6651 assert_eq!(TYPED_URLS_TIME.id, "typed_urls_time");
6652 assert_eq!(TYPED_URLS_TIME.hive, Some(HiveTarget::NtUser));
6653 assert_eq!(TYPED_URLS_TIME.scope, DataScope::User);
6654 assert!(TYPED_URLS_TIME.key_path.contains("TypedURLsTime"));
6655 }
6656
6657 #[test]
6660 fn mru_recent_docs_metadata() {
6661 assert_eq!(MRU_RECENT_DOCS.id, "mru_recent_docs");
6662 assert_eq!(MRU_RECENT_DOCS.hive, Some(HiveTarget::NtUser));
6663 assert_eq!(MRU_RECENT_DOCS.scope, DataScope::User);
6664 assert!(MRU_RECENT_DOCS.key_path.contains("RecentDocs"));
6665 }
6666
6667 #[test]
6670 fn usb_enum_metadata() {
6671 assert_eq!(USB_ENUM.id, "usb_enum");
6672 assert_eq!(USB_ENUM.hive, Some(HiveTarget::HklmSystem));
6673 assert_eq!(USB_ENUM.scope, DataScope::System);
6674 assert!(USB_ENUM.mitre_techniques.contains(&"T1200"));
6675 assert!(USB_ENUM.key_path.contains("USBSTOR"));
6676 }
6677
6678 #[test]
6681 fn muicache_metadata() {
6682 assert_eq!(MUICACHE.id, "muicache");
6683 assert_eq!(MUICACHE.hive, Some(HiveTarget::UsrClass));
6684 assert_eq!(MUICACHE.scope, DataScope::User);
6685 assert!(MUICACHE.key_path.contains("MuiCache"));
6686 }
6687
6688 #[test]
6691 fn appinit_dlls_metadata() {
6692 assert_eq!(APPINIT_DLLS.id, "appinit_dlls");
6693 assert_eq!(APPINIT_DLLS.hive, Some(HiveTarget::HklmSoftware));
6694 assert_eq!(APPINIT_DLLS.scope, DataScope::System);
6695 assert!(APPINIT_DLLS.mitre_techniques.contains(&"T1546.010"));
6696 assert!(APPINIT_DLLS.key_path.contains("Windows NT"));
6697 }
6698
6699 #[test]
6702 fn winlogon_userinit_metadata() {
6703 assert_eq!(WINLOGON_USERINIT.id, "winlogon_userinit");
6704 assert_eq!(WINLOGON_USERINIT.hive, Some(HiveTarget::HklmSoftware));
6705 assert_eq!(WINLOGON_USERINIT.scope, DataScope::System);
6706 assert!(WINLOGON_USERINIT.mitre_techniques.contains(&"T1547.004"));
6707 assert!(WINLOGON_USERINIT.key_path.contains("Winlogon"));
6708 }
6709
6710 #[test]
6713 fn screensaver_exe_metadata() {
6714 assert_eq!(SCREENSAVER_EXE.id, "screensaver_exe");
6715 assert_eq!(SCREENSAVER_EXE.hive, Some(HiveTarget::NtUser));
6716 assert_eq!(SCREENSAVER_EXE.scope, DataScope::User);
6717 assert!(SCREENSAVER_EXE.mitre_techniques.contains(&"T1546.002"));
6718 assert!(SCREENSAVER_EXE.key_path.contains("Desktop"));
6719 }
6720
6721 #[test]
6724 fn catalog_contains_all_new_descriptors() {
6725 let ids: Vec<&str> = CATALOG.list().iter().map(|d| d.id).collect();
6726 for expected in &[
6727 "run_key_hkcu",
6728 "run_key_hkcu_once",
6729 "run_key_hklm_once",
6730 "ifeo_debugger",
6731 "userassist_folder",
6732 "shellbags_user",
6733 "amcache_app_file",
6734 "shimcache",
6735 "bam_user",
6736 "dam_user",
6737 "sam_users",
6738 "lsa_secrets",
6739 "dcc2_cache",
6740 "typed_urls_time",
6741 "mru_recent_docs",
6742 "usb_enum",
6743 "muicache",
6744 "appinit_dlls",
6745 "winlogon_userinit",
6746 "screensaver_exe",
6747 ] {
6748 assert!(ids.contains(expected), "CATALOG missing: {expected}");
6749 }
6750 }
6751}
6752
6753#[cfg(test)]
6756mod tests_batch_c {
6757 use super::*;
6758
6759 #[test]
6762 fn winlogon_shell_md() {
6763 assert_eq!(WINLOGON_SHELL.id, "winlogon_shell");
6764 assert_eq!(WINLOGON_SHELL.hive, Some(HiveTarget::HklmSoftware));
6765 assert_eq!(WINLOGON_SHELL.scope, DataScope::System);
6766 assert!(WINLOGON_SHELL.mitre_techniques.contains(&"T1547.004"));
6767 assert!(WINLOGON_SHELL.key_path.contains("Winlogon"));
6768 }
6769 #[test]
6770 fn services_imagepath_md() {
6771 assert_eq!(SERVICES_IMAGEPATH.id, "services_imagepath");
6772 assert_eq!(SERVICES_IMAGEPATH.hive, Some(HiveTarget::HklmSystem));
6773 assert_eq!(SERVICES_IMAGEPATH.scope, DataScope::System);
6774 assert!(SERVICES_IMAGEPATH.mitre_techniques.contains(&"T1543.003"));
6775 }
6776 #[test]
6777 fn active_setup_hklm_md() {
6778 assert_eq!(ACTIVE_SETUP_HKLM.id, "active_setup_hklm");
6779 assert_eq!(ACTIVE_SETUP_HKLM.hive, Some(HiveTarget::HklmSoftware));
6780 assert_eq!(ACTIVE_SETUP_HKLM.scope, DataScope::System);
6781 assert!(ACTIVE_SETUP_HKLM.mitre_techniques.contains(&"T1547.014"));
6782 }
6783 #[test]
6784 fn active_setup_hkcu_md() {
6785 assert_eq!(ACTIVE_SETUP_HKCU.id, "active_setup_hkcu");
6786 assert_eq!(ACTIVE_SETUP_HKCU.hive, Some(HiveTarget::NtUser));
6787 assert_eq!(ACTIVE_SETUP_HKCU.scope, DataScope::User);
6788 }
6789 #[test]
6790 fn com_hijack_clsid_hkcu_md() {
6791 assert_eq!(COM_HIJACK_CLSID_HKCU.id, "com_hijack_clsid_hkcu");
6792 assert_eq!(COM_HIJACK_CLSID_HKCU.hive, Some(HiveTarget::UsrClass));
6793 assert_eq!(COM_HIJACK_CLSID_HKCU.scope, DataScope::User);
6794 assert!(COM_HIJACK_CLSID_HKCU
6795 .mitre_techniques
6796 .contains(&"T1546.015"));
6797 }
6798 #[test]
6799 fn appcert_dlls_md() {
6800 assert_eq!(APPCERT_DLLS.id, "appcert_dlls");
6801 assert_eq!(APPCERT_DLLS.hive, Some(HiveTarget::HklmSystem));
6802 assert_eq!(APPCERT_DLLS.scope, DataScope::System);
6803 assert!(APPCERT_DLLS.mitre_techniques.contains(&"T1546.009"));
6804 }
6805 #[test]
6806 fn boot_execute_md() {
6807 assert_eq!(BOOT_EXECUTE.id, "boot_execute");
6808 assert_eq!(BOOT_EXECUTE.hive, Some(HiveTarget::HklmSystem));
6809 assert_eq!(BOOT_EXECUTE.scope, DataScope::System);
6810 assert!(BOOT_EXECUTE.mitre_techniques.contains(&"T1547.001"));
6811 assert!(BOOT_EXECUTE.key_path.contains("Session Manager"));
6812 }
6813 #[test]
6814 fn lsa_security_pkgs_md() {
6815 assert_eq!(LSA_SECURITY_PKGS.id, "lsa_security_pkgs");
6816 assert_eq!(LSA_SECURITY_PKGS.hive, Some(HiveTarget::HklmSystem));
6817 assert_eq!(LSA_SECURITY_PKGS.scope, DataScope::System);
6818 assert!(LSA_SECURITY_PKGS.mitre_techniques.contains(&"T1547.005"));
6819 }
6820 #[test]
6821 fn lsa_auth_pkgs_md() {
6822 assert_eq!(LSA_AUTH_PKGS.id, "lsa_auth_pkgs");
6823 assert_eq!(LSA_AUTH_PKGS.hive, Some(HiveTarget::HklmSystem));
6824 assert_eq!(LSA_AUTH_PKGS.scope, DataScope::System);
6825 assert!(LSA_AUTH_PKGS.mitre_techniques.contains(&"T1547.002"));
6826 }
6827 #[test]
6828 fn print_monitors_md() {
6829 assert_eq!(PRINT_MONITORS.id, "print_monitors");
6830 assert_eq!(PRINT_MONITORS.hive, Some(HiveTarget::HklmSystem));
6831 assert_eq!(PRINT_MONITORS.scope, DataScope::System);
6832 assert!(PRINT_MONITORS.mitre_techniques.contains(&"T1547.010"));
6833 }
6834 #[test]
6835 fn time_providers_md() {
6836 assert_eq!(TIME_PROVIDERS.id, "time_providers");
6837 assert_eq!(TIME_PROVIDERS.hive, Some(HiveTarget::HklmSystem));
6838 assert_eq!(TIME_PROVIDERS.scope, DataScope::System);
6839 assert!(TIME_PROVIDERS.mitre_techniques.contains(&"T1547.003"));
6840 }
6841 #[test]
6842 fn netsh_helper_dlls_md() {
6843 assert_eq!(NETSH_HELPER_DLLS.id, "netsh_helper_dlls");
6844 assert_eq!(NETSH_HELPER_DLLS.hive, Some(HiveTarget::HklmSoftware));
6845 assert_eq!(NETSH_HELPER_DLLS.scope, DataScope::System);
6846 assert!(NETSH_HELPER_DLLS.mitre_techniques.contains(&"T1546.007"));
6847 }
6848 #[test]
6849 fn browser_helper_objects_md() {
6850 assert_eq!(BROWSER_HELPER_OBJECTS.id, "browser_helper_objects");
6851 assert_eq!(BROWSER_HELPER_OBJECTS.hive, Some(HiveTarget::HklmSoftware));
6852 assert_eq!(BROWSER_HELPER_OBJECTS.scope, DataScope::System);
6853 assert!(BROWSER_HELPER_OBJECTS.mitre_techniques.contains(&"T1176"));
6854 }
6855 #[test]
6856 fn startup_folder_user_md() {
6857 assert_eq!(STARTUP_FOLDER_USER.id, "startup_folder_user");
6858 assert_eq!(STARTUP_FOLDER_USER.artifact_type, ArtifactType::Directory);
6859 assert_eq!(STARTUP_FOLDER_USER.scope, DataScope::User);
6860 assert!(STARTUP_FOLDER_USER.mitre_techniques.contains(&"T1547.001"));
6861 }
6862 #[test]
6863 fn startup_folder_system_md() {
6864 assert_eq!(STARTUP_FOLDER_SYSTEM.id, "startup_folder_system");
6865 assert_eq!(STARTUP_FOLDER_SYSTEM.artifact_type, ArtifactType::Directory);
6866 assert_eq!(STARTUP_FOLDER_SYSTEM.scope, DataScope::System);
6867 assert!(STARTUP_FOLDER_SYSTEM
6868 .mitre_techniques
6869 .contains(&"T1547.001"));
6870 }
6871 #[test]
6872 fn scheduled_tasks_dir_md() {
6873 assert_eq!(SCHEDULED_TASKS_DIR.id, "scheduled_tasks_dir");
6874 assert_eq!(SCHEDULED_TASKS_DIR.artifact_type, ArtifactType::Directory);
6875 assert_eq!(SCHEDULED_TASKS_DIR.scope, DataScope::System);
6876 assert!(SCHEDULED_TASKS_DIR.mitre_techniques.contains(&"T1053.005"));
6877 }
6878 #[test]
6879 fn wdigest_caching_md() {
6880 assert_eq!(WDIGEST_CACHING.id, "wdigest_caching");
6881 assert_eq!(WDIGEST_CACHING.hive, Some(HiveTarget::HklmSystem));
6882 assert_eq!(WDIGEST_CACHING.scope, DataScope::System);
6883 assert!(WDIGEST_CACHING.mitre_techniques.contains(&"T1003.001"));
6884 }
6885
6886 #[test]
6889 fn wordwheel_query_md() {
6890 assert_eq!(WORDWHEEL_QUERY.id, "wordwheel_query");
6891 assert_eq!(WORDWHEEL_QUERY.hive, Some(HiveTarget::NtUser));
6892 assert_eq!(WORDWHEEL_QUERY.scope, DataScope::User);
6893 assert!(WORDWHEEL_QUERY.key_path.contains("WordWheelQuery"));
6894 }
6895 #[test]
6896 fn opensave_mru_md() {
6897 assert_eq!(OPENSAVE_MRU.id, "opensave_mru");
6898 assert_eq!(OPENSAVE_MRU.hive, Some(HiveTarget::NtUser));
6899 assert_eq!(OPENSAVE_MRU.scope, DataScope::User);
6900 assert!(OPENSAVE_MRU.key_path.contains("OpenSaveMRU"));
6901 }
6902 #[test]
6903 fn lastvisited_mru_md() {
6904 assert_eq!(LASTVISITED_MRU.id, "lastvisited_mru");
6905 assert_eq!(LASTVISITED_MRU.hive, Some(HiveTarget::NtUser));
6906 assert_eq!(LASTVISITED_MRU.scope, DataScope::User);
6907 assert!(LASTVISITED_MRU.key_path.contains("LastVisitedMRU"));
6908 }
6909 #[test]
6910 fn prefetch_dir_md() {
6911 assert_eq!(PREFETCH_DIR.id, "prefetch_dir");
6912 assert_eq!(PREFETCH_DIR.artifact_type, ArtifactType::Directory);
6913 assert_eq!(PREFETCH_DIR.scope, DataScope::System);
6914 assert!(PREFETCH_DIR.mitre_techniques.contains(&"T1204.002"));
6915 }
6916 #[test]
6917 fn srum_db_md() {
6918 assert_eq!(SRUM_DB.id, "srum_db");
6919 assert_eq!(SRUM_DB.artifact_type, ArtifactType::File);
6920 assert_eq!(SRUM_DB.scope, DataScope::System);
6921 assert!(SRUM_DB.os_scope == OsScope::Win8Plus);
6922 }
6923 #[test]
6924 fn windows_timeline_md() {
6925 assert_eq!(WINDOWS_TIMELINE.id, "windows_timeline");
6926 assert_eq!(WINDOWS_TIMELINE.artifact_type, ArtifactType::File);
6927 assert_eq!(WINDOWS_TIMELINE.scope, DataScope::User);
6928 assert_eq!(WINDOWS_TIMELINE.os_scope, OsScope::Win10Plus);
6929 }
6930 #[test]
6931 fn powershell_history_md() {
6932 assert_eq!(POWERSHELL_HISTORY.id, "powershell_history");
6933 assert_eq!(POWERSHELL_HISTORY.artifact_type, ArtifactType::File);
6934 assert_eq!(POWERSHELL_HISTORY.scope, DataScope::User);
6935 assert!(POWERSHELL_HISTORY.mitre_techniques.contains(&"T1059.001"));
6936 }
6937 #[test]
6938 fn recycle_bin_md() {
6939 assert_eq!(RECYCLE_BIN.id, "recycle_bin");
6940 assert_eq!(RECYCLE_BIN.artifact_type, ArtifactType::Directory);
6941 assert_eq!(RECYCLE_BIN.scope, DataScope::User);
6942 assert!(RECYCLE_BIN.mitre_techniques.contains(&"T1070.004"));
6943 }
6944 #[test]
6945 fn thumbcache_md() {
6946 assert_eq!(THUMBCACHE.id, "thumbcache");
6947 assert_eq!(THUMBCACHE.artifact_type, ArtifactType::Directory);
6948 assert_eq!(THUMBCACHE.scope, DataScope::User);
6949 }
6950 #[test]
6951 fn search_db_user_md() {
6952 assert_eq!(SEARCH_DB_USER.id, "search_db_user");
6953 assert_eq!(SEARCH_DB_USER.artifact_type, ArtifactType::File);
6954 assert_eq!(SEARCH_DB_USER.scope, DataScope::System);
6955 }
6956
6957 #[test]
6960 fn dpapi_masterkey_user_md() {
6961 assert_eq!(DPAPI_MASTERKEY_USER.id, "dpapi_masterkey_user");
6962 assert_eq!(DPAPI_MASTERKEY_USER.artifact_type, ArtifactType::Directory);
6963 assert_eq!(DPAPI_MASTERKEY_USER.scope, DataScope::User);
6964 assert!(DPAPI_MASTERKEY_USER.mitre_techniques.contains(&"T1555.004"));
6965 }
6966 #[test]
6967 fn dpapi_cred_user_md() {
6968 assert_eq!(DPAPI_CRED_USER.id, "dpapi_cred_user");
6969 assert_eq!(DPAPI_CRED_USER.artifact_type, ArtifactType::Directory);
6970 assert_eq!(DPAPI_CRED_USER.scope, DataScope::User);
6971 }
6972 #[test]
6973 fn dpapi_cred_roaming_md() {
6974 assert_eq!(DPAPI_CRED_ROAMING.id, "dpapi_cred_roaming");
6975 assert_eq!(DPAPI_CRED_ROAMING.artifact_type, ArtifactType::Directory);
6976 assert_eq!(DPAPI_CRED_ROAMING.scope, DataScope::User);
6977 }
6978 #[test]
6979 fn windows_vault_user_md() {
6980 assert_eq!(WINDOWS_VAULT_USER.id, "windows_vault_user");
6981 assert_eq!(WINDOWS_VAULT_USER.artifact_type, ArtifactType::Directory);
6982 assert_eq!(WINDOWS_VAULT_USER.scope, DataScope::User);
6983 assert!(WINDOWS_VAULT_USER.mitre_techniques.contains(&"T1555.004"));
6984 }
6985 #[test]
6986 fn windows_vault_system_md() {
6987 assert_eq!(WINDOWS_VAULT_SYSTEM.id, "windows_vault_system");
6988 assert_eq!(WINDOWS_VAULT_SYSTEM.artifact_type, ArtifactType::Directory);
6989 assert_eq!(WINDOWS_VAULT_SYSTEM.scope, DataScope::System);
6990 }
6991 #[test]
6992 fn rdp_client_servers_md() {
6993 assert_eq!(RDP_CLIENT_SERVERS.id, "rdp_client_servers");
6994 assert_eq!(RDP_CLIENT_SERVERS.hive, Some(HiveTarget::NtUser));
6995 assert_eq!(RDP_CLIENT_SERVERS.scope, DataScope::User);
6996 assert!(RDP_CLIENT_SERVERS.mitre_techniques.contains(&"T1021.001"));
6997 }
6998 #[test]
6999 fn rdp_client_default_md() {
7000 assert_eq!(RDP_CLIENT_DEFAULT.id, "rdp_client_default");
7001 assert_eq!(RDP_CLIENT_DEFAULT.hive, Some(HiveTarget::NtUser));
7002 assert_eq!(RDP_CLIENT_DEFAULT.scope, DataScope::User);
7003 assert!(RDP_CLIENT_DEFAULT.mitre_techniques.contains(&"T1021.001"));
7004 }
7005 #[test]
7006 fn ntds_dit_md() {
7007 assert_eq!(NTDS_DIT.id, "ntds_dit");
7008 assert_eq!(NTDS_DIT.artifact_type, ArtifactType::File);
7009 assert_eq!(NTDS_DIT.scope, DataScope::System);
7010 assert!(NTDS_DIT.mitre_techniques.contains(&"T1003.003"));
7011 }
7012 #[test]
7013 fn chrome_login_data_md() {
7014 assert_eq!(CHROME_LOGIN_DATA.id, "chrome_login_data");
7015 assert_eq!(CHROME_LOGIN_DATA.artifact_type, ArtifactType::File);
7016 assert_eq!(CHROME_LOGIN_DATA.scope, DataScope::User);
7017 assert!(CHROME_LOGIN_DATA.mitre_techniques.contains(&"T1555.003"));
7018 }
7019 #[test]
7020 fn firefox_logins_md() {
7021 assert_eq!(FIREFOX_LOGINS.id, "firefox_logins");
7022 assert_eq!(FIREFOX_LOGINS.artifact_type, ArtifactType::File);
7023 assert_eq!(FIREFOX_LOGINS.scope, DataScope::User);
7024 assert!(FIREFOX_LOGINS.mitre_techniques.contains(&"T1555.003"));
7025 }
7026 #[test]
7027 fn wifi_profiles_md() {
7028 assert_eq!(WIFI_PROFILES.id, "wifi_profiles");
7029 assert_eq!(WIFI_PROFILES.artifact_type, ArtifactType::Directory);
7030 assert_eq!(WIFI_PROFILES.scope, DataScope::System);
7031 assert!(WIFI_PROFILES.mitre_techniques.contains(&"T1552.001"));
7032 }
7033
7034 #[test]
7037 fn catalog_contains_batch_c() {
7038 let ids: Vec<&str> = CATALOG.list().iter().map(|d| d.id).collect();
7039 for expected in &[
7040 "winlogon_shell",
7041 "services_imagepath",
7042 "active_setup_hklm",
7043 "active_setup_hkcu",
7044 "com_hijack_clsid_hkcu",
7045 "appcert_dlls",
7046 "boot_execute",
7047 "lsa_security_pkgs",
7048 "lsa_auth_pkgs",
7049 "print_monitors",
7050 "time_providers",
7051 "netsh_helper_dlls",
7052 "browser_helper_objects",
7053 "startup_folder_user",
7054 "startup_folder_system",
7055 "scheduled_tasks_dir",
7056 "wdigest_caching",
7057 "wordwheel_query",
7058 "opensave_mru",
7059 "lastvisited_mru",
7060 "prefetch_dir",
7061 "srum_db",
7062 "windows_timeline",
7063 "powershell_history",
7064 "recycle_bin",
7065 "thumbcache",
7066 "search_db_user",
7067 "dpapi_masterkey_user",
7068 "dpapi_cred_user",
7069 "dpapi_cred_roaming",
7070 "windows_vault_user",
7071 "windows_vault_system",
7072 "rdp_client_servers",
7073 "rdp_client_default",
7074 "ntds_dit",
7075 "chrome_login_data",
7076 "firefox_logins",
7077 "wifi_profiles",
7078 ] {
7079 assert!(ids.contains(expected), "CATALOG missing: {expected}");
7080 }
7081 }
7082}
7083
7084#[cfg(test)]
7087mod tests_batch_d {
7088 use super::*;
7089
7090 #[test]
7093 fn linux_crontab_system_md() {
7094 assert_eq!(LINUX_CRONTAB_SYSTEM.id, "linux_crontab_system");
7095 assert_eq!(LINUX_CRONTAB_SYSTEM.artifact_type, ArtifactType::File);
7096 assert_eq!(LINUX_CRONTAB_SYSTEM.scope, DataScope::System);
7097 assert_eq!(LINUX_CRONTAB_SYSTEM.os_scope, OsScope::Linux);
7098 assert!(LINUX_CRONTAB_SYSTEM.mitre_techniques.contains(&"T1053.003"));
7099 }
7100 #[test]
7101 fn linux_cron_d_md() {
7102 assert_eq!(LINUX_CRON_D.id, "linux_cron_d");
7103 assert_eq!(LINUX_CRON_D.artifact_type, ArtifactType::Directory);
7104 assert_eq!(LINUX_CRON_D.scope, DataScope::System);
7105 assert_eq!(LINUX_CRON_D.os_scope, OsScope::Linux);
7106 }
7107 #[test]
7108 fn linux_cron_periodic_md() {
7109 assert_eq!(LINUX_CRON_PERIODIC.id, "linux_cron_periodic");
7110 assert_eq!(LINUX_CRON_PERIODIC.artifact_type, ArtifactType::Directory);
7111 assert_eq!(LINUX_CRON_PERIODIC.scope, DataScope::System);
7112 }
7113 #[test]
7114 fn linux_user_crontab_md() {
7115 assert_eq!(LINUX_USER_CRONTAB.id, "linux_user_crontab");
7116 assert_eq!(LINUX_USER_CRONTAB.artifact_type, ArtifactType::File);
7117 assert_eq!(LINUX_USER_CRONTAB.scope, DataScope::User);
7118 assert!(LINUX_USER_CRONTAB.mitre_techniques.contains(&"T1053.003"));
7119 }
7120 #[test]
7121 fn linux_anacrontab_md() {
7122 assert_eq!(LINUX_ANACRONTAB.id, "linux_anacrontab");
7123 assert_eq!(LINUX_ANACRONTAB.artifact_type, ArtifactType::File);
7124 assert_eq!(LINUX_ANACRONTAB.scope, DataScope::System);
7125 }
7126
7127 #[test]
7130 fn linux_systemd_system_unit_md() {
7131 assert_eq!(LINUX_SYSTEMD_SYSTEM_UNIT.id, "linux_systemd_system_unit");
7132 assert_eq!(
7133 LINUX_SYSTEMD_SYSTEM_UNIT.artifact_type,
7134 ArtifactType::Directory
7135 );
7136 assert_eq!(LINUX_SYSTEMD_SYSTEM_UNIT.scope, DataScope::System);
7137 assert_eq!(LINUX_SYSTEMD_SYSTEM_UNIT.os_scope, OsScope::LinuxSystemd);
7138 assert!(LINUX_SYSTEMD_SYSTEM_UNIT
7139 .mitre_techniques
7140 .contains(&"T1543.002"));
7141 }
7142 #[test]
7143 fn linux_systemd_user_unit_md() {
7144 assert_eq!(LINUX_SYSTEMD_USER_UNIT.id, "linux_systemd_user_unit");
7145 assert_eq!(
7146 LINUX_SYSTEMD_USER_UNIT.artifact_type,
7147 ArtifactType::Directory
7148 );
7149 assert_eq!(LINUX_SYSTEMD_USER_UNIT.scope, DataScope::User);
7150 assert_eq!(LINUX_SYSTEMD_USER_UNIT.os_scope, OsScope::LinuxSystemd);
7151 }
7152 #[test]
7153 fn linux_systemd_timer_md() {
7154 assert_eq!(LINUX_SYSTEMD_TIMER.id, "linux_systemd_timer");
7155 assert_eq!(LINUX_SYSTEMD_TIMER.artifact_type, ArtifactType::Directory);
7156 assert_eq!(LINUX_SYSTEMD_TIMER.os_scope, OsScope::LinuxSystemd);
7157 assert!(LINUX_SYSTEMD_TIMER.mitre_techniques.contains(&"T1053.006"));
7158 }
7159
7160 #[test]
7163 fn linux_rc_local_md() {
7164 assert_eq!(LINUX_RC_LOCAL.id, "linux_rc_local");
7165 assert_eq!(LINUX_RC_LOCAL.artifact_type, ArtifactType::File);
7166 assert_eq!(LINUX_RC_LOCAL.scope, DataScope::System);
7167 assert!(LINUX_RC_LOCAL.mitre_techniques.contains(&"T1037.004"));
7168 }
7169 #[test]
7170 fn linux_init_d_md() {
7171 assert_eq!(LINUX_INIT_D.id, "linux_init_d");
7172 assert_eq!(LINUX_INIT_D.artifact_type, ArtifactType::Directory);
7173 assert_eq!(LINUX_INIT_D.scope, DataScope::System);
7174 }
7175
7176 #[test]
7179 fn linux_bashrc_user_md() {
7180 assert_eq!(LINUX_BASHRC_USER.id, "linux_bashrc_user");
7181 assert_eq!(LINUX_BASHRC_USER.artifact_type, ArtifactType::File);
7182 assert_eq!(LINUX_BASHRC_USER.scope, DataScope::User);
7183 assert!(LINUX_BASHRC_USER.mitre_techniques.contains(&"T1546.004"));
7184 }
7185 #[test]
7186 fn linux_bash_profile_user_md() {
7187 assert_eq!(LINUX_BASH_PROFILE_USER.id, "linux_bash_profile_user");
7188 assert_eq!(LINUX_BASH_PROFILE_USER.scope, DataScope::User);
7189 assert!(LINUX_BASH_PROFILE_USER
7190 .mitre_techniques
7191 .contains(&"T1546.004"));
7192 }
7193 #[test]
7194 fn linux_profile_user_md() {
7195 assert_eq!(LINUX_PROFILE_USER.id, "linux_profile_user");
7196 assert_eq!(LINUX_PROFILE_USER.scope, DataScope::User);
7197 }
7198 #[test]
7199 fn linux_zshrc_user_md() {
7200 assert_eq!(LINUX_ZSHRC_USER.id, "linux_zshrc_user");
7201 assert_eq!(LINUX_ZSHRC_USER.scope, DataScope::User);
7202 assert!(LINUX_ZSHRC_USER.mitre_techniques.contains(&"T1546.004"));
7203 }
7204 #[test]
7205 fn linux_profile_system_md() {
7206 assert_eq!(LINUX_PROFILE_SYSTEM.id, "linux_profile_system");
7207 assert_eq!(LINUX_PROFILE_SYSTEM.scope, DataScope::System);
7208 }
7209 #[test]
7210 fn linux_profile_d_md() {
7211 assert_eq!(LINUX_PROFILE_D.id, "linux_profile_d");
7212 assert_eq!(LINUX_PROFILE_D.artifact_type, ArtifactType::Directory);
7213 assert_eq!(LINUX_PROFILE_D.scope, DataScope::System);
7214 }
7215
7216 #[test]
7219 fn linux_ld_so_preload_md() {
7220 assert_eq!(LINUX_LD_SO_PRELOAD.id, "linux_ld_so_preload");
7221 assert_eq!(LINUX_LD_SO_PRELOAD.artifact_type, ArtifactType::File);
7222 assert_eq!(LINUX_LD_SO_PRELOAD.scope, DataScope::System);
7223 assert!(LINUX_LD_SO_PRELOAD.mitre_techniques.contains(&"T1574.006"));
7224 }
7225 #[test]
7226 fn linux_ld_so_conf_d_md() {
7227 assert_eq!(LINUX_LD_SO_CONF_D.id, "linux_ld_so_conf_d");
7228 assert_eq!(LINUX_LD_SO_CONF_D.artifact_type, ArtifactType::Directory);
7229 assert_eq!(LINUX_LD_SO_CONF_D.scope, DataScope::System);
7230 }
7231
7232 #[test]
7235 fn linux_ssh_authorized_keys_md() {
7236 assert_eq!(LINUX_SSH_AUTHORIZED_KEYS.id, "linux_ssh_authorized_keys");
7237 assert_eq!(LINUX_SSH_AUTHORIZED_KEYS.artifact_type, ArtifactType::File);
7238 assert_eq!(LINUX_SSH_AUTHORIZED_KEYS.scope, DataScope::User);
7239 assert!(LINUX_SSH_AUTHORIZED_KEYS
7240 .mitre_techniques
7241 .contains(&"T1098.004"));
7242 }
7243
7244 #[test]
7247 fn linux_pam_d_md() {
7248 assert_eq!(LINUX_PAM_D.id, "linux_pam_d");
7249 assert_eq!(LINUX_PAM_D.artifact_type, ArtifactType::Directory);
7250 assert_eq!(LINUX_PAM_D.scope, DataScope::System);
7251 assert!(LINUX_PAM_D.mitre_techniques.contains(&"T1556.003"));
7252 }
7253 #[test]
7254 fn linux_sudoers_d_md() {
7255 assert_eq!(LINUX_SUDOERS_D.id, "linux_sudoers_d");
7256 assert_eq!(LINUX_SUDOERS_D.artifact_type, ArtifactType::Directory);
7257 assert_eq!(LINUX_SUDOERS_D.scope, DataScope::System);
7258 assert!(LINUX_SUDOERS_D.mitre_techniques.contains(&"T1548.003"));
7259 }
7260 #[test]
7261 fn linux_modules_load_d_md() {
7262 assert_eq!(LINUX_MODULES_LOAD_D.id, "linux_modules_load_d");
7263 assert_eq!(LINUX_MODULES_LOAD_D.artifact_type, ArtifactType::Directory);
7264 assert_eq!(LINUX_MODULES_LOAD_D.scope, DataScope::System);
7265 assert!(LINUX_MODULES_LOAD_D.mitre_techniques.contains(&"T1547.006"));
7266 }
7267 #[test]
7268 fn linux_motd_d_md() {
7269 assert_eq!(LINUX_MOTD_D.id, "linux_motd_d");
7270 assert_eq!(LINUX_MOTD_D.artifact_type, ArtifactType::Directory);
7271 assert_eq!(LINUX_MOTD_D.scope, DataScope::System);
7272 }
7273 #[test]
7274 fn linux_udev_rules_d_md() {
7275 assert_eq!(LINUX_UDEV_RULES_D.id, "linux_udev_rules_d");
7276 assert_eq!(LINUX_UDEV_RULES_D.artifact_type, ArtifactType::Directory);
7277 assert_eq!(LINUX_UDEV_RULES_D.scope, DataScope::System);
7278 assert!(LINUX_UDEV_RULES_D.mitre_techniques.contains(&"T1546"));
7279 }
7280
7281 #[test]
7284 fn linux_bash_history_md() {
7285 assert_eq!(LINUX_BASH_HISTORY.id, "linux_bash_history");
7286 assert_eq!(LINUX_BASH_HISTORY.artifact_type, ArtifactType::File);
7287 assert_eq!(LINUX_BASH_HISTORY.scope, DataScope::User);
7288 assert!(LINUX_BASH_HISTORY.mitre_techniques.contains(&"T1059.004"));
7289 }
7290 #[test]
7291 fn linux_zsh_history_md() {
7292 assert_eq!(LINUX_ZSH_HISTORY.id, "linux_zsh_history");
7293 assert_eq!(LINUX_ZSH_HISTORY.scope, DataScope::User);
7294 }
7295 #[test]
7296 fn linux_wtmp_md() {
7297 assert_eq!(LINUX_WTMP.id, "linux_wtmp");
7298 assert_eq!(LINUX_WTMP.artifact_type, ArtifactType::File);
7299 assert_eq!(LINUX_WTMP.scope, DataScope::System);
7300 assert!(LINUX_WTMP.mitre_techniques.contains(&"T1078"));
7301 }
7302 #[test]
7303 fn linux_btmp_md() {
7304 assert_eq!(LINUX_BTMP.id, "linux_btmp");
7305 assert_eq!(LINUX_BTMP.artifact_type, ArtifactType::File);
7306 assert_eq!(LINUX_BTMP.scope, DataScope::System);
7307 }
7308 #[test]
7309 fn linux_lastlog_md() {
7310 assert_eq!(LINUX_LASTLOG.id, "linux_lastlog");
7311 assert_eq!(LINUX_LASTLOG.artifact_type, ArtifactType::File);
7312 assert_eq!(LINUX_LASTLOG.scope, DataScope::System);
7313 }
7314 #[test]
7315 fn linux_auth_log_md() {
7316 assert_eq!(LINUX_AUTH_LOG.id, "linux_auth_log");
7317 assert_eq!(LINUX_AUTH_LOG.artifact_type, ArtifactType::File);
7318 assert_eq!(LINUX_AUTH_LOG.scope, DataScope::System);
7319 assert!(LINUX_AUTH_LOG.mitre_techniques.contains(&"T1078"));
7320 }
7321 #[test]
7322 fn linux_journal_dir_md() {
7323 assert_eq!(LINUX_JOURNAL_DIR.id, "linux_journal_dir");
7324 assert_eq!(LINUX_JOURNAL_DIR.artifact_type, ArtifactType::Directory);
7325 assert_eq!(LINUX_JOURNAL_DIR.os_scope, OsScope::LinuxSystemd);
7326 }
7327
7328 #[test]
7331 fn linux_passwd_md() {
7332 assert_eq!(LINUX_PASSWD.id, "linux_passwd");
7333 assert_eq!(LINUX_PASSWD.artifact_type, ArtifactType::File);
7334 assert_eq!(LINUX_PASSWD.scope, DataScope::System);
7335 assert!(LINUX_PASSWD.mitre_techniques.contains(&"T1087.001"));
7336 }
7337 #[test]
7338 fn linux_shadow_md() {
7339 assert_eq!(LINUX_SHADOW.id, "linux_shadow");
7340 assert_eq!(LINUX_SHADOW.artifact_type, ArtifactType::File);
7341 assert_eq!(LINUX_SHADOW.scope, DataScope::System);
7342 assert!(LINUX_SHADOW.mitre_techniques.contains(&"T1003.008"));
7343 }
7344 #[test]
7345 fn linux_ssh_private_key_md() {
7346 assert_eq!(LINUX_SSH_PRIVATE_KEY.id, "linux_ssh_private_key");
7347 assert_eq!(LINUX_SSH_PRIVATE_KEY.artifact_type, ArtifactType::File);
7348 assert_eq!(LINUX_SSH_PRIVATE_KEY.scope, DataScope::User);
7349 assert!(LINUX_SSH_PRIVATE_KEY
7350 .mitre_techniques
7351 .contains(&"T1552.004"));
7352 }
7353 #[test]
7354 fn linux_ssh_known_hosts_md() {
7355 assert_eq!(LINUX_SSH_KNOWN_HOSTS.id, "linux_ssh_known_hosts");
7356 assert_eq!(LINUX_SSH_KNOWN_HOSTS.scope, DataScope::User);
7357 assert!(LINUX_SSH_KNOWN_HOSTS
7358 .mitre_techniques
7359 .contains(&"T1021.004"));
7360 }
7361 #[test]
7362 fn linux_gnupg_private_md() {
7363 assert_eq!(LINUX_GNUPG_PRIVATE.id, "linux_gnupg_private");
7364 assert_eq!(LINUX_GNUPG_PRIVATE.artifact_type, ArtifactType::Directory);
7365 assert_eq!(LINUX_GNUPG_PRIVATE.scope, DataScope::User);
7366 assert!(LINUX_GNUPG_PRIVATE.mitre_techniques.contains(&"T1552.004"));
7367 }
7368 #[test]
7369 fn linux_aws_credentials_md() {
7370 assert_eq!(LINUX_AWS_CREDENTIALS.id, "linux_aws_credentials");
7371 assert_eq!(LINUX_AWS_CREDENTIALS.artifact_type, ArtifactType::File);
7372 assert_eq!(LINUX_AWS_CREDENTIALS.scope, DataScope::User);
7373 assert!(LINUX_AWS_CREDENTIALS
7374 .mitre_techniques
7375 .contains(&"T1552.001"));
7376 }
7377 #[test]
7378 fn linux_docker_config_md() {
7379 assert_eq!(LINUX_DOCKER_CONFIG.id, "linux_docker_config");
7380 assert_eq!(LINUX_DOCKER_CONFIG.artifact_type, ArtifactType::File);
7381 assert_eq!(LINUX_DOCKER_CONFIG.scope, DataScope::User);
7382 assert!(LINUX_DOCKER_CONFIG.mitre_techniques.contains(&"T1552.001"));
7383 }
7384
7385 #[test]
7388 fn catalog_contains_batch_d() {
7389 let ids: Vec<&str> = CATALOG.list().iter().map(|d| d.id).collect();
7390 for expected in &[
7391 "linux_crontab_system",
7392 "linux_cron_d",
7393 "linux_cron_periodic",
7394 "linux_user_crontab",
7395 "linux_anacrontab",
7396 "linux_systemd_system_unit",
7397 "linux_systemd_user_unit",
7398 "linux_systemd_timer",
7399 "linux_rc_local",
7400 "linux_init_d",
7401 "linux_bashrc_user",
7402 "linux_bash_profile_user",
7403 "linux_profile_user",
7404 "linux_zshrc_user",
7405 "linux_profile_system",
7406 "linux_profile_d",
7407 "linux_ld_so_preload",
7408 "linux_ld_so_conf_d",
7409 "linux_ssh_authorized_keys",
7410 "linux_pam_d",
7411 "linux_sudoers_d",
7412 "linux_modules_load_d",
7413 "linux_motd_d",
7414 "linux_udev_rules_d",
7415 "linux_bash_history",
7416 "linux_zsh_history",
7417 "linux_wtmp",
7418 "linux_btmp",
7419 "linux_lastlog",
7420 "linux_auth_log",
7421 "linux_journal_dir",
7422 "linux_passwd",
7423 "linux_shadow",
7424 "linux_ssh_private_key",
7425 "linux_ssh_known_hosts",
7426 "linux_gnupg_private",
7427 "linux_aws_credentials",
7428 "linux_docker_config",
7429 ] {
7430 assert!(ids.contains(expected), "CATALOG missing: {expected}");
7431 }
7432 }
7433
7434 #[test]
7441 fn lnk_files_md() {
7442 assert_eq!(LNK_FILES.id, "lnk_files");
7443 assert_eq!(LNK_FILES.artifact_type, ArtifactType::Directory);
7444 assert_eq!(LNK_FILES.scope, DataScope::User);
7445 assert!(LNK_FILES.mitre_techniques.contains(&"T1547.009"));
7446 }
7447 #[test]
7448 fn jump_list_auto_md() {
7449 assert_eq!(JUMP_LIST_AUTO.id, "jump_list_auto");
7450 assert_eq!(JUMP_LIST_AUTO.artifact_type, ArtifactType::Directory);
7451 assert_eq!(JUMP_LIST_AUTO.scope, DataScope::User);
7452 assert!(JUMP_LIST_AUTO.mitre_techniques.contains(&"T1547.009"));
7453 }
7454 #[test]
7455 fn jump_list_custom_md() {
7456 assert_eq!(JUMP_LIST_CUSTOM.id, "jump_list_custom");
7457 assert_eq!(JUMP_LIST_CUSTOM.artifact_type, ArtifactType::Directory);
7458 assert_eq!(JUMP_LIST_CUSTOM.scope, DataScope::User);
7459 assert!(JUMP_LIST_CUSTOM.mitre_techniques.contains(&"T1547.009"));
7460 }
7461 #[test]
7462 fn evtx_dir_md() {
7463 assert_eq!(EVTX_DIR.id, "evtx_dir");
7464 assert_eq!(EVTX_DIR.artifact_type, ArtifactType::Directory);
7465 assert_eq!(EVTX_DIR.scope, DataScope::System);
7466 assert!(EVTX_DIR.mitre_techniques.contains(&"T1070.001"));
7467 }
7468 #[test]
7469 fn usn_journal_md() {
7470 assert_eq!(USN_JOURNAL.id, "usn_journal");
7471 assert_eq!(USN_JOURNAL.artifact_type, ArtifactType::File);
7472 assert_eq!(USN_JOURNAL.scope, DataScope::System);
7473 assert_eq!(USN_JOURNAL.os_scope, OsScope::Win7Plus);
7474 }
7475
7476 #[test]
7479 fn wmi_mof_dir_md() {
7480 assert_eq!(WMI_MOF_DIR.id, "wmi_mof_dir");
7481 assert_eq!(WMI_MOF_DIR.artifact_type, ArtifactType::Directory);
7482 assert_eq!(WMI_MOF_DIR.scope, DataScope::System);
7483 assert!(WMI_MOF_DIR.mitre_techniques.contains(&"T1546.003"));
7484 }
7485 #[test]
7486 fn bits_db_md() {
7487 assert_eq!(BITS_DB.id, "bits_db");
7488 assert_eq!(BITS_DB.artifact_type, ArtifactType::Directory);
7489 assert_eq!(BITS_DB.scope, DataScope::System);
7490 assert!(BITS_DB.mitre_techniques.contains(&"T1197"));
7491 }
7492 #[test]
7493 fn wmi_subscriptions_md() {
7494 assert_eq!(WMI_SUBSCRIPTIONS.id, "wmi_subscriptions");
7495 assert_eq!(WMI_SUBSCRIPTIONS.artifact_type, ArtifactType::RegistryKey);
7496 assert_eq!(WMI_SUBSCRIPTIONS.scope, DataScope::System);
7497 assert!(WMI_SUBSCRIPTIONS.mitre_techniques.contains(&"T1546.003"));
7498 }
7499 #[test]
7500 fn logon_scripts_md() {
7501 assert_eq!(LOGON_SCRIPTS.id, "logon_scripts");
7502 assert_eq!(LOGON_SCRIPTS.artifact_type, ArtifactType::RegistryValue);
7503 assert_eq!(LOGON_SCRIPTS.scope, DataScope::User);
7504 assert!(LOGON_SCRIPTS.mitre_techniques.contains(&"T1037.001"));
7505 }
7506 #[test]
7507 fn winsock_lsp_md() {
7508 assert_eq!(WINSOCK_LSP.id, "winsock_lsp");
7509 assert_eq!(WINSOCK_LSP.artifact_type, ArtifactType::RegistryKey);
7510 assert_eq!(WINSOCK_LSP.scope, DataScope::System);
7511 assert!(WINSOCK_LSP.mitre_techniques.contains(&"T1547.010"));
7512 }
7513 #[test]
7514 fn appshim_db_md() {
7515 assert_eq!(APPSHIM_DB.id, "appshim_db");
7516 assert_eq!(APPSHIM_DB.artifact_type, ArtifactType::Directory);
7517 assert_eq!(APPSHIM_DB.scope, DataScope::System);
7518 assert!(APPSHIM_DB.mitre_techniques.contains(&"T1546.011"));
7519 }
7520 #[test]
7521 fn password_filter_dll_md() {
7522 assert_eq!(PASSWORD_FILTER_DLL.id, "password_filter_dll");
7523 assert_eq!(
7524 PASSWORD_FILTER_DLL.artifact_type,
7525 ArtifactType::RegistryValue
7526 );
7527 assert_eq!(PASSWORD_FILTER_DLL.scope, DataScope::System);
7528 assert!(PASSWORD_FILTER_DLL.mitre_techniques.contains(&"T1556.002"));
7529 }
7530 #[test]
7531 fn office_normal_dotm_md() {
7532 assert_eq!(OFFICE_NORMAL_DOTM.id, "office_normal_dotm");
7533 assert_eq!(OFFICE_NORMAL_DOTM.artifact_type, ArtifactType::File);
7534 assert_eq!(OFFICE_NORMAL_DOTM.scope, DataScope::User);
7535 assert!(OFFICE_NORMAL_DOTM.mitre_techniques.contains(&"T1137.001"));
7536 }
7537 #[test]
7538 fn powershell_profile_all_md() {
7539 assert_eq!(POWERSHELL_PROFILE_ALL.id, "powershell_profile_all");
7540 assert_eq!(POWERSHELL_PROFILE_ALL.artifact_type, ArtifactType::File);
7541 assert_eq!(POWERSHELL_PROFILE_ALL.scope, DataScope::System);
7542 assert!(POWERSHELL_PROFILE_ALL
7543 .mitre_techniques
7544 .contains(&"T1546.013"));
7545 }
7546
7547 #[test]
7550 fn dpapi_system_masterkey_md() {
7551 assert_eq!(DPAPI_SYSTEM_MASTERKEY.id, "dpapi_system_masterkey");
7552 assert_eq!(
7553 DPAPI_SYSTEM_MASTERKEY.artifact_type,
7554 ArtifactType::Directory
7555 );
7556 assert_eq!(DPAPI_SYSTEM_MASTERKEY.scope, DataScope::System);
7557 assert!(DPAPI_SYSTEM_MASTERKEY
7558 .mitre_techniques
7559 .contains(&"T1555.004"));
7560 }
7561 #[test]
7562 fn dpapi_credhist_md() {
7563 assert_eq!(DPAPI_CREDHIST.id, "dpapi_credhist");
7564 assert_eq!(DPAPI_CREDHIST.artifact_type, ArtifactType::File);
7565 assert_eq!(DPAPI_CREDHIST.scope, DataScope::User);
7566 assert!(DPAPI_CREDHIST.mitre_techniques.contains(&"T1555.004"));
7567 }
7568 #[test]
7569 fn chrome_cookies_md() {
7570 assert_eq!(CHROME_COOKIES.id, "chrome_cookies");
7571 assert_eq!(CHROME_COOKIES.artifact_type, ArtifactType::File);
7572 assert_eq!(CHROME_COOKIES.scope, DataScope::User);
7573 assert!(CHROME_COOKIES.mitre_techniques.contains(&"T1539"));
7574 }
7575 #[test]
7576 fn edge_webcache_md() {
7577 assert_eq!(EDGE_WEBCACHE.id, "edge_webcache");
7578 assert_eq!(EDGE_WEBCACHE.artifact_type, ArtifactType::Directory);
7579 assert_eq!(EDGE_WEBCACHE.scope, DataScope::User);
7580 assert!(EDGE_WEBCACHE.mitre_techniques.contains(&"T1539"));
7581 }
7582 #[test]
7583 fn vpn_ras_phonebook_md() {
7584 assert_eq!(VPN_RAS_PHONEBOOK.id, "vpn_ras_phonebook");
7585 assert_eq!(VPN_RAS_PHONEBOOK.artifact_type, ArtifactType::File);
7586 assert_eq!(VPN_RAS_PHONEBOOK.scope, DataScope::User);
7587 assert!(VPN_RAS_PHONEBOOK.mitre_techniques.contains(&"T1552.001"));
7588 }
7589 #[test]
7590 fn windows_hello_ngc_md() {
7591 assert_eq!(WINDOWS_HELLO_NGC.id, "windows_hello_ngc");
7592 assert_eq!(WINDOWS_HELLO_NGC.artifact_type, ArtifactType::Directory);
7593 assert_eq!(WINDOWS_HELLO_NGC.scope, DataScope::System);
7594 assert!(WINDOWS_HELLO_NGC.mitre_techniques.contains(&"T1555"));
7595 }
7596 #[test]
7597 fn user_cert_private_key_md() {
7598 assert_eq!(USER_CERT_PRIVATE_KEY.id, "user_cert_private_key");
7599 assert_eq!(USER_CERT_PRIVATE_KEY.artifact_type, ArtifactType::Directory);
7600 assert_eq!(USER_CERT_PRIVATE_KEY.scope, DataScope::User);
7601 assert!(USER_CERT_PRIVATE_KEY
7602 .mitre_techniques
7603 .contains(&"T1552.004"));
7604 }
7605 #[test]
7606 fn machine_cert_store_md() {
7607 assert_eq!(MACHINE_CERT_STORE.id, "machine_cert_store");
7608 assert_eq!(MACHINE_CERT_STORE.artifact_type, ArtifactType::Directory);
7609 assert_eq!(MACHINE_CERT_STORE.scope, DataScope::System);
7610 assert!(MACHINE_CERT_STORE.mitre_techniques.contains(&"T1552.004"));
7611 }
7612
7613 #[test]
7616 fn catalog_contains_batch_e() {
7617 let ids: Vec<&str> = CATALOG.list().iter().map(|d| d.id).collect();
7618 for expected in &[
7619 "lnk_files",
7620 "jump_list_auto",
7621 "jump_list_custom",
7622 "evtx_dir",
7623 "usn_journal",
7624 "wmi_mof_dir",
7625 "bits_db",
7626 "wmi_subscriptions",
7627 "logon_scripts",
7628 "winsock_lsp",
7629 "appshim_db",
7630 "password_filter_dll",
7631 "office_normal_dotm",
7632 "powershell_profile_all",
7633 "dpapi_system_masterkey",
7634 "dpapi_credhist",
7635 "chrome_cookies",
7636 "edge_webcache",
7637 "vpn_ras_phonebook",
7638 "windows_hello_ngc",
7639 "user_cert_private_key",
7640 "machine_cert_store",
7641 ] {
7642 assert!(ids.contains(expected), "CATALOG missing: {expected}");
7643 }
7644 }
7645
7646 #[test]
7651 fn linux_at_queue_md() {
7652 assert_eq!(LINUX_AT_QUEUE.id, "linux_at_queue");
7653 assert_eq!(LINUX_AT_QUEUE.artifact_type, ArtifactType::Directory);
7654 assert_eq!(LINUX_AT_QUEUE.scope, DataScope::System);
7655 assert!(LINUX_AT_QUEUE.mitre_techniques.contains(&"T1053.001"));
7656 }
7657 #[test]
7658 fn linux_sshd_config_md() {
7659 assert_eq!(LINUX_SSHD_CONFIG.id, "linux_sshd_config");
7660 assert_eq!(LINUX_SSHD_CONFIG.artifact_type, ArtifactType::File);
7661 assert_eq!(LINUX_SSHD_CONFIG.scope, DataScope::System);
7662 assert!(LINUX_SSHD_CONFIG.mitre_techniques.contains(&"T1098.004"));
7663 }
7664 #[test]
7665 fn linux_etc_group_md() {
7666 assert_eq!(LINUX_ETC_GROUP.id, "linux_etc_group");
7667 assert_eq!(LINUX_ETC_GROUP.artifact_type, ArtifactType::File);
7668 assert_eq!(LINUX_ETC_GROUP.scope, DataScope::System);
7669 assert!(LINUX_ETC_GROUP.mitre_techniques.contains(&"T1087.001"));
7670 }
7671 #[test]
7672 fn linux_gnome_keyring_md() {
7673 assert_eq!(LINUX_GNOME_KEYRING.id, "linux_gnome_keyring");
7674 assert_eq!(LINUX_GNOME_KEYRING.artifact_type, ArtifactType::Directory);
7675 assert_eq!(LINUX_GNOME_KEYRING.scope, DataScope::User);
7676 assert!(LINUX_GNOME_KEYRING.mitre_techniques.contains(&"T1555.003"));
7677 }
7678 #[test]
7679 fn linux_kde_kwallet_md() {
7680 assert_eq!(LINUX_KDE_KWALLET.id, "linux_kde_kwallet");
7681 assert_eq!(LINUX_KDE_KWALLET.artifact_type, ArtifactType::Directory);
7682 assert_eq!(LINUX_KDE_KWALLET.scope, DataScope::User);
7683 assert!(LINUX_KDE_KWALLET.mitre_techniques.contains(&"T1555.003"));
7684 }
7685 #[test]
7686 fn linux_chrome_login_linux_md() {
7687 assert_eq!(LINUX_CHROME_LOGIN_LINUX.id, "linux_chrome_login_linux");
7688 assert_eq!(LINUX_CHROME_LOGIN_LINUX.artifact_type, ArtifactType::File);
7689 assert_eq!(LINUX_CHROME_LOGIN_LINUX.scope, DataScope::User);
7690 assert!(LINUX_CHROME_LOGIN_LINUX
7691 .mitre_techniques
7692 .contains(&"T1555.003"));
7693 }
7694 #[test]
7695 fn linux_firefox_logins_linux_md() {
7696 assert_eq!(LINUX_FIREFOX_LOGINS_LINUX.id, "linux_firefox_logins_linux");
7697 assert_eq!(LINUX_FIREFOX_LOGINS_LINUX.artifact_type, ArtifactType::File);
7698 assert_eq!(LINUX_FIREFOX_LOGINS_LINUX.scope, DataScope::User);
7699 assert!(LINUX_FIREFOX_LOGINS_LINUX
7700 .mitre_techniques
7701 .contains(&"T1555.003"));
7702 }
7703 #[test]
7704 fn linux_utmp_md() {
7705 assert_eq!(LINUX_UTMP.id, "linux_utmp");
7706 assert_eq!(LINUX_UTMP.artifact_type, ArtifactType::File);
7707 assert_eq!(LINUX_UTMP.scope, DataScope::System);
7708 assert!(LINUX_UTMP.mitre_techniques.contains(&"T1078"));
7709 }
7710 #[test]
7711 fn linux_gcp_credentials_md() {
7712 assert_eq!(LINUX_GCP_CREDENTIALS.id, "linux_gcp_credentials");
7713 assert_eq!(LINUX_GCP_CREDENTIALS.artifact_type, ArtifactType::Directory);
7714 assert_eq!(LINUX_GCP_CREDENTIALS.scope, DataScope::User);
7715 assert!(LINUX_GCP_CREDENTIALS
7716 .mitre_techniques
7717 .contains(&"T1552.001"));
7718 }
7719 #[test]
7720 fn linux_azure_credentials_md() {
7721 assert_eq!(LINUX_AZURE_CREDENTIALS.id, "linux_azure_credentials");
7722 assert_eq!(
7723 LINUX_AZURE_CREDENTIALS.artifact_type,
7724 ArtifactType::Directory
7725 );
7726 assert_eq!(LINUX_AZURE_CREDENTIALS.scope, DataScope::User);
7727 assert!(LINUX_AZURE_CREDENTIALS
7728 .mitre_techniques
7729 .contains(&"T1552.001"));
7730 }
7731 #[test]
7732 fn linux_kube_config_md() {
7733 assert_eq!(LINUX_KUBE_CONFIG.id, "linux_kube_config");
7734 assert_eq!(LINUX_KUBE_CONFIG.artifact_type, ArtifactType::File);
7735 assert_eq!(LINUX_KUBE_CONFIG.scope, DataScope::User);
7736 assert!(LINUX_KUBE_CONFIG.mitre_techniques.contains(&"T1552.001"));
7737 }
7738 #[test]
7739 fn linux_git_credentials_md() {
7740 assert_eq!(LINUX_GIT_CREDENTIALS.id, "linux_git_credentials");
7741 assert_eq!(LINUX_GIT_CREDENTIALS.artifact_type, ArtifactType::File);
7742 assert_eq!(LINUX_GIT_CREDENTIALS.scope, DataScope::User);
7743 assert!(LINUX_GIT_CREDENTIALS
7744 .mitre_techniques
7745 .contains(&"T1552.001"));
7746 }
7747 #[test]
7748 fn linux_netrc_md() {
7749 assert_eq!(LINUX_NETRC.id, "linux_netrc");
7750 assert_eq!(LINUX_NETRC.artifact_type, ArtifactType::File);
7751 assert_eq!(LINUX_NETRC.scope, DataScope::User);
7752 assert!(LINUX_NETRC.mitre_techniques.contains(&"T1552.001"));
7753 }
7754
7755 #[test]
7758 fn catalog_contains_batch_f() {
7759 let ids: Vec<&str> = CATALOG.list().iter().map(|d| d.id).collect();
7760 for expected in &[
7761 "linux_at_queue",
7762 "linux_sshd_config",
7763 "linux_etc_group",
7764 "linux_gnome_keyring",
7765 "linux_kde_kwallet",
7766 "linux_chrome_login_linux",
7767 "linux_firefox_logins_linux",
7768 "linux_utmp",
7769 "linux_gcp_credentials",
7770 "linux_azure_credentials",
7771 "linux_kube_config",
7772 "linux_git_credentials",
7773 "linux_netrc",
7774 ] {
7775 assert!(ids.contains(expected), "CATALOG missing: {expected}");
7776 }
7777 }
7778
7779 #[test]
7785 fn linux_etc_environment_md() {
7786 assert_eq!(LINUX_ETC_ENVIRONMENT.id, "linux_etc_environment");
7787 assert_eq!(LINUX_ETC_ENVIRONMENT.artifact_type, ArtifactType::File);
7788 assert_eq!(LINUX_ETC_ENVIRONMENT.scope, DataScope::System);
7789 assert!(LINUX_ETC_ENVIRONMENT
7790 .mitre_techniques
7791 .contains(&"T1546.004"));
7792 }
7793 #[test]
7794 fn linux_xdg_autostart_user_md() {
7795 assert_eq!(LINUX_XDG_AUTOSTART_USER.id, "linux_xdg_autostart_user");
7796 assert_eq!(
7797 LINUX_XDG_AUTOSTART_USER.artifact_type,
7798 ArtifactType::Directory
7799 );
7800 assert_eq!(LINUX_XDG_AUTOSTART_USER.scope, DataScope::User);
7801 assert!(LINUX_XDG_AUTOSTART_USER
7802 .mitre_techniques
7803 .contains(&"T1547.014"));
7804 }
7805 #[test]
7806 fn linux_xdg_autostart_system_md() {
7807 assert_eq!(LINUX_XDG_AUTOSTART_SYSTEM.id, "linux_xdg_autostart_system");
7808 assert_eq!(
7809 LINUX_XDG_AUTOSTART_SYSTEM.artifact_type,
7810 ArtifactType::Directory
7811 );
7812 assert_eq!(LINUX_XDG_AUTOSTART_SYSTEM.scope, DataScope::System);
7813 assert!(LINUX_XDG_AUTOSTART_SYSTEM
7814 .mitre_techniques
7815 .contains(&"T1547.014"));
7816 }
7817 #[test]
7818 fn linux_networkmanager_dispatcher_md() {
7819 assert_eq!(
7820 LINUX_NETWORKMANAGER_DISPATCHER.id,
7821 "linux_networkmanager_dispatcher"
7822 );
7823 assert_eq!(
7824 LINUX_NETWORKMANAGER_DISPATCHER.artifact_type,
7825 ArtifactType::Directory
7826 );
7827 assert_eq!(LINUX_NETWORKMANAGER_DISPATCHER.scope, DataScope::System);
7828 assert!(LINUX_NETWORKMANAGER_DISPATCHER
7829 .mitre_techniques
7830 .contains(&"T1547.013"));
7831 }
7832 #[test]
7833 fn linux_apt_hooks_md() {
7834 assert_eq!(LINUX_APT_HOOKS.id, "linux_apt_hooks");
7835 assert_eq!(LINUX_APT_HOOKS.artifact_type, ArtifactType::Directory);
7836 assert_eq!(LINUX_APT_HOOKS.scope, DataScope::System);
7837 assert_eq!(LINUX_APT_HOOKS.os_scope, OsScope::LinuxDebian);
7838 assert!(LINUX_APT_HOOKS.mitre_techniques.contains(&"T1546.004"));
7839 }
7840
7841 #[test]
7844 fn catalog_contains_batch_g() {
7845 let ids: Vec<&str> = CATALOG.list().iter().map(|d| d.id).collect();
7846 for expected in &[
7847 "linux_etc_environment",
7848 "linux_xdg_autostart_user",
7849 "linux_xdg_autostart_system",
7850 "linux_networkmanager_dispatcher",
7851 "linux_apt_hooks",
7852 ] {
7853 assert!(ids.contains(expected), "CATALOG missing: {expected}");
7854 }
7855 }
7856
7857 #[test]
7864 fn jump_list_system_md() {
7865 assert_eq!(JUMP_LIST_SYSTEM.id, "jump_list_system");
7866 assert_eq!(JUMP_LIST_SYSTEM.artifact_type, ArtifactType::Directory);
7867 assert_eq!(JUMP_LIST_SYSTEM.scope, DataScope::System);
7868 assert!(JUMP_LIST_SYSTEM.mitre_techniques.contains(&"T1547.009"));
7869 }
7870
7871 #[test]
7874 fn lnk_files_office_md() {
7875 assert_eq!(LNK_FILES_OFFICE.id, "lnk_files_office");
7876 assert_eq!(LNK_FILES_OFFICE.artifact_type, ArtifactType::Directory);
7877 assert_eq!(LNK_FILES_OFFICE.scope, DataScope::User);
7878 assert!(LNK_FILES_OFFICE.mitre_techniques.contains(&"T1547.009"));
7879 }
7880
7881 #[test]
7884 fn prefetch_file_md() {
7885 assert_eq!(PREFETCH_FILE.id, "prefetch_file");
7886 assert_eq!(PREFETCH_FILE.artifact_type, ArtifactType::File);
7887 assert_eq!(PREFETCH_FILE.scope, DataScope::System);
7888 assert_eq!(PREFETCH_FILE.os_scope, OsScope::Win7Plus);
7889 assert!(PREFETCH_FILE.mitre_techniques.contains(&"T1059"));
7890 }
7891
7892 #[test]
7895 fn srum_network_usage_md() {
7896 assert_eq!(SRUM_NETWORK_USAGE.id, "srum_network_usage");
7897 assert_eq!(SRUM_NETWORK_USAGE.artifact_type, ArtifactType::File);
7898 assert_eq!(SRUM_NETWORK_USAGE.scope, DataScope::System);
7899 assert_eq!(SRUM_NETWORK_USAGE.os_scope, OsScope::Win8Plus);
7900 assert!(SRUM_NETWORK_USAGE.mitre_techniques.contains(&"T1049"));
7901 }
7902 #[test]
7903 fn srum_app_resource_md() {
7904 assert_eq!(SRUM_APP_RESOURCE.id, "srum_app_resource");
7905 assert_eq!(SRUM_APP_RESOURCE.artifact_type, ArtifactType::File);
7906 assert_eq!(SRUM_APP_RESOURCE.scope, DataScope::System);
7907 assert_eq!(SRUM_APP_RESOURCE.os_scope, OsScope::Win8Plus);
7908 assert!(SRUM_APP_RESOURCE.mitre_techniques.contains(&"T1059"));
7909 }
7910 #[test]
7911 fn srum_energy_usage_md() {
7912 assert_eq!(SRUM_ENERGY_USAGE.id, "srum_energy_usage");
7913 assert_eq!(SRUM_ENERGY_USAGE.artifact_type, ArtifactType::File);
7914 assert_eq!(SRUM_ENERGY_USAGE.scope, DataScope::System);
7915 assert_eq!(SRUM_ENERGY_USAGE.os_scope, OsScope::Win8Plus);
7916 assert!(SRUM_ENERGY_USAGE.mitre_techniques.contains(&"T1059"));
7917 }
7918 #[test]
7919 fn srum_push_notification_md() {
7920 assert_eq!(SRUM_PUSH_NOTIFICATION.id, "srum_push_notification");
7921 assert_eq!(SRUM_PUSH_NOTIFICATION.artifact_type, ArtifactType::File);
7922 assert_eq!(SRUM_PUSH_NOTIFICATION.scope, DataScope::System);
7923 assert_eq!(SRUM_PUSH_NOTIFICATION.os_scope, OsScope::Win10Plus);
7924 assert!(SRUM_PUSH_NOTIFICATION.mitre_techniques.contains(&"T1059"));
7925 }
7926
7927 #[test]
7930 fn evtx_security_md() {
7931 assert_eq!(EVTX_SECURITY.id, "evtx_security");
7932 assert_eq!(EVTX_SECURITY.artifact_type, ArtifactType::File);
7933 assert_eq!(EVTX_SECURITY.scope, DataScope::System);
7934 assert!(EVTX_SECURITY.mitre_techniques.contains(&"T1070.001"));
7935 }
7936 #[test]
7937 fn evtx_system_md() {
7938 assert_eq!(EVTX_SYSTEM.id, "evtx_system");
7939 assert_eq!(EVTX_SYSTEM.artifact_type, ArtifactType::File);
7940 assert_eq!(EVTX_SYSTEM.scope, DataScope::System);
7941 assert!(EVTX_SYSTEM.mitre_techniques.contains(&"T1543.003"));
7942 }
7943 #[test]
7944 fn evtx_powershell_md() {
7945 assert_eq!(EVTX_POWERSHELL.id, "evtx_powershell");
7946 assert_eq!(EVTX_POWERSHELL.artifact_type, ArtifactType::File);
7947 assert_eq!(EVTX_POWERSHELL.scope, DataScope::System);
7948 assert!(EVTX_POWERSHELL.mitre_techniques.contains(&"T1059.001"));
7949 }
7950 #[test]
7951 fn evtx_sysmon_md() {
7952 assert_eq!(EVTX_SYSMON.id, "evtx_sysmon");
7953 assert_eq!(EVTX_SYSMON.artifact_type, ArtifactType::File);
7954 assert_eq!(EVTX_SYSMON.scope, DataScope::System);
7955 assert!(EVTX_SYSMON.mitre_techniques.contains(&"T1059"));
7956 }
7957
7958 #[test]
7965 fn triage_priority_ordering() {
7966 assert!(TriagePriority::Critical > TriagePriority::High);
7967 assert!(TriagePriority::High > TriagePriority::Medium);
7968 assert!(TriagePriority::Medium > TriagePriority::Low);
7969 }
7970
7971 #[test]
7974 fn descriptor_has_retention_field() {
7975 assert_eq!(RUN_KEY_HKLM_RUN.retention, None);
7977 }
7978
7979 #[test]
7980 fn descriptor_has_triage_priority_field() {
7981 assert_eq!(RUN_KEY_HKLM_RUN.triage_priority, TriagePriority::High);
7982 }
7983
7984 #[test]
7985 fn descriptor_has_related_artifacts_field() {
7986 let _ = RUN_KEY_HKLM_RUN.related_artifacts;
7987 }
7988
7989 #[test]
7992 fn srum_retention_is_30_days() {
7993 assert_eq!(SRUM_DB.retention, Some("~30 days"));
7994 }
7995
7996 #[test]
7997 fn shimcache_retention_mentions_shutdown() {
7998 assert!(SHIMCACHE.retention.unwrap_or("").contains("shutdown"));
7999 }
8000
8001 #[test]
8002 fn powershell_history_retention_mentions_limit() {
8003 assert!(POWERSHELL_HISTORY.retention.unwrap_or("").contains("4096"));
8004 }
8005
8006 #[test]
8007 fn bam_user_retention_is_7_days() {
8008 assert!(BAM_USER.retention.unwrap_or("").contains("7 day"));
8009 }
8010
8011 #[test]
8012 fn evtx_security_retention_mentions_rolling() {
8013 assert!(EVTX_SECURITY.retention.unwrap_or("").contains("rolling"));
8014 }
8015
8016 #[test]
8019 fn evtx_security_triage_is_critical() {
8020 assert_eq!(EVTX_SECURITY.triage_priority, TriagePriority::Critical);
8021 }
8022
8023 #[test]
8024 fn sam_users_triage_is_critical() {
8025 assert_eq!(SAM_USERS.triage_priority, TriagePriority::Critical);
8026 }
8027
8028 #[test]
8029 fn lsa_secrets_triage_is_critical() {
8030 assert_eq!(LSA_SECRETS.triage_priority, TriagePriority::Critical);
8031 }
8032
8033 #[test]
8034 fn linux_shadow_triage_is_critical() {
8035 assert_eq!(LINUX_SHADOW.triage_priority, TriagePriority::Critical);
8036 }
8037
8038 #[test]
8039 fn shimcache_triage_is_critical() {
8040 assert_eq!(SHIMCACHE.triage_priority, TriagePriority::Critical);
8041 }
8042
8043 #[test]
8044 fn userassist_exe_triage_is_high() {
8045 assert_eq!(USERASSIST_EXE.triage_priority, TriagePriority::High);
8046 }
8047
8048 #[test]
8049 fn thumbcache_triage_is_medium() {
8050 assert_eq!(THUMBCACHE.triage_priority, TriagePriority::Medium);
8051 }
8052
8053 #[test]
8054 fn vpn_ras_phonebook_triage_is_low() {
8055 assert_eq!(VPN_RAS_PHONEBOOK.triage_priority, TriagePriority::Low);
8056 }
8057
8058 #[test]
8061 fn srum_network_related_includes_evtx_security() {
8062 assert!(SRUM_NETWORK_USAGE
8063 .related_artifacts
8064 .contains(&"evtx_security"));
8065 }
8066
8067 #[test]
8068 fn evtx_security_related_includes_srum() {
8069 assert!(EVTX_SECURITY
8070 .related_artifacts
8071 .contains(&"srum_network_usage"));
8072 }
8073
8074 #[test]
8075 fn prefetch_file_related_includes_shimcache() {
8076 assert!(PREFETCH_FILE.related_artifacts.contains(&"shimcache"));
8077 }
8078
8079 #[test]
8080 fn dpapi_masterkey_related_includes_dpapi_cred() {
8081 assert!(DPAPI_MASTERKEY_USER
8082 .related_artifacts
8083 .contains(&"dpapi_cred_user"));
8084 }
8085
8086 #[test]
8089 fn catalog_by_mitre_finds_srum_network_usage() {
8090 let hits = CATALOG.by_mitre("T1049");
8091 assert!(hits.iter().any(|d| d.id == "srum_network_usage"));
8092 }
8093
8094 #[test]
8095 fn catalog_by_mitre_finds_no_results_for_unknown() {
8096 assert!(CATALOG.by_mitre("T9999.999").is_empty());
8097 }
8098
8099 #[test]
8100 fn catalog_for_triage_nonempty_and_critical_first() {
8101 let hits = CATALOG.for_triage();
8102 assert!(!hits.is_empty());
8103 assert_eq!(hits[0].triage_priority, TriagePriority::Critical);
8104 assert!(hits.last().unwrap().triage_priority <= TriagePriority::Medium);
8106 }
8107
8108 #[test]
8109 fn catalog_for_triage_stable_within_priority() {
8110 let hits = CATALOG.for_triage();
8112 let mut max_seen = TriagePriority::Critical;
8113 for d in &hits {
8114 assert!(d.triage_priority <= max_seen, "priority not monotone");
8115 max_seen = d.triage_priority;
8116 }
8117 }
8118
8119 #[test]
8120 fn catalog_filter_by_keyword_finds_dpapi() {
8121 let hits = CATALOG.filter_by_keyword("DPAPI");
8122 assert!(!hits.is_empty());
8123 assert!(hits.iter().any(|d| d.id.contains("dpapi")));
8124 }
8125
8126 #[test]
8127 fn catalog_filter_by_keyword_case_insensitive() {
8128 let lower = CATALOG.filter_by_keyword("dpapi");
8129 let upper = CATALOG.filter_by_keyword("DPAPI");
8130 assert_eq!(lower.len(), upper.len());
8131 }
8132
8133 #[test]
8140 fn userassist_has_authoritative_sources() {
8141 assert!(
8142 !USERASSIST_EXE.sources.is_empty(),
8143 "USERASSIST_EXE must cite at least one authoritative source"
8144 );
8145 }
8146
8147 #[test]
8148 fn run_key_hklm_has_authoritative_sources() {
8149 assert!(
8150 !RUN_KEY_HKLM_RUN.sources.is_empty(),
8151 "RUN_KEY_HKLM_RUN must cite at least one authoritative source"
8152 );
8153 }
8154
8155 #[test]
8156 fn shimcache_has_authoritative_sources() {
8157 assert!(
8158 !SHIMCACHE.sources.is_empty(),
8159 "SHIMCACHE must cite at least one authoritative source"
8160 );
8161 }
8162
8163 #[test]
8164 fn prefetch_dir_has_authoritative_sources() {
8165 assert!(
8166 !PREFETCH_DIR.sources.is_empty(),
8167 "PREFETCH_DIR must cite at least one authoritative source"
8168 );
8169 }
8170
8171 #[test]
8172 fn amcache_has_authoritative_sources() {
8173 assert!(
8174 !AMCACHE_APP_FILE.sources.is_empty(),
8175 "AMCACHE_APP_FILE must cite at least one authoritative source"
8176 );
8177 }
8178
8179 #[test]
8180 fn evtx_security_has_authoritative_sources() {
8181 assert!(
8182 !EVTX_SECURITY.sources.is_empty(),
8183 "EVTX_SECURITY must cite at least one authoritative source"
8184 );
8185 }
8186
8187 #[test]
8188 fn srum_app_resource_has_authoritative_sources() {
8189 assert!(
8190 !SRUM_APP_RESOURCE.sources.is_empty(),
8191 "SRUM_APP_RESOURCE must cite at least one authoritative source"
8192 );
8193 }
8194
8195 #[test]
8196 fn sam_users_has_authoritative_sources() {
8197 assert!(
8198 !SAM_USERS.sources.is_empty(),
8199 "SAM_USERS must cite at least one authoritative source"
8200 );
8201 }
8202
8203 #[test]
8204 fn shellbags_has_authoritative_sources() {
8205 assert!(
8206 !SHELLBAGS_USER.sources.is_empty(),
8207 "SHELLBAGS_USER must cite at least one authoritative source"
8208 );
8209 }
8210
8211 #[test]
8212 fn no_descriptor_in_catalog_has_empty_sources() {
8213 let empty: Vec<&str> = CATALOG
8214 .list()
8215 .iter()
8216 .filter(|d| d.sources.is_empty())
8217 .map(|d| d.id)
8218 .collect();
8219 assert!(
8220 empty.is_empty(),
8221 "These catalog entries have no authoritative sources: {empty:?}"
8222 );
8223 }
8224
8225 #[test]
8226 fn catalog_contains_batch_h() {
8227 let ids: Vec<&str> = CATALOG.list().iter().map(|d| d.id).collect();
8228 for expected in &[
8229 "jump_list_system",
8230 "lnk_files_office",
8231 "prefetch_file",
8232 "srum_network_usage",
8233 "srum_app_resource",
8234 "srum_energy_usage",
8235 "srum_push_notification",
8236 "evtx_security",
8237 "evtx_system",
8238 "evtx_powershell",
8239 "evtx_sysmon",
8240 ] {
8241 assert!(ids.contains(expected), "CATALOG missing: {expected}");
8242 }
8243 }
8244}