forensicnomicon 0.2.1

The ForensicNomicon — comprehensive DFIR artifact catalog: UserAssist, Shimcache, Amcache, Prefetch, $MFT, ShellBags, EVTX, NTDS.dit, SAM, SRUM, LNK, Jump Lists + KAPE/Velociraptor/Sigma/MITRE. Zero deps.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
//! Extended Linux artifact descriptors.
//!
//! Sources: Velociraptor Linux artifacts, ForensicArtifacts/artifacts (linux.yaml),
//! SANS FOR508, auditd documentation, Docker/container forensics resources.

#![allow(clippy::too_many_lines)]

use super::super::types::{
    ArtifactDescriptor, ArtifactType, DataScope, Decoder, FieldSchema, OsScope, TriagePriority,
    ValueType,
};

pub(crate) static LINUX_AUDITD_LOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_auditd_log",
    name: "Auditd Log",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/var/log/audit/audit.log"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Linux Audit daemon log recording syscall-level events: file access, process execution (execve), privilege escalation, network connections, and authentication. The highest-fidelity forensic source on Linux when configured — provides a comprehensive record equivalent to Sysmon on Windows.",
    mitre_techniques: &["T1562.001", "T1059", "T1078"],
    fields: &[
        FieldSchema { name: "type", value_type: ValueType::Text, description: "Audit record type (SYSCALL, EXECVE, etc.)", is_uid_component: true },
        FieldSchema { name: "pid", value_type: ValueType::UnsignedInt, description: "Process ID", is_uid_component: false },
        FieldSchema { name: "comm", value_type: ValueType::Text, description: "Command name", is_uid_component: false },
        FieldSchema { name: "exe", value_type: ValueType::Text, description: "Executable path", is_uid_component: false },
    ],
    retention: Some("Rotated by logrotate; retain_num and max_log_file configurable"),
    triage_priority: TriagePriority::Critical,
    related_artifacts: &["linux_auth_log", "linux_syslog"],
    sources: &[
        "https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/chap-system_auditing",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Definitive),
    evidence_caveats: &["Kernel-level syscall auditing; attacker must disable auditd to evade"],
    volatility: Some(crate::volatility::VolatilityClass::RotatingBuffer),
    volatility_rationale: "Log file; rotated by logrotate",
};

pub(crate) static LINUX_AUDIT_RULES: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_audit_rules",
    name: "Auditd Rules Configuration",
    artifact_type: ArtifactType::Directory,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/etc/audit/rules.d/"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Active auditd ruleset defining what syscalls and file accesses are monitored. Reviewing rules reveals coverage gaps and attacker-planted rule deletions that silently disable monitoring of specific activity.",
    mitre_techniques: &["T1562.001"],
    fields: &[FieldSchema { name: "rule", value_type: ValueType::Text, description: "Audit rule definition", is_uid_component: true }],
    retention: Some("Persistent configuration"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_auditd_log"],
    sources: &["https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/chap-system_auditing"],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &["Empty/missing rules indicate auditd not configured, not necessarily attacker tampering"],
    volatility: Some(crate::volatility::VolatilityClass::Persistent),
    volatility_rationale: "Configuration files persist until explicit modification",
};

pub(crate) static LINUX_SYSLOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_syslog",
    name: "Syslog",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/var/log/syslog"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Main system log on Debian/Ubuntu aggregating messages from most daemons (cron, NetworkManager, rsyslogd, kernel, etc.). Broad-spectrum timeline reconstruction source — often the first log checked in Linux IR.",
    mitre_techniques: &["T1562.002"],
    fields: &[
        FieldSchema { name: "facility", value_type: ValueType::Text, description: "Syslog facility (auth, kern, daemon, etc.)", is_uid_component: false },
        FieldSchema { name: "message", value_type: ValueType::Text, description: "Log message body", is_uid_component: true },
    ],
    retention: Some("Rotated weekly; 4 rotations kept by default"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_auth_log", "linux_journal_dir"],
    sources: &["https://www.sans.org/blog/linux-forensics-from-basic-to-in-depth-evidence-collection/"],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &[
        "Easily cleared/modified by root attackers",
        "logrotate compresses and eventually deletes old entries",
    ],
    volatility: Some(crate::volatility::VolatilityClass::RotatingBuffer),
    volatility_rationale: "Syslog file rotated daily/weekly by logrotate",
};

pub(crate) static LINUX_MESSAGES_LOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_messages_log",
    name: "Messages Log (RHEL/CentOS)",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/var/log/messages"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Main system log on RHEL/CentOS/Fedora (equivalent to /var/log/syslog on Debian). Contains daemon messages, hardware events, and network activity. Primary starting point for Linux IR on Red Hat-family systems.",
    mitre_techniques: &["T1562.002"],
    fields: &[FieldSchema { name: "message", value_type: ValueType::Text, description: "Log message body", is_uid_component: true }],
    retention: Some("Rotated; 4 rotations kept"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_secure_log", "linux_journal_dir"],
    sources: &["https://www.sans.org/blog/linux-forensics-from-basic-to-in-depth-evidence-collection/"],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &[
        "Easily cleared/modified by root attackers",
        "logrotate compresses and eventually deletes old entries",
    ],
    volatility: Some(crate::volatility::VolatilityClass::RotatingBuffer),
    volatility_rationale: "Messages log rotated by logrotate with bounded retention",
};

pub(crate) static LINUX_SECURE_LOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_secure_log",
    name: "Secure Log (RHEL/CentOS authentication)",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/var/log/secure"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Authentication and authorization log on RHEL/CentOS/Fedora (equivalent to auth.log on Debian). Contains su, sudo, sshd, and PAM events. Primary source for privilege escalation and lateral movement analysis on Red Hat-family systems.",
    mitre_techniques: &["T1078", "T1110", "T1021.004"],
    fields: &[
        FieldSchema { name: "process", value_type: ValueType::Text, description: "Process generating the auth event", is_uid_component: true },
        FieldSchema { name: "message", value_type: ValueType::Text, description: "Authentication event message", is_uid_component: false },
    ],
    retention: Some("Rotated; 4 rotations kept"),
    triage_priority: TriagePriority::Critical,
    related_artifacts: &["linux_auditd_log", "linux_journal_dir"],
    sources: &["https://www.sans.org/blog/linux-forensics-from-basic-to-in-depth-evidence-collection/"],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &["Authentication events; quality depends on PAM configuration"],
    volatility: Some(crate::volatility::VolatilityClass::RotatingBuffer),
    volatility_rationale: "Log file; rotated by logrotate",
};

pub(crate) static LINUX_APACHE_ACCESS_LOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_apache_access_log",
    name: "Apache HTTP Server Access Log",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/var/log/apache2/access.log"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Apache access log recording client IP, request method, URI, response code, and user-agent. Critical for web attack investigation: SQL injection, LFI/RFI, webshell access, C2 beaconing, and data exfiltration via HTTP.",
    mitre_techniques: &["T1190", "T1505.003", "T1071.001"],
    fields: &[
        FieldSchema { name: "client_ip", value_type: ValueType::Text, description: "Client IP address", is_uid_component: true },
        FieldSchema { name: "request", value_type: ValueType::Text, description: "HTTP method + URI + protocol", is_uid_component: false },
        FieldSchema { name: "status_code", value_type: ValueType::UnsignedInt, description: "HTTP response status code", is_uid_component: false },
        FieldSchema { name: "user_agent", value_type: ValueType::Text, description: "Client User-Agent header", is_uid_component: false },
    ],
    retention: Some("Rotated weekly; configurable"),
    triage_priority: TriagePriority::Critical,
    related_artifacts: &["linux_nginx_access_log"],
    sources: &[
        "https://www.sans.org/blog/web-server-log-analysis-for-incident-responders/",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Definitive),
    evidence_caveats: &["Web exploitation primary source; attacker may delete or tamper"],
    volatility: Some(crate::volatility::VolatilityClass::RotatingBuffer),
    volatility_rationale: "Log file; rotated by logrotate",
};

pub(crate) static LINUX_APACHE_ERROR_LOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_apache_error_log",
    name: "Apache HTTP Server Error Log",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/var/log/apache2/error.log"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Apache error log showing server-side errors, mod_security alerts, and failed request details. Reveals exploitation attempts that generate server-side exceptions — stack traces may expose vulnerable code paths.",
    mitre_techniques: &["T1190"],
    fields: &[FieldSchema { name: "error_message", value_type: ValueType::Text, description: "Error message and stack trace", is_uid_component: true }],
    retention: Some("Rotated weekly"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_apache_access_log"],
    sources: &[
        "https://www.sans.org/blog/web-server-log-analysis-for-incident-responders/",
        "https://httpd.apache.org/docs/current/logs.html",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &["Routine application errors generate noise — exploit indicators require pattern matching"],
    volatility: Some(crate::volatility::VolatilityClass::RotatingBuffer),
    volatility_rationale: "Apache error log rotated by logrotate",
};

pub(crate) static LINUX_NGINX_ACCESS_LOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_nginx_access_log",
    name: "Nginx Access Log",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/var/log/nginx/access.log"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Nginx web server access log. Same forensic value as Apache access log; critical for reverse proxy and web application attack investigation. Also covers nginx acting as API gateway or load balancer for containerized apps.",
    mitre_techniques: &["T1190", "T1505.003", "T1071.001"],
    fields: &[
        FieldSchema { name: "client_ip", value_type: ValueType::Text, description: "Client IP address", is_uid_component: true },
        FieldSchema { name: "request", value_type: ValueType::Text, description: "HTTP request line", is_uid_component: false },
        FieldSchema { name: "status_code", value_type: ValueType::UnsignedInt, description: "HTTP response status code", is_uid_component: false },
    ],
    retention: Some("Rotated; configurable"),
    triage_priority: TriagePriority::Critical,
    related_artifacts: &["linux_apache_access_log"],
    sources: &[
        "https://www.sans.org/blog/web-server-log-analysis-for-incident-responders/",
        "https://nginx.org/en/docs/http/ngx_http_log_module.html",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Definitive),
    evidence_caveats: &["Web exploitation primary source; attacker may delete or tamper"],
    volatility: Some(crate::volatility::VolatilityClass::RotatingBuffer),
    volatility_rationale: "Log file; rotated by logrotate",
};

pub(crate) static LINUX_FAIL2BAN_LOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_fail2ban_log",
    name: "Fail2Ban Log",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/var/log/fail2ban.log"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Fail2ban action log recording IP addresses banned for repeated authentication failures. Shows brute-force attack source IPs and ban/unban events — unban events may indicate attacker manipulation of fail2ban rules.",
    mitre_techniques: &["T1110"],
    fields: &[
        FieldSchema { name: "banned_ip", value_type: ValueType::Text, description: "IP address banned", is_uid_component: true },
        FieldSchema { name: "jail", value_type: ValueType::Text, description: "Fail2ban jail that triggered the ban", is_uid_component: false },
    ],
    retention: Some("Rotated"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_auth_log", "linux_secure_log"],
    sources: &[
        "https://www.fail2ban.org/wiki/index.php/Main_Page",
        "https://linux.die.net/man/8/fail2ban",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &["Only present when fail2ban is installed and active"],
    volatility: Some(crate::volatility::VolatilityClass::RotatingBuffer),
    volatility_rationale: "Fail2ban log rotated by logrotate",
};

pub(crate) static LINUX_DPKG_LOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_dpkg_log",
    name: "DPKG Package Manager Log",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/var/log/dpkg.log"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Debian package manager log recording all install/upgrade/remove/purge operations with precise timestamps. Establishes software installation timeline — reveals attacker-installed tools, backdoored packages, or cleanup attempts.",
    mitre_techniques: &["T1072", "T1195.002"],
    fields: &[
        FieldSchema { name: "package_name", value_type: ValueType::Text, description: "Package name", is_uid_component: true },
        FieldSchema { name: "action", value_type: ValueType::Text, description: "install/upgrade/remove/purge", is_uid_component: false },
        FieldSchema { name: "version", value_type: ValueType::Text, description: "Package version", is_uid_component: false },
    ],
    retention: Some("Rotated monthly; 12 months typically kept"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_apt_hooks"],
    sources: &[
        "https://linux.die.net/man/1/dpkg",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Definitive),
    evidence_caveats: &[
        "Root attackers can delete or modify entries",
        "Snap/Flatpak/manual installs do not appear here",
    ],
    volatility: Some(crate::volatility::VolatilityClass::RotatingBuffer),
    volatility_rationale: "DPKG log rotated by logrotate",
};

pub(crate) static LINUX_RPM_DB: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_rpm_db",
    name: "RPM Package Database",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/var/lib/rpm/Packages"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Berkeley DB / SQLite database of all installed RPM packages with install timestamps, file checksums, and signatories. Queried with `rpm -qa --last` to reconstruct package installation timeline on RHEL/CentOS systems.",
    mitre_techniques: &["T1072", "T1195.002"],
    fields: &[
        FieldSchema { name: "package_name", value_type: ValueType::Text, description: "RPM package name", is_uid_component: true },
        FieldSchema { name: "install_time", value_type: ValueType::Timestamp, description: "Package installation timestamp", is_uid_component: false },
    ],
    retention: Some("Updated on install/remove; reflects current state"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_messages_log"],
    sources: &[
        "https://linux.die.net/man/8/rpm",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Definitive),
    evidence_caveats: &[
        "Root attackers can rebuild the database to hide entries",
        "Manual binary installs bypass RPM",
    ],
    volatility: Some(crate::volatility::VolatilityClass::Persistent),
    volatility_rationale: "RPM database persists across reboots; updated on each package operation",
};

pub(crate) static LINUX_SELINUX_CONFIG: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_selinux_config",
    name: "SELinux Configuration",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/etc/selinux/config"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "SELinux mode configuration (Enforcing/Permissive/Disabled). An attacker who sets SELINUX=permissive or disabled removes mandatory access control enforcement — this file persists the change across reboots and is a clear indicator of defense evasion.",
    mitre_techniques: &["T1562"],
    fields: &[FieldSchema { name: "selinux_mode", value_type: ValueType::Text, description: "SELinux mode (enforcing/permissive/disabled)", is_uid_component: true }],
    retention: Some("Persistent"),
    triage_priority: TriagePriority::Critical,
    related_artifacts: &["linux_auditd_log"],
    sources: &[
        "https://www.sans.org/blog/linux-persistence-mechanisms/",
        "https://linux.die.net/man/8/selinux",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &["Disabled SELinux is itself a strong indicator of attacker activity"],
    volatility: Some(crate::volatility::VolatilityClass::Persistent),
    volatility_rationale: "Config file; persistent until modified",
};

pub(crate) static LINUX_APPARMOR_PROFILES: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_apparmor_profiles",
    name: "AppArmor Profiles",
    artifact_type: ArtifactType::Directory,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/etc/apparmor.d/"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "AppArmor mandatory access control profiles for confined processes. Attacker modification of profiles can silently grant confined processes expanded file, network, or capability permissions — effective defense evasion on Ubuntu/Debian systems.",
    mitre_techniques: &["T1562"],
    fields: &[FieldSchema { name: "profile_name", value_type: ValueType::Text, description: "AppArmor profile name (usually process path)", is_uid_component: true }],
    retention: Some("Persistent configuration"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_auditd_log"],
    sources: &[
        "https://www.sans.org/blog/linux-persistence-mechanisms/",
        "https://gitlab.com/apparmor/apparmor/-/wikis/Documentation",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &["Only meaningful on AppArmor-enabled distributions (Ubuntu, SUSE)"],
    volatility: Some(crate::volatility::VolatilityClass::Persistent),
    volatility_rationale: "Configuration files persist until explicit modification",
};

pub(crate) static LINUX_IPTABLES_RULES: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_iptables_rules",
    name: "Persisted iptables Rules (IPv4)",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/etc/iptables/rules.v4"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Persisted IPv4 iptables ruleset (Debian/Ubuntu). Reveals firewall configuration including port redirections, ACCEPT/DROP rules, and logging targets. Attacker modification can open ports for C2 reverse shells or disable egress filtering.",
    mitre_techniques: &["T1562.004"],
    fields: &[FieldSchema { name: "rule", value_type: ValueType::Text, description: "iptables rule definition", is_uid_component: true }],
    retention: Some("Persistent"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_nftables_conf"],
    sources: &[
        "https://www.sans.org/blog/linux-persistence-mechanisms/",
        "https://linux.die.net/man/8/iptables",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &[
        "Live ruleset (iptables -L) may differ from persisted file if not saved",
        "Modern systems use nftables instead",
    ],
    volatility: Some(crate::volatility::VolatilityClass::Persistent),
    volatility_rationale: "Configuration file persists until explicit modification",
};

pub(crate) static LINUX_NFTABLES_CONF: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_nftables_conf",
    name: "nftables Firewall Configuration",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/etc/nftables.conf"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "nftables firewall configuration (modern replacement for iptables on RHEL 8+/Debian 10+). Modification reveals firewall tampering for defense evasion or lateral movement facilitation.",
    mitre_techniques: &["T1562.004"],
    fields: &[FieldSchema { name: "rule", value_type: ValueType::Text, description: "nftables rule definition", is_uid_component: true }],
    retention: Some("Persistent"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_iptables_rules"],
    sources: &[
        "https://www.sans.org/blog/linux-persistence-mechanisms/",
        "https://wiki.nftables.org/wiki-nftables/index.php/Main_Page",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &["Live ruleset may differ from persisted file if not saved"],
    volatility: Some(crate::volatility::VolatilityClass::Persistent),
    volatility_rationale: "Configuration file persists until explicit modification",
};

pub(crate) static LINUX_HOSTS_FILE: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_hosts_file",
    name: "/etc/hosts (static DNS overrides)",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/etc/hosts"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Static DNS resolution table. Attacker modification redirects domain lookups (e.g., security update servers) to attacker-controlled IPs, enabling DNS hijacking for credential harvesting, C2, or blocking security tool updates.",
    mitre_techniques: &["T1565.001", "T1584"],
    fields: &[
        FieldSchema { name: "ip_address", value_type: ValueType::Text, description: "IP address", is_uid_component: true },
        FieldSchema { name: "hostname", value_type: ValueType::Text, description: "Hostname(s) mapped to IP", is_uid_component: false },
    ],
    retention: Some("Persistent"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_resolv_conf"],
    sources: &[
        "https://www.sans.org/blog/linux-persistence-mechanisms/",
        "https://linux.die.net/man/5/hosts",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Definitive),
    evidence_caveats: &["Some legitimate enterprise environments use hosts entries for internal services"],
    volatility: Some(crate::volatility::VolatilityClass::Persistent),
    volatility_rationale: "Configuration file persists until explicit modification",
};

pub(crate) static LINUX_RESOLV_CONF: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_resolv_conf",
    name: "/etc/resolv.conf (DNS resolver config)",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/etc/resolv.conf"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "DNS resolver configuration pointing to nameserver IPs. Modification to point to an attacker-controlled DNS server enables DNS hijacking and traffic interception — all hostname resolution goes through the malicious resolver.",
    mitre_techniques: &["T1565.001"],
    fields: &[FieldSchema { name: "nameserver", value_type: ValueType::Text, description: "DNS server IP address", is_uid_component: true }],
    retention: Some("Persistent; may be overwritten by NetworkManager/dhclient"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_hosts_file"],
    sources: &[
        "https://www.sans.org/blog/linux-persistence-mechanisms/",
        "https://linux.die.net/man/5/resolv.conf",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &[
        "Frequently regenerated by NetworkManager/systemd-resolved — not always persistent",
        "DHCP-pushed nameservers may legitimately point to unfamiliar IPs",
    ],
    volatility: Some(crate::volatility::VolatilityClass::ActivityDriven),
    volatility_rationale: "Frequently overwritten by NetworkManager/systemd-resolved on network changes",
};

pub(crate) static LINUX_PROC_MODULES: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_proc_modules",
    name: "/proc/modules (loaded kernel modules)",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/proc/modules"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Live list of loaded kernel modules with addresses and reference counts. Rootkits often load as kernel modules — this file (during live response) reveals loaded modules including those hidden from lsmod via /proc manipulation.",
    mitre_techniques: &["T1014", "T1547.006"],
    fields: &[
        FieldSchema { name: "module_name", value_type: ValueType::Text, description: "Kernel module name", is_uid_component: true },
        FieldSchema { name: "size", value_type: ValueType::UnsignedInt, description: "Module size in bytes", is_uid_component: false },
    ],
    retention: Some("Live kernel state — volatile"),
    triage_priority: TriagePriority::Critical,
    related_artifacts: &["linux_modprobe_d", "linux_journal_dir"],
    sources: &[
        // proc_modules(5) — dedicated man page for /proc/modules format and fields
        "https://man7.org/linux/man-pages/man5/proc_modules.5.html",
        // Volatility Phalanx 2 analysis: linux_lsmod vs /proc/modules to detect hidden LKM rootkits
        "https://volatility-labs.blogspot.com/2012/10/phalanx-2-revealed-using-volatility-to.html",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Definitive),
    evidence_caveats: &["Live kernel modules; rootkit detection; lost on reboot"],
    volatility: Some(crate::volatility::VolatilityClass::Volatile),
    volatility_rationale: "Virtual FS; lost on reboot",
};

pub(crate) static LINUX_MODPROBE_D: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_modprobe_d",
    name: "modprobe.d Configuration (module loading hooks)",
    artifact_type: ArtifactType::Directory,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/etc/modprobe.d/"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Kernel module configuration directory. Persistence via `install` directives causes a malicious binary to execute whenever a legitimate module is loaded — effective module hijacking that survives reboots and appears as normal hardware activity.",
    mitre_techniques: &["T1547.006", "T1574.006"],
    fields: &[FieldSchema { name: "directive", value_type: ValueType::Text, description: "modprobe configuration directive", is_uid_component: true }],
    retention: Some("Persistent"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_proc_modules", "linux_modules_load_d"],
    sources: &[
        "https://www.sans.org/blog/linux-persistence-mechanisms/",
        "https://linux.die.net/man/5/modprobe.d",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Definitive),
    evidence_caveats: &["Some legitimate hardware vendor packages add modprobe configuration"],
    volatility: Some(crate::volatility::VolatilityClass::Persistent),
    volatility_rationale: "Configuration directory persists until explicit modification",
};

pub(crate) static LINUX_DOCKER_CONTAINER_LOGS: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_docker_container_logs",
    name: "Docker Container Logs and State",
    artifact_type: ArtifactType::Directory,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/var/lib/docker/containers/"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Docker container runtime data including per-container JSON log files (`*-json.log`), configuration, network settings, and state. Reveals container activity, volume mounts, environment variables, and exposed ports for containerized malware or compromised workloads.",
    mitre_techniques: &["T1610", "T1611"],
    fields: &[
        FieldSchema { name: "container_id", value_type: ValueType::Text, description: "Container ID (directory name prefix)", is_uid_component: true },
        FieldSchema { name: "image", value_type: ValueType::Text, description: "Container image name and tag", is_uid_component: false },
    ],
    retention: Some("Persists until container and logs are removed"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_docker_daemon_json"],
    sources: &[
        "https://www.sans.org/blog/container-forensics/",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &[
        "Container removal deletes associated logs",
        "json-log driver is default but can be overridden to non-persistent backends",
    ],
    volatility: Some(crate::volatility::VolatilityClass::RotatingBuffer),
    volatility_rationale: "Per-container JSON logs with size-based rotation; deleted on container removal",
};

pub(crate) static LINUX_DOCKER_DAEMON_JSON: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_docker_daemon_json",
    name: "Docker Daemon Configuration",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/etc/docker/daemon.json"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Docker daemon configuration. Modification can enable insecure registries, disable content trust, expose the Docker API socket via TCP (unauthenticated), or configure privileged containers — all high-value attacker persistence and escalation techniques.",
    mitre_techniques: &["T1610", "T1562"],
    fields: &[FieldSchema { name: "config_key", value_type: ValueType::Text, description: "Configuration parameter", is_uid_component: true }],
    retention: Some("Persistent"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_docker_container_logs"],
    sources: &[
        "https://www.sans.org/blog/container-forensics/",
        "https://docs.docker.com/config/daemon/",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &["File may be absent on default installs (Docker uses defaults)"],
    volatility: Some(crate::volatility::VolatilityClass::Persistent),
    volatility_rationale: "Configuration file persists until explicit modification",
};

pub(crate) static LINUX_COREDUMP_DIR: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_coredump_dir",
    name: "systemd Coredump Storage",
    artifact_type: ArtifactType::Directory,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/var/lib/systemd/coredump/"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "systemd coredump storage for crashed processes. Process memory dumps preserved here can contain in-memory secrets (decryption keys, plaintext credentials), decrypted data, and evidence of exploited processes — valuable but often overlooked.",
    mitre_techniques: &["T1005"],
    fields: &[
        FieldSchema { name: "process_name", value_type: ValueType::Text, description: "Crashed process name", is_uid_component: true },
        FieldSchema { name: "signal", value_type: ValueType::UnsignedInt, description: "Signal that caused the crash", is_uid_component: false },
    ],
    retention: Some("Kept up to configured size limit"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_journal_dir"],
    sources: &["https://systemd.io/COREDUMP/"],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &[
        "Coredumps disabled by default on many distributions (kernel.core_pattern, ulimit)",
        "systemd-coredump retention is time- and size-bounded",
    ],
    volatility: Some(crate::volatility::VolatilityClass::RotatingBuffer),
    volatility_rationale: "systemd-coredump retention is bounded by time and size",
};

pub(crate) static LINUX_LOGROTATE_D: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_logrotate_d",
    name: "Logrotate Configuration Fragments",
    artifact_type: ArtifactType::Directory,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/etc/logrotate.d/"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Per-service log rotation configuration fragments. Attacker modification can reduce retention periods, disable compression, or shred rotated logs — anti-forensic evidence that silently destroys log history.",
    mitre_techniques: &["T1070"],
    fields: &[FieldSchema { name: "config_file", value_type: ValueType::Text, description: "Service-specific logrotate config", is_uid_component: true }],
    retention: Some("Persistent configuration"),
    triage_priority: TriagePriority::Medium,
    related_artifacts: &["linux_syslog", "linux_auth_log"],
    sources: &[
        "https://www.sans.org/blog/linux-persistence-mechanisms/",
        "https://linux.die.net/man/8/logrotate",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &["Most fragments are package-installed defaults; tampering must be distinguished"],
    volatility: Some(crate::volatility::VolatilityClass::Persistent),
    volatility_rationale: "Configuration directory persists until explicit modification",
};

pub(crate) static LINUX_SNAP_PACKAGES: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_snap_packages",
    name: "Installed Snap Packages",
    artifact_type: ArtifactType::Directory,
    hive: None,
    key_path: "",
    value_name: None,    file_path: Some("/var/lib/snapd/snaps/"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Installed Snap packages (squashfs images). Snap installs bypass traditional package managers and may leave no dpkg/rpm audit trail — reveals snap-installed software including attacker tools that evade package-log-based detection.",
    mitre_techniques: &["T1072"],
    fields: &[FieldSchema { name: "snap_name", value_type: ValueType::Text, description: "Snap package name and revision", is_uid_component: true }],
    retention: Some("Retained until snap is removed"),
    triage_priority: TriagePriority::Medium,
    related_artifacts: &["linux_dpkg_log"],
    sources: &[
        "https://snapcraft.io/docs/snap-format",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &[
        "Only meaningful on systems with snapd installed",
        "Snap revisions accumulate but are pruned",
    ],
    volatility: Some(crate::volatility::VolatilityClass::Persistent),
    volatility_rationale: "Snap package directory persists until explicit removal",
};

// ── Batch I: Linux kernel / live-system artifacts ──────────────────────────

/// Live kernel ring buffer — the in-memory circular buffer read via `dmesg` or `/dev/kmsg`.
///
/// Distinct from `linux_dmesg` (/var/log/dmesg file written at boot): this is the
/// live buffer holding all messages since boot, not yet written to any file. On a
/// running system this contains more recent messages than the file. Lost on reboot.
pub(crate) static LINUX_DMESG_RING_BUFFER: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_dmesg_ring_buffer",
    name: "Kernel Ring Buffer (live, dmesg command)",
    artifact_type: ArtifactType::LiveResponse,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: None,
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Live kernel ring buffer — all messages since boot, including those not yet \
        written to /var/log/dmesg. Records driver load errors, hardware detection, LKM load \
        events, and module initialization in real time. Richer than the boot-time snapshot \
        in linux_dmesg. In rootkit investigations, compare against /var/log/dmesg to detect \
        messages that appeared after boot (indicating post-boot LKM injection).",
    mitre_techniques: &["T1014", "T1547.006"],
    fields: &[
        FieldSchema { name: "timestamp", value_type: ValueType::Timestamp, description: "Seconds since boot (monotonic, e.g. [    1.234567])", is_uid_component: false },
        FieldSchema { name: "subsystem", value_type: ValueType::Text, description: "Kernel subsystem prefix", is_uid_component: false },
        FieldSchema { name: "message", value_type: ValueType::Text, description: "Kernel ring buffer message text", is_uid_component: false },
    ],
    retention: Some("Lost on reboot; ring buffer wraps when full (default 512KB–16MB depending on kernel config)"),
    triage_priority: TriagePriority::Critical,
    related_artifacts: &["linux_dmesg", "linux_kern_log", "linux_proc_modules", "linux_chkrootkit_output"],
    sources: &[
        "https://man7.org/linux/man-pages/man1/dmesg.1.html",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &[
        "Ring buffer wraps when full; collect early in live response",
        "Root can clear the ring buffer with dmesg --clear (T1070); absence of boot messages is suspicious",
        "See linux_dmesg for the persisted file snapshot written at boot",
    ],
    volatility: Some(crate::volatility::VolatilityClass::Volatile),
    volatility_rationale: "In-memory circular buffer; lost on reboot",
};

pub(crate) static LINUX_KERN_LOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_kern_log",
    name: "Kernel Syslog (Debian/Ubuntu)",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: Some("/var/log/kern.log"),
    scope: DataScope::System,
    os_scope: OsScope::LinuxDebian,
    decoder: Decoder::Identity,
    meaning: "Continuous kernel syslog messages (Debian/Ubuntu). Contains kernel module load/unload events, iptables rule firings, and hardware anomalies. Rootkit-loaded kernel modules appear here as insmod/modprobe events unless the rootkit hides its own load.",
    mitre_techniques: &["T1014", "T1547.006"],
    fields: &[],
    retention: Some("Rotated by logrotate; typically 4 weeks retained"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_dmesg_ring_buffer", "linux_proc_modules", "linux_syslog"],
    sources: &[
        // syslog(3) — kernel logging facility LOG_KERN feeds kern.log
        "https://man7.org/linux/man-pages/man3/syslog.3.html",
        // Elastic sequel: syslog/kern messages used to detect LKM rootkit persistence events
        "https://www.elastic.co/security-labs/sequel-on-persistence-mechanisms",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &[
        "Rootkits can suppress their own load events",
        "Easily cleared/modified by root attackers",
    ],
    volatility: Some(crate::volatility::VolatilityClass::RotatingBuffer),
    volatility_rationale: "Kernel log rotated by logrotate",
};

pub(crate) static LINUX_PROC_KALLSYMS: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_proc_kallsyms",
    name: "Kernel Symbol Table",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: Some("/proc/kallsyms"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Kernel symbol table listing all exported kernel symbols with addresses. Cross-reference with lsmod to find kernel modules that have injected symbols without appearing in the module list — a primary LKM rootkit detection technique. Requires root to see addresses (security.perf_kernel_harden).",
    mitre_techniques: &["T1014", "T1547.006"],
    fields: &[],
    retention: Some("Live /proc interface; reflects current kernel state"),
    triage_priority: TriagePriority::Critical,
    related_artifacts: &["linux_proc_modules", "linux_dmesg_ring_buffer"],
    sources: &[
        "https://man7.org/linux/man-pages/man5/proc.5.html",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Definitive),
    evidence_caveats: &["Requires root; compare against expected module symbols to find injected code"],
    volatility: Some(crate::volatility::VolatilityClass::Volatile),
    volatility_rationale: "Reflects live kernel symbol table; changes if modules loaded/unloaded",
};

pub(crate) static LINUX_PROC_NET_TCP: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_proc_net_tcp",
    name: "Kernel IPv4 TCP Socket Table",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: Some("/proc/net/tcp"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Raw IPv4 TCP socket table in hex format. Cross-reference with 'ss -antp' output: sockets present here but absent from ss indicate a rootkit hiding network connections via syscall hooking or /proc manipulation. Used to detect hidden miner pool connections and C2 channels.",
    mitre_techniques: &["T1014", "T1571", "T1572"],
    fields: &[],
    retention: Some("Live /proc interface; reflects current kernel state"),
    triage_priority: TriagePriority::Critical,
    related_artifacts: &["linux_ss_output", "linux_proc_net_tcp6", "linux_proc_net_unix"],
    sources: &[
        "https://man7.org/linux/man-pages/man5/proc.5.html",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Definitive),
    evidence_caveats: &["Live socket table; grab immediately — C2 connections close on detection"],
    volatility: Some(crate::volatility::VolatilityClass::Volatile),
    volatility_rationale: "Kernel socket table; entries vanish on connection close",
};

pub(crate) static LINUX_PROC_NET_TCP6: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_proc_net_tcp6",
    name: "Kernel IPv6 TCP Socket Table",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: Some("/proc/net/tcp6"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Raw IPv6 TCP socket table. Complements /proc/net/tcp for IPv6 connections. Rootkits may suppress IPv6 hiding from ss/netstat but leave entries in /proc/net/tcp6 visible to direct file reads.",
    mitre_techniques: &["T1014", "T1571"],
    fields: &[],
    retention: Some("Live /proc interface; reflects current kernel state"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_proc_net_tcp", "linux_ss_output"],
    sources: &[
        "https://man7.org/linux/man-pages/man5/proc.5.html",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &["Live snapshot only — historical connections not preserved"],
    volatility: Some(crate::volatility::VolatilityClass::Volatile),
    volatility_rationale: "Live kernel snapshot; lost on reboot",
};

pub(crate) static LINUX_PROC_NET_UDP: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_proc_net_udp",
    name: "Kernel IPv4 UDP Socket Table",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: Some("/proc/net/udp"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Raw IPv4 UDP socket table. DNS-over-UDP port 53 traffic, NTP, and exfiltration via UDP can be detected here. Compare with ss -u output for discrepancies indicating hidden UDP channels.",
    mitre_techniques: &["T1048", "T1071.004"],
    fields: &[],
    retention: Some("Live /proc interface; reflects current kernel state"),
    triage_priority: TriagePriority::Medium,
    related_artifacts: &["linux_proc_net_tcp", "linux_ss_output"],
    sources: &[
        "https://man7.org/linux/man-pages/man5/proc.5.html",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &["UDP is connectionless — entries reflect bound sockets, not flows"],
    volatility: Some(crate::volatility::VolatilityClass::Volatile),
    volatility_rationale: "Live kernel snapshot; lost on reboot",
};

pub(crate) static LINUX_PROC_NET_UNIX: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_proc_net_unix",
    name: "Kernel Unix Domain Socket Table",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: Some("/proc/net/unix"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Unix domain socket table. Cryptocurrency miners like XMRig use unix sockets for IPC between the miner process and its controller. Hidden processes with unix socket connections to known miner paths appear here even when the process is hidden from ps.",
    mitre_techniques: &["T1496", "T1014"],
    fields: &[],
    retention: Some("Live /proc interface; reflects current kernel state"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_proc_net_tcp", "linux_ss_output", "linux_lsof_output"],
    sources: &[
        "https://man7.org/linux/man-pages/man5/proc.5.html",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &["Only reflects active sockets at acquisition time"],
    volatility: Some(crate::volatility::VolatilityClass::Volatile),
    volatility_rationale: "Live kernel snapshot; lost on reboot",
};

pub(crate) static LINUX_LSOF_OUTPUT: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_lsof_output",
    name: "lsof Open Files Output",
    artifact_type: ArtifactType::LiveResponse,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: None,
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "lsof (list open files) output from live response collection. Shows all files, sockets, and devices held open by each process including deleted files still referenced by file descriptors. Critical for finding: (1) deleted malware binaries still running via memfd, (2) hidden library injection via LD_PRELOAD, (3) C2 sockets with remote endpoints.",
    mitre_techniques: &["T1014", "T1055", "T1574.006"],
    fields: &[],
    retention: Some("UAC live response collection: live_response/process/lsof*"),
    triage_priority: TriagePriority::Critical,
    related_artifacts: &["linux_proc_net_unix", "linux_ss_output"],
    sources: &[
        "https://man7.org/linux/man-pages/man8/lsof.8.html",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Definitive),
    evidence_caveats: &["Live-response only; deleted files visible only while process holds fd open"],
    volatility: Some(crate::volatility::VolatilityClass::Volatile),
    volatility_rationale: "Process state; lost on process exit or system reboot",
};

pub(crate) static LINUX_SS_OUTPUT: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_ss_output",
    name: "ss Socket Statistics Output",
    artifact_type: ArtifactType::LiveResponse,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: None,
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "ss (socket statistics) output with process information (-antp flags). The authoritative user-space view of network connections. Compare with /proc/net/tcp to detect rootkit-hidden connections: if a socket appears in /proc/net/tcp but not in ss output, a rootkit is filtering the syscall return value.",
    mitre_techniques: &["T1014", "T1571", "T1572"],
    fields: &[],
    retention: Some("UAC live response collection: live_response/network/ss*"),
    triage_priority: TriagePriority::Critical,
    related_artifacts: &["linux_proc_net_tcp", "linux_lsof_output", "linux_proc_net_unix"],
    sources: &[
        "https://man7.org/linux/man-pages/man8/ss.8.html",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Definitive),
    evidence_caveats: &["Live-response only; C2 connections disappear on session teardown"],
    volatility: Some(crate::volatility::VolatilityClass::Volatile),
    volatility_rationale: "Socket table exists only while connections are active",
};

pub(crate) static LINUX_CHKROOTKIT_OUTPUT: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_chkrootkit_output",
    name: "chkrootkit Scan Results",
    artifact_type: ArtifactType::LiveResponse,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: None,
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "chkrootkit scan results from UAC live response. Checks for known rootkit indicators: LD_PRELOAD entries, hidden processes (via /proc vs ps discrepancy), suspicious network connections, trojaned binaries. The 'etc_ld_so_preload' check directly surfaces LD_PRELOAD rootkit persistence.",
    mitre_techniques: &["T1014", "T1574.006"],
    fields: &[],
    retention: Some("UAC live response collection: chkrootkit/"),
    triage_priority: TriagePriority::Critical,
    related_artifacts: &["linux_lsof_output", "linux_rkhunter_log", "linux_dmesg_ring_buffer"],
    sources: &[
        "https://www.chkrootkit.org/",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Corroborative),
    evidence_caveats: &["Rootkit may subvert chkrootkit itself; corroborate with memory forensics"],
    volatility: Some(crate::volatility::VolatilityClass::Volatile),
    volatility_rationale: "Assessment output; not persisted unless explicitly saved",
};

pub(crate) static LINUX_RKHUNTER_LOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_rkhunter_log",
    name: "Rootkit Hunter Log",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: Some("/var/log/rkhunter.log"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Rootkit Hunter scan log. Checks for known rootkit file signatures, hidden files in /dev, suspicious shared libraries, and system command tampering. Complements chkrootkit with SHA256 baseline comparison against known-good system binaries.",
    mitre_techniques: &["T1014", "T1036.005"],
    fields: &[],
    retention: Some("Retained until manually cleared or logrotated"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_chkrootkit_output", "linux_dmesg_ring_buffer"],
    sources: &[
        "https://rkhunter.sourceforge.net/",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &[
        "Only present when rkhunter is installed and run",
        "Generates false positives for legitimate system modifications",
    ],
    volatility: Some(crate::volatility::VolatilityClass::RotatingBuffer),
    volatility_rationale: "Scan log rotated by logrotate",
};

pub(crate) static LINUX_SYSCTL_CONF: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_sysctl_conf",
    name: "Kernel Parameter Configuration",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: Some("/etc/sysctl.conf"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Kernel parameter configuration applied at boot. Attackers modify sysctl parameters for persistence or evasion: disabling core dumps (kernel.core_pattern for malicious handler), enabling IP forwarding for routing attacks (net.ipv4.ip_forward=1), or modifying memory protection (kernel.randomize_va_space=0 to disable ASLR).",
    mitre_techniques: &["T1562.006", "T1547.011"],
    fields: &[],
    retention: Some("Persistent configuration file"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_modules_load_d", "linux_udev_rules_d"],
    sources: &[
        "https://man7.org/linux/man-pages/man8/sysctl.8.html",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &["Live sysctl values may differ if changes were made via /proc/sys at runtime"],
    volatility: Some(crate::volatility::VolatilityClass::Persistent),
    volatility_rationale: "Configuration file persists until explicit modification",
};

// ── Group D: Linux Kernel / Proc (new artifacts only — LINUX_KERN_LOG already defined above) ──

pub(crate) static LINUX_DMESG: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_dmesg",
    name: "Kernel Ring Buffer Log (dmesg)",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: Some("/var/log/dmesg"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Persisted copy of the kernel ring buffer from the most recent boot. Written by the init system (systemd/SysV) at boot completion. Contains hardware initialization, device driver probe messages, module loading at boot time, and kernel taint information. Forensically distinct from kern.log in that it captures only the boot-time window. Key indicators: LKM load events during boot (rootkit persistence via /etc/modules or initrd), taint flags set during boot, unexpected hardware appearing in lspci/lsusb output but not here (indicates late/live insertion). The live ring buffer is volatile — accessible via 'dmesg' command on running systems.",
    mitre_techniques: &["T1014", "T1547.006"],
    fields: &[
        FieldSchema { name: "elapsed_seconds", value_type: ValueType::Text, description: "Seconds since boot (kernel monotonic clock, e.g. [    1.234567])", is_uid_component: false },
        FieldSchema { name: "subsystem", value_type: ValueType::Text, description: "Kernel subsystem prefix (usb, pci, net, etc.)", is_uid_component: false },
        FieldSchema { name: "message", value_type: ValueType::Text, description: "Kernel ring buffer message text", is_uid_component: false },
    ],
    retention: Some("Overwritten at each boot; in-memory ring buffer is volatile"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_kern_log", "linux_proc_modules", "linux_dmesg_ring_buffer"],
    sources: &[
        "https://man7.org/linux/man-pages/man1/dmesg.1.html",
        "https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &[
        "Only captures most-recent boot window; older boots overwritten",
        "Easily cleared/modified by root attackers",
    ],
    volatility: Some(crate::volatility::VolatilityClass::RotatingBuffer),
    volatility_rationale: "Persisted at boot; overwritten on next boot",
};

pub(crate) static LINUX_BOOT_LOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_boot_log",
    name: "Boot Log (/var/log/boot.log)",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: Some("/var/log/boot.log"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Service start/stop messages captured during system boot by bootlogd or the init system. On systemd systems, equivalent output is in the journal. boot.log records service success/failure status lines (OK/FAILED/SKIPPED) with service names. Forensically valuable as a temporal anchor: comparing boot.log timestamps against MFT/inode change times establishes whether files were modified before or after a known boot event. Unusual FAILED entries may indicate rootkit interference with service initialization.",
    mitre_techniques: &["T1014"],
    fields: &[
        FieldSchema { name: "timestamp", value_type: ValueType::Timestamp, description: "Boot event timestamp", is_uid_component: false },
        FieldSchema { name: "service_name", value_type: ValueType::Text, description: "Service or unit name", is_uid_component: false },
        FieldSchema { name: "status", value_type: ValueType::Text, description: "OK, FAILED, or SKIPPED", is_uid_component: false },
    ],
    retention: Some("Overwritten at each boot on many distributions"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["linux_kern_log", "linux_journal_dir"],
    sources: &[
        "https://man7.org/linux/man-pages/man8/bootlogd.8.html",
        "https://www.freedesktop.org/software/systemd/man/latest/systemd-journald.service.html",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Corroborative),
    evidence_caveats: &["systemd systems may have empty boot.log; equivalent data in journald"],
    volatility: Some(crate::volatility::VolatilityClass::RotatingBuffer),
    volatility_rationale: "Boot log rotated by logrotate",
};

// ── Group E: Linux Auth/Binary Logs ──────────────────────────────────────────

pub(crate) static LINUX_FAILLOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "linux_faillog",
    name: "Failed Login Log (/var/log/faillog)",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: Some("/var/log/faillog"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Binary database of failed login counts indexed by UID. Fixed-size records (struct faillog): fail_cnt (int16, consecutive failure count), fail_max (int16, lockout threshold), fail_time (time_t, last failure time), fail_line (tty string, 12 bytes), fail_locktime (int32, lockout duration in seconds). Read with 'faillog -a' or parse directly at struct offset UID * sizeof(faillog). High fail_cnt values for specific UIDs indicate brute-force targeting. Last failure time provides a timestamp independent of text log rotation. Root UID (0) attacks show at offset 0.",
    mitre_techniques: &["T1110"],
    fields: &[
        FieldSchema { name: "uid", value_type: ValueType::UnsignedInt, description: "User ID (record index; struct offset = uid * record_size)", is_uid_component: true },
        FieldSchema { name: "fail_cnt", value_type: ValueType::UnsignedInt, description: "Number of consecutive login failures for this UID", is_uid_component: false },
        FieldSchema { name: "fail_time", value_type: ValueType::Timestamp, description: "Unix timestamp of most recent failure", is_uid_component: false },
        FieldSchema { name: "fail_line", value_type: ValueType::Text, description: "TTY or PAM service of most recent failure attempt", is_uid_component: false },
    ],
    retention: Some("Persistent binary file; not affected by logrotate unless explicitly configured"),
    triage_priority: TriagePriority::Medium,
    related_artifacts: &["linux_auth_log", "linux_utmp", "linux_wtmp"],
    sources: &[
        "https://man7.org/linux/man-pages/man5/faillog.5.html",
        "https://man7.org/linux/man-pages/man8/faillog.8.html",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &[
        "Many modern distributions have deprecated faillog in favor of pam_tally2/pam_faillock",
        "Fixed-size structure overwritten on each failure",
    ],
    volatility: Some(crate::volatility::VolatilityClass::ActivityDriven),
    volatility_rationale: "Fixed-size per-UID record overwritten on each failure event",
};

// ── Hak5 LAN Turtle Credential Loot ─────────────────────────────────────────

/// Hak5 LAN Turtle credential loot directory (`/root/loot/`).
///
/// The LAN Turtle is a covert penetration testing device housed in a USB
/// Ethernet adapter case (Realtek RTL8152, VID 0BDA / PID 8152) running
/// OpenWrt Linux. The QuickCreds module runs Responder to capture LLMNR/
/// NBT-NS credentials (typically NTLMv2 hashes) from the host it is plugged
/// into. Captured credentials are saved to numbered subdirectories under
/// `/root/loot/` on the device's 16 MB flash storage.
///
/// Forensic examination of a seized LAN Turtle device involves SSH'ing to
/// 172.16.84.1 (default static IP on the USB Ethernet interface) or imaging
/// the flash storage directly. The loot directory contains Responder output
/// files with victim hostname, domain, username, and NTLMv2 hash.
///
/// On the victim Windows host, the LAN Turtle leaves standard USB device
/// registry artifacts (SYSTEM hive: USB\VID_0BDA&PID_8152) and DHCP event
/// log entries for the new network adapter.
///
/// # Sources
/// - <https://cheeky4n6monkey.blogspot.com/2017/01/monkey-plays-lan-turtle.html> —
///   LAN Turtle forensic examination, QuickCreds credential capture, host artifacts
/// - <https://docs.hak5.org/lan-turtle/> — Hak5 LAN Turtle official documentation
// Source: https://cheeky4n6monkey.blogspot.com/2017/01/monkey-plays-lan-turtle.html
pub(crate) static LAN_TURTLE_LOOT: ArtifactDescriptor = ArtifactDescriptor {
    id: "lan_turtle_loot",
    name: "Hak5 LAN Turtle Credential Loot",
    artifact_type: ArtifactType::Directory,
    hive: None,
    key_path: "",
    value_name: None,
    // Source: https://cheeky4n6monkey.blogspot.com/2017/01/monkey-plays-lan-turtle.html
    // QuickCreds saves Responder output to numbered dirs in /root/loot/
    file_path: Some("/root/loot/"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Hak5 LAN Turtle credential loot directory on the device's OpenWrt Linux \
        filesystem. The QuickCreds module uses Laurent Gaffie's Responder to perform \
        LLMNR/NBT-NS poisoning and capture NTLMv2 credentials from the host machine \
        the Turtle is plugged into. Credentials are stored in numbered subdirectories \
        under /root/loot/. Each capture file contains victim hostname, domain, username, \
        and NTLMv2 hash. The device identifies as a Realtek RTL8152 USB Ethernet \
        adapter (VID 0BDA / PID 8152) and has a static IP of 172.16.84.1 on its USB \
        interface. Credential capture completes in 30 seconds to a few minutes and \
        works whether the victim screen is locked or not (user must be logged in). \
        On the victim Windows host, evidence includes USB device registry entries \
        (SYSTEM hive: USB\\VID_0BDA&PID_8152\\00E04C36150A) and DHCP event log entries \
        for the Realtek USB FE Family Controller network adapter.",
    mitre_techniques: &["T1557.001", "T1200", "T1056"],
    fields: &[
        FieldSchema {
            name: "credential_type",
            value_type: ValueType::Text,
            // Source: https://cheeky4n6monkey.blogspot.com/2017/01/monkey-plays-lan-turtle.html
            description: "Type of captured credential (e.g. NTLMv2, NTLMv1, HTTP Basic)",
            is_uid_component: false,
        },
        FieldSchema {
            name: "victim_hostname",
            value_type: ValueType::Text,
            // Source: https://cheeky4n6monkey.blogspot.com/2017/01/monkey-plays-lan-turtle.html
            description: "Hostname of the victim machine that sent the credential",
            is_uid_component: true,
        },
        FieldSchema {
            name: "victim_username",
            value_type: ValueType::Text,
            description: "Username extracted from the credential response",
            is_uid_component: false,
        },
        FieldSchema {
            name: "hash_value",
            value_type: ValueType::Text,
            // Source: https://cheeky4n6monkey.blogspot.com/2017/01/monkey-plays-lan-turtle.html
            description: "Captured NTLMv2 (or other) hash value; crackable with hashcat/john",
            is_uid_component: false,
        },
    ],
    retention: Some("Persistent on 16 MB flash until manually deleted or reflashed"),
    triage_priority: TriagePriority::Critical,
    related_artifacts: &[],
    sources: &[
        // Source: https://cheeky4n6monkey.blogspot.com/2017/01/monkey-plays-lan-turtle.html
        // — LAN Turtle forensic examination walkthrough with QuickCreds and Responder
        "https://cheeky4n6monkey.blogspot.com/2017/01/monkey-plays-lan-turtle.html",
        // Source: https://docs.hak5.org/lan-turtle/ — official Hak5 LAN Turtle docs
        "https://docs.hak5.org/lan-turtle/",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Definitive),
    evidence_caveats: &[
        "Requires physical access to the LAN Turtle device (SSH to 172.16.84.1 or flash imaging)",
        "Loot files can be deleted by the attacker before seizure",
        "Credential type depends on victim OS — NTLMv2 for Windows 7+, may vary for others",
    ],
    volatility: Some(crate::volatility::VolatilityClass::Persistent),
    volatility_rationale:
        "Stored on 16 MB flash; persists until manually deleted or device is reflashed",
};

// ── /etc/passwd — local user account database ────────────────────────────────

/// Linux `/etc/passwd` — local user account database (world-readable).
///
/// Contains username, UID, GID, GECOS full name, home directory, and login shell

// ── ESXi vSphere Trust Authority service logs ─────────────────────────────────

/// ESXi `/var/run/log/attestd.log` — vSphere Trust Authority Attestation Service.
///
/// Records attestation events for ESXi Trusted Hosts in a vSphere Trust Authority
/// deployment. Relevant in environments using vTA; anomalies here may indicate
/// tampering with the ESXi TPM attestation chain.
pub(crate) static ESXI_ATTESTD_LOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "esxi_attestd_log",
    name: "ESXi Attestation Service Log (attestd.log)",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: Some("/var/run/log/attestd.log"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Records attestation events for the ESXi vSphere Trust Authority service. \
        Attestation failures or repeated retries may indicate hypervisor integrity tampering, \
        unauthorized firmware changes, or a host being removed from a trusted cluster. \
        Relevant in vTA deployments; cross-reference with esxtokend.log and kmxa.log for \
        full Trust Authority chain visibility.",
    mitre_techniques: &["T1562"],
    fields: &[FieldSchema {
        name: "log_entry",
        value_type: ValueType::Text,
        description: "Timestamped syslog-format log line from the attestation daemon",
        is_uid_component: false,
    }],
    retention: Some("Rotated; check /var/run/log/ for .gz rotations"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["esxi_esxtokend_log", "esxi_kmxa_log"],
    sources: &["https://github.com/forensicartifacts/artifacts"],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Corroborative),
    evidence_caveats: &[
        "Only present on ESXi hosts configured as vSphere Trust Authority Trusted Hosts",
    ],
    volatility: Some(crate::volatility::VolatilityClass::Volatile),
    volatility_rationale: "/var/run/log/ on ESXi is RAM-backed (tmpfs); lost on reboot",
};

/// ESXi `/var/run/log/esxtokend.log` — vSphere Trust Authority ESX Token Service.
///
/// Records token issuance events for authenticated workloads in a vTA deployment.
/// Unexpected token requests or failures can indicate credential harvesting against
/// the ESXi token service.
pub(crate) static ESXI_ESXTOKEND_LOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "esxi_esxtokend_log",
    name: "ESXi Token Service Log (esxtokend.log)",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: Some("/var/run/log/esxtokend.log"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Records token issuance events for the ESXi vSphere Trust Authority Token Service. \
        Unexpected or high-volume token requests, authentication failures, or service restarts \
        may indicate credential harvesting against the ESXi trust chain. \
        Correlate with attestd.log and kmxa.log for full vTA event reconstruction.",
    mitre_techniques: &["T1552", "T1562"],
    fields: &[FieldSchema {
        name: "log_entry",
        value_type: ValueType::Text,
        description: "Timestamped syslog-format log line from the token service daemon",
        is_uid_component: false,
    }],
    retention: Some("Rotated; check /var/run/log/ for .gz rotations"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["esxi_attestd_log", "esxi_kmxa_log"],
    sources: &["https://github.com/forensicartifacts/artifacts"],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Corroborative),
    evidence_caveats: &["Only present on ESXi hosts in a vSphere Trust Authority deployment"],
    volatility: Some(crate::volatility::VolatilityClass::Volatile),
    volatility_rationale: "/var/run/log/ on ESXi is RAM-backed (tmpfs); lost on reboot",
};

/// ESXi `/var/run/log/kmxa.log` — vSphere Trust Authority Key Provider Client Service.
///
/// Records activities of the ESXi Key Management Agent (Client Service) on a
/// Trusted Host. Key provider failures can indicate encryption bypass attempts
/// or infrastructure-level attacks on a vTA cluster.
pub(crate) static ESXI_KMXA_LOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "esxi_kmxa_log",
    name: "ESXi Key Provider Agent Log (kmxa.log)",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,
    file_path: Some("/var/run/log/kmxa.log"),
    scope: DataScope::System,
    os_scope: OsScope::Linux,
    decoder: Decoder::Identity,
    meaning: "Records activities of the Key Management Agent (Client Service) on an ESXi \
        Trusted Host in a vSphere Trust Authority deployment. Key provider errors, \
        unexpected key requests, or service restarts may indicate encryption bypass attempts \
        or infrastructure attacks targeting VM encryption keys. \
        Correlate with attestd.log and esxtokend.log.",
    mitre_techniques: &["T1552", "T1486"],
    fields: &[FieldSchema {
        name: "log_entry",
        value_type: ValueType::Text,
        description: "Timestamped syslog-format log line from the key management agent",
        is_uid_component: false,
    }],
    retention: Some("Rotated; check /var/run/log/ for .gz rotations"),
    triage_priority: TriagePriority::High,
    related_artifacts: &["esxi_attestd_log", "esxi_esxtokend_log"],
    sources: &["https://github.com/forensicartifacts/artifacts"],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Corroborative),
    evidence_caveats: &[
        "Only present on ESXi Trusted Hosts in a vSphere Trust Authority deployment",
    ],
    volatility: Some(crate::volatility::VolatilityClass::Volatile),
    volatility_rationale: "/var/run/log/ on ESXi is RAM-backed (tmpfs); lost on reboot",
};