pub const ZONE_LOCAL: u32 = 0;
pub const ZONE_INTRANET: u32 = 1;
pub const ZONE_TRUSTED: u32 = 2;
pub const ZONE_INTERNET: u32 = 3;
pub const ZONE_RESTRICTED: u32 = 4;
#[must_use]
pub fn is_internet_download(zone_id: u32) -> bool {
zone_id >= ZONE_INTERNET
}
#[must_use]
pub fn is_double_extension(filename: &str) -> bool {
let name = filename.rsplit(['/', '\\']).next().unwrap_or(filename);
let parts: Vec<&str> = name.splitn(3, '.').collect();
parts.len() == 3 && parts.iter().all(|p| !p.is_empty())
}
#[must_use]
pub fn is_alternate_data_stream(path: &str) -> bool {
path.chars().skip(2).any(|c| c == ':')
}
#[must_use]
pub fn is_linux_hidden_name(name: &str) -> bool {
name.starts_with('.') && name.len() > 1
}
#[must_use]
pub fn is_unc_path(path: &str) -> bool {
path.starts_with("\\\\") || path.starts_with("//")
}
pub const SUSPICIOUS_EXEC_PREFIXES: &[&str] = &[
"\\Temp\\",
"\\tmp\\",
"\\AppData\\Local\\Temp\\",
"\\Users\\Public\\",
"\\ProgramData\\",
"/tmp/",
"/dev/shm/",
"/run/shm/",
"/var/tmp/",
];
#[must_use]
pub fn is_suspicious_exec_path(path: &str) -> bool {
SUSPICIOUS_EXEC_PREFIXES.iter().any(|p| path.contains(p))
}
pub const CONSOLE_KNOWN_VALUE_NAMES: &[&str] = &[
"ColorTable00",
"ColorTable01",
"ColorTable02",
"ColorTable03",
"ColorTable04",
"ColorTable05",
"ColorTable06",
"ColorTable07",
"ColorTable08",
"ColorTable09",
"ColorTable10",
"ColorTable11",
"ColorTable12",
"ColorTable13",
"ColorTable14",
"ColorTable15",
"CtrlKeyShortcutsDisabled",
"CursorColor",
"CursorSize",
"CursorType",
"DefaultBackground",
"DefaultForeground",
"EnableColorSelection",
"ExtendedEditKey",
"ExtendedEditKeyCustom",
"FaceName",
"FilterOnPaste",
"FontFamily",
"FontSize",
"FontWeight",
"ForceV2",
"HistoryBufferSize",
"HistoryNoDup",
"InsertMode",
"LineSelection",
"LineWrap",
"LoadConIme",
"NumberOfHistoryBuffers",
"PopupColors",
"QuickEdit",
"ScreenBufferSize",
"ScreenColors",
"TerminalScrolling",
"TrimLeadingZeros",
"WindowAlpha",
"WindowPosition",
"WindowSize",
"WordDelimiters",
];
#[must_use]
pub fn is_suspicious_console_value_name(name: &str) -> bool {
if name.is_empty() {
return true;
}
!CONSOLE_KNOWN_VALUE_NAMES
.iter()
.any(|known| known.eq_ignore_ascii_case(name))
}
#[must_use]
pub fn is_suspicious_console_subkey(key_path: &str) -> bool {
const PREFIX: &str = "HKCU\\Console\\";
if key_path.len() <= PREFIX.len() {
return false;
}
if !key_path
.get(..PREFIX.len())
.is_some_and(|p| p.eq_ignore_ascii_case(PREFIX))
{
return false;
}
let tail = &key_path[PREFIX.len()..];
let first_segment = tail.split('\\').next().unwrap_or(tail);
!first_segment.is_empty() && first_segment.chars().all(|c| c.is_ascii_digit())
}
#[must_use]
pub fn is_ntuser_man_path(path: &str) -> bool {
let base = path.rsplit(['/', '\\']).next().unwrap_or(path);
base.eq_ignore_ascii_case("NTUSER.MAN")
}
#[must_use]
pub fn is_task_com_handler_dll_suspicious(dll_path: &str) -> bool {
if dll_path.is_empty() {
return false;
}
let lower = dll_path.to_ascii_lowercase();
let safe_prefixes = [
r"%systemroot%\system32",
r"%windir%\system32",
r"c:\windows\system32",
r"%systemroot%\syswow64",
r"%windir%\syswow64",
r"c:\windows\syswow64",
];
!safe_prefixes.iter().any(|p| lower.starts_with(p))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zone_internet_is_internet_download() {
assert!(is_internet_download(ZONE_INTERNET));
}
#[test]
fn zone_restricted_is_internet_download() {
assert!(is_internet_download(ZONE_RESTRICTED));
}
#[test]
fn zone_local_is_not_internet_download() {
assert!(!is_internet_download(ZONE_LOCAL));
}
#[test]
fn zone_trusted_is_not_internet_download() {
assert!(!is_internet_download(ZONE_TRUSTED));
}
#[test]
fn double_extension_pdf_exe() {
assert!(is_double_extension("invoice.pdf.exe"));
}
#[test]
fn double_extension_doc_exe() {
assert!(is_double_extension("report.doc.exe"));
}
#[test]
fn single_extension_not_double() {
assert!(!is_double_extension("program.exe"));
}
#[test]
fn no_extension_not_double() {
assert!(!is_double_extension("makefile"));
}
#[test]
fn double_extension_empty_part_not_flagged() {
assert!(!is_double_extension(".hidden.exe"));
}
#[test]
fn ads_path_detected() {
assert!(is_alternate_data_stream(r"C:\file.txt:stream"));
}
#[test]
fn normal_path_not_ads() {
assert!(!is_alternate_data_stream(r"C:\file.txt"));
}
#[test]
fn drive_colon_not_ads() {
assert!(!is_alternate_data_stream(r"C:\dir\file.txt"));
}
#[test]
fn linux_hidden_dot_file() {
assert!(is_linux_hidden_name(".bashrc"));
}
#[test]
fn linux_hidden_double_dot() {
assert!(is_linux_hidden_name("..file"));
}
#[test]
fn linux_non_hidden() {
assert!(!is_linux_hidden_name("bashrc"));
}
#[test]
fn linux_single_dot_not_hidden() {
assert!(!is_linux_hidden_name("."));
}
#[test]
fn unc_path_backslash() {
assert!(is_unc_path(r"\\server\share"));
}
#[test]
fn unc_path_forward_slash() {
assert!(is_unc_path("//server/share"));
}
#[test]
fn normal_path_not_unc() {
assert!(!is_unc_path(r"C:\Windows"));
}
#[test]
fn suspicious_exec_tmp_path() {
assert!(is_suspicious_exec_path(
r"C:\Users\bob\AppData\Local\Temp\evil.exe"
));
}
#[test]
fn suspicious_exec_dev_shm() {
assert!(is_suspicious_exec_path("/dev/shm/payload"));
}
#[test]
fn normal_exec_path_not_suspicious() {
assert!(!is_suspicious_exec_path(r"C:\Windows\System32\calc.exe"));
}
#[test]
fn console_facename_is_known() {
assert!(!is_suspicious_console_value_name("FaceName"));
}
#[test]
fn console_fontsize_is_known() {
assert!(!is_suspicious_console_value_name("FontSize"));
}
#[test]
fn console_colortable00_is_known() {
assert!(!is_suspicious_console_value_name("ColorTable00"));
}
#[test]
fn console_known_value_case_insensitive() {
assert!(!is_suspicious_console_value_name("facename"));
assert!(!is_suspicious_console_value_name("FACENAME"));
}
#[test]
fn console_arbitrary_blob_name_is_suspicious() {
assert!(is_suspicious_console_value_name("config"));
assert!(is_suspicious_console_value_name(
"d33f351a4aeea5e608853d1a56661059"
));
}
#[test]
fn console_empty_value_name_is_suspicious() {
assert!(is_suspicious_console_value_name(""));
}
#[test]
fn console_numeric_subkey_is_suspicious() {
assert!(is_suspicious_console_subkey(r"HKCU\Console\0"));
assert!(is_suspicious_console_subkey(
r"HKCU\Console\0\d33f351a4aeea5e608853d1a56661059"
));
}
#[test]
fn console_app_subkey_not_suspicious() {
assert!(!is_suspicious_console_subkey(r"HKCU\Console\cmd.exe"));
assert!(!is_suspicious_console_subkey(
r"HKCU\Console\%SystemRoot%_System32_cmd.exe"
));
}
#[test]
fn console_root_key_not_flagged_as_subkey() {
assert!(!is_suspicious_console_subkey(r"HKCU\Console"));
assert!(!is_suspicious_console_subkey(r"HKCU\Console\"));
}
#[test]
fn console_subkey_check_case_insensitive() {
assert!(is_suspicious_console_subkey(r"hkcu\console\0"));
}
#[test]
fn non_console_key_not_flagged() {
assert!(!is_suspicious_console_subkey(
r"HKCU\Software\Microsoft\Windows"
));
}
#[test]
fn ntuser_man_in_userprofile_detected() {
assert!(is_ntuser_man_path(r"C:\Users\bob\NTUSER.MAN"));
}
#[test]
fn ntuser_man_case_insensitive() {
assert!(is_ntuser_man_path(r"C:\Users\bob\ntuser.man"));
assert!(is_ntuser_man_path(r"C:\Users\bob\NtUser.Man"));
}
#[test]
fn ntuser_dat_not_flagged() {
assert!(!is_ntuser_man_path(r"C:\Users\bob\NTUSER.DAT"));
}
#[test]
fn ntuser_man_on_unc_share_detected() {
assert!(is_ntuser_man_path(r"\\server\share\profile.v6\NTUSER.MAN"));
}
#[test]
fn ntuser_man_substring_in_other_filename_not_flagged() {
assert!(!is_ntuser_man_path(
r"C:\Users\bob\notes\ntuser.man.backup.txt"
));
}
#[test]
fn system32_dll_is_not_suspicious() {
assert!(!is_task_com_handler_dll_suspicious(
r"%SystemRoot%\System32\regidle.dll"
));
}
#[test]
fn system32_dll_case_insensitive() {
assert!(!is_task_com_handler_dll_suspicious(
r"C:\WINDOWS\system32\DeviceDirectoryClient.dll"
));
}
#[test]
fn syswow64_dll_is_not_suspicious() {
assert!(!is_task_com_handler_dll_suspicious(
r"%SystemRoot%\SysWOW64\example.dll"
));
}
#[test]
fn temp_dir_dll_is_suspicious() {
assert!(is_task_com_handler_dll_suspicious(
r"C:\Users\bob\AppData\Local\Temp\evil.dll"
));
}
#[test]
fn programdata_dll_is_suspicious() {
assert!(is_task_com_handler_dll_suspicious(
r"C:\ProgramData\payload.dll"
));
}
#[test]
fn empty_dll_path_is_not_flagged() {
assert!(!is_task_com_handler_dll_suspicious(""));
}
}
#[must_use]
pub fn is_pam_module_path_suspicious(module_path: &str) -> bool {
if module_path.is_empty() {
return false;
}
let lower = module_path.to_ascii_lowercase();
let safe_prefixes = [
"/lib/security/",
"/lib/x86_64-linux-gnu/security/",
"/lib/aarch64-linux-gnu/security/",
"/usr/lib/security/",
"/usr/lib/x86_64-linux-gnu/security/",
"/usr/lib64/security/",
];
!safe_prefixes.iter().any(|p| lower.starts_with(p))
}
#[must_use]
pub fn is_pam_exec_script_suspicious(script_path: &str) -> bool {
if script_path.is_empty() {
return false;
}
let lower = script_path.to_ascii_lowercase();
let suspicious_prefixes = [
"/tmp/",
"/var/tmp/",
"/dev/shm/",
"/home/",
"/root/",
"/run/user/",
];
suspicious_prefixes.iter().any(|p| lower.starts_with(p))
}
#[cfg(test)]
mod tests_pam_heuristics {
use super::*;
#[test]
fn standard_lib_security_so_is_safe() {
assert!(!is_pam_module_path_suspicious("/lib/security/pam_unix.so"));
}
#[test]
fn debian_security_path_is_safe() {
assert!(!is_pam_module_path_suspicious(
"/lib/x86_64-linux-gnu/security/pam_sss.so"
));
}
#[test]
fn usr_lib_security_is_safe() {
assert!(!is_pam_module_path_suspicious(
"/usr/lib/x86_64-linux-gnu/security/pam_unix.so"
));
}
#[test]
fn tmp_pam_so_is_suspicious() {
assert!(is_pam_module_path_suspicious("/tmp/pam_linux.so"));
}
#[test]
fn home_dir_pam_so_is_suspicious() {
assert!(is_pam_module_path_suspicious("/home/attacker/pam_linux.so"));
}
#[test]
fn var_tmp_pam_so_is_suspicious() {
assert!(is_pam_module_path_suspicious("/var/tmp/pam_evil.so"));
}
#[test]
fn empty_pam_module_path_is_not_suspicious() {
assert!(!is_pam_module_path_suspicious(""));
}
#[test]
fn etc_script_is_not_suspicious() {
assert!(!is_pam_exec_script_suspicious("/etc/pam_scripts/notify.sh"));
}
#[test]
fn usr_local_script_is_not_suspicious() {
assert!(!is_pam_exec_script_suspicious(
"/usr/local/bin/pam_check.sh"
));
}
#[test]
fn tmp_capture_script_is_suspicious() {
assert!(is_pam_exec_script_suspicious("/tmp/capture.sh"));
}
#[test]
fn dev_shm_script_is_suspicious() {
assert!(is_pam_exec_script_suspicious("/dev/shm/exfil.sh"));
}
#[test]
fn home_dir_script_is_suspicious() {
assert!(is_pam_exec_script_suspicious("/home/user/.config/run.sh"));
}
#[test]
fn var_tmp_script_is_suspicious() {
assert!(is_pam_exec_script_suspicious("/var/tmp/backdoor.sh"));
}
#[test]
fn root_home_script_is_suspicious() {
assert!(is_pam_exec_script_suspicious("/root/.bashrc_extra.sh"));
}
#[test]
fn empty_script_path_is_not_suspicious() {
assert!(!is_pam_exec_script_suspicious(""));
}
}