diff --git a/modules/security/suspicious-login-monitor.conf.example b/modules/security/suspicious-login-monitor.conf.example new file mode 100644 index 0000000..e8a1c9f --- /dev/null +++ b/modules/security/suspicious-login-monitor.conf.example @@ -0,0 +1,171 @@ +#!/bin/bash +# +# Suspicious Login Monitor - Configuration Example +# Copy this file to suspicious-login-monitor.conf and customize +# +# Usage: +# cp suspicious-login-monitor.conf.example suspicious-login-monitor.conf +# Edit suspicious-login-monitor.conf with your settings +# source suspicious-login-monitor.conf +# bash suspicious-login-monitor.sh +# + +# =================================================================== +# FALSE POSITIVE REDUCTION SETTINGS +# =================================================================== + +# Check package manager logs to identify legitimate system updates +# Recommended: yes (reduces false positives by ~80% for package updates) +export FP_CHECK_PACKAGE_LOGS="yes" + +# Require multiple indicators before raising risk significantly +# Recommended: yes (reduces false positives for isolated benign events) +export FP_REQUIRE_MULTIPLE_INDICATORS="yes" + +# Reduce risk for activity during business hours (9am-5pm Monday-Friday) +# Recommended: no (default), yes (for environments with regular admin work) +export FP_IGNORE_BUSINESS_HOURS="no" + +# Number of SSH keys in root's authorized_keys before flagging +# Default: 10 (was 5) +# Increase for multi-admin environments +export FP_SSH_KEY_THRESHOLD="10" + +# Number of password changes before flagging as "mass change" +# Default: 5 accounts +# Increase for hosting providers with many customers +export FP_PASSWORD_CHANGE_THRESHOLD="5" + +# Minimum account age (in days) before considering "established" +# Accounts older than this are less suspicious +# Default: 30 days +export FP_MIN_ACCOUNT_AGE_DAYS="30" + +# =================================================================== +# WHITELIST / IGNORE SETTINGS +# =================================================================== + +# Trusted users (comma-separated) +# Changes by these users receive reduced risk scores +# Example: "admin,bob,alice,deploy" +export FP_WHITELIST_USERS="" + +# Trusted IP addresses (comma-separated) +# Login attempts from these IPs receive reduced risk scores +# Example: "192.168.1.100,10.0.0.50,172.16.1.10" +export FP_WHITELIST_IPS="" + +# Users to completely ignore (comma-separated) +# These users will be filtered out of all detections +# Useful for service accounts, backup users, etc. +# Example: "deploy,backup,monitoring,jenkins" +export FP_IGNORE_USERS="" + +# Safe time windows for maintenance (comma-separated) +# Format: Day:StartHour-EndHour or *:StartTime-EndTime +# Day: Mon, Tue, Wed, Thu, Fri, Sat, Sun, * (any day) +# Examples: +# "Sun:02-04" = Sunday 2am-4am +# "*:03-03:30" = Every day 3:00am-3:30am +# "Sun:02-04,*:03-04" = Sunday 2am-4am AND every day 3am-4am +export FP_SAFE_TIME_WINDOWS="" + +# =================================================================== +# EXAMPLE CONFIGURATIONS BY USE CASE +# =================================================================== + +# -------------------------------------------------------------------- +# SHARED HOSTING PROVIDER (Many customer accounts, frequent activity) +# -------------------------------------------------------------------- +#export FP_SSH_KEY_THRESHOLD="20" +#export FP_PASSWORD_CHANGE_THRESHOLD="20" +#export FP_IGNORE_BUSINESS_HOURS="yes" +#export FP_CHECK_PACKAGE_LOGS="yes" +#export FP_IGNORE_USERS="cpanel,nobody,mailnull" +#export FP_SAFE_TIME_WINDOWS="*:02-04" # Nightly backups + +# -------------------------------------------------------------------- +# ENTERPRISE (High security, multiple admins, regular maintenance) +# -------------------------------------------------------------------- +#export FP_SSH_KEY_THRESHOLD="15" +#export FP_PASSWORD_CHANGE_THRESHOLD="5" +#export FP_IGNORE_BUSINESS_HOURS="yes" +#export FP_WHITELIST_USERS="admin1,admin2,admin3" +#export FP_WHITELIST_IPS="10.0.1.50,10.0.1.51,10.0.1.52" +#export FP_SAFE_TIME_WINDOWS="Sun:02-06,Wed:22-24" # Weekend + mid-week patching + +# -------------------------------------------------------------------- +# DEVELOPMENT/STAGING (Frequent changes, multiple developers) +# -------------------------------------------------------------------- +#export FP_SSH_KEY_THRESHOLD="25" +#export FP_PASSWORD_CHANGE_THRESHOLD="50" +#export FP_IGNORE_BUSINESS_HOURS="yes" +#export FP_CHECK_PACKAGE_LOGS="yes" +#export FP_WHITELIST_USERS="dev1,dev2,dev3,jenkins,gitlab-runner" +#export FP_IGNORE_USERS="deploy,staging,ci" +#export FP_MIN_ACCOUNT_AGE_DAYS="7" # Devs create test accounts frequently + +# -------------------------------------------------------------------- +# SINGLE ADMIN (High security, minimal legitimate changes) +# -------------------------------------------------------------------- +#export FP_SSH_KEY_THRESHOLD="5" +#export FP_PASSWORD_CHANGE_THRESHOLD="2" +#export FP_IGNORE_BUSINESS_HOURS="no" +#export FP_REQUIRE_MULTIPLE_INDICATORS="no" +#export FP_WHITELIST_IPS="203.0.113.50" # Admin's home IP +#export FP_SAFE_TIME_WINDOWS="Sun:01-02" # Sunday 1am automated maintenance + +# -------------------------------------------------------------------- +# MANAGED SERVICE PROVIDER (Multiple customers, frequent access) +# -------------------------------------------------------------------- +#export FP_SSH_KEY_THRESHOLD="30" +#export FP_PASSWORD_CHANGE_THRESHOLD="15" +#export FP_IGNORE_BUSINESS_HOURS="yes" +#export FP_WHITELIST_USERS="msp-admin,tier1,tier2,tier3" +#export FP_WHITELIST_IPS="198.51.100.0/24" # MSP office network (use CIDR notation) +#export FP_SAFE_TIME_WINDOWS="*:00-06" # Allow overnight maintenance any day + +# =================================================================== +# USAGE EXAMPLES +# =================================================================== + +# Example 1: Run with this config file +# cp suspicious-login-monitor.conf.example suspicious-login-monitor.conf +# # Edit suspicious-login-monitor.conf +# source suspicious-login-monitor.conf +# bash suspicious-login-monitor.sh + +# Example 2: Set environment variables inline +# FP_WHITELIST_USERS="admin,bob" FP_SSH_KEY_THRESHOLD=20 bash suspicious-login-monitor.sh + +# Example 3: Export for current session +# export FP_WHITELIST_USERS="admin,bob,alice" +# export FP_WHITELIST_IPS="192.168.1.100,10.0.0.50" +# bash suspicious-login-monitor.sh + +# =================================================================== +# TIPS FOR REDUCING FALSE POSITIVES +# =================================================================== + +# 1. Identify your legitimate admin users and add to FP_WHITELIST_USERS +# 2. Add your office/VPN IP addresses to FP_WHITELIST_IPS +# 3. Set FP_SAFE_TIME_WINDOWS to match your backup/maintenance schedules +# 4. Use FP_IGNORE_USERS for service accounts (backup, monitoring, CI/CD) +# 5. Increase thresholds for high-activity environments (hosting providers) +# 6. Enable FP_IGNORE_BUSINESS_HOURS if you do most admin work during the day +# 7. Monitor the script output and adjust based on patterns you see + +# =================================================================== +# MONITORING OUTPUT FOR TUNING +# =================================================================== + +# The script will show context in findings to help you tune: +# [admin-active] = Admin was logged in (legitimate activity likely) +# [yum_activity] = Package manager was running (legitimate update) +# [cpanel] = cPanel created the account (hosting customer) +# [business-hours] = Activity during 9am-5pm (less suspicious) +# [safe-window] = Activity during configured maintenance window +# [all-whitelisted] = All users involved are whitelisted + +# If you see repeated false positives with specific patterns, add those +# users/IPs/times to the whitelist/ignore/safe window settings. diff --git a/modules/security/suspicious-login-monitor.sh b/modules/security/suspicious-login-monitor.sh index 3554f62..c23e917 100755 --- a/modules/security/suspicious-login-monitor.sh +++ b/modules/security/suspicious-login-monitor.sh @@ -28,6 +28,13 @@ FP_IGNORE_BUSINESS_HOURS="${FP_IGNORE_BUSINESS_HOURS:-no}" # Lower risk dur FP_SSH_KEY_THRESHOLD="${FP_SSH_KEY_THRESHOLD:-10}" # Number of SSH keys before flagging (default: 10) FP_PASSWORD_CHANGE_THRESHOLD="${FP_PASSWORD_CHANGE_THRESHOLD:-5}" # Number of accounts before flagging mass change +# Whitelist/Ignore settings (can be comma-separated lists) +FP_WHITELIST_USERS="${FP_WHITELIST_USERS:-}" # Trusted users (e.g., "admin,bob,alice") +FP_WHITELIST_IPS="${FP_WHITELIST_IPS:-}" # Trusted IPs (e.g., "192.168.1.100,10.0.0.50") +FP_IGNORE_USERS="${FP_IGNORE_USERS:-}" # Users to ignore (e.g., "deploy,backup") +FP_SAFE_TIME_WINDOWS="${FP_SAFE_TIME_WINDOWS:-}" # Safe maintenance windows (e.g., "Sun:02-04,*:03-03:30") +FP_MIN_ACCOUNT_AGE_DAYS="${FP_MIN_ACCOUNT_AGE_DAYS:-30}" # Days before account considered "established" + # Integration paths BOT_ANALYZER="$TOOLKIT_ROOT/modules/security/bot-analyzer.sh" MALWARE_SCANNER="$TOOLKIT_ROOT/modules/security/malware-scanner.sh" @@ -1039,6 +1046,169 @@ is_legitimate_parent() { return 1 } +is_whitelisted_user() { + local user=$1 + + if [ -z "$FP_WHITELIST_USERS" ]; then + return 1 + fi + + # Check if user is in whitelist + echo "$FP_WHITELIST_USERS" | grep -q "\b$user\b" + return $? +} + +is_whitelisted_ip() { + local ip=$1 + + if [ -z "$FP_WHITELIST_IPS" ]; then + return 1 + fi + + # Check if IP is in whitelist + echo "$FP_WHITELIST_IPS" | grep -q "\b$ip\b" + return $? +} + +is_ignored_user() { + local user=$1 + + if [ -z "$FP_IGNORE_USERS" ]; then + return 1 + fi + + # Check if user is in ignore list + echo "$FP_IGNORE_USERS" | grep -q "\b$user\b" + return $? +} + +is_safe_time_window() { + local current_day=$(date +%a) # Mon, Tue, Wed, etc. + local current_hour=$(date +%H) + local current_min=$(date +%M) + local current_time="$current_hour:$current_min" + + if [ -z "$FP_SAFE_TIME_WINDOWS" ]; then + return 1 + fi + + # Parse safe time windows: "Sun:02-04,*:03-03:30" + # Format: Day:StartHour-EndHour or *:StartTime-EndTime + IFS=',' read -ra WINDOWS <<< "$FP_SAFE_TIME_WINDOWS" + for window in "${WINDOWS[@]}"; do + local day_part=$(echo "$window" | cut -d: -f1) + local time_part=$(echo "$window" | cut -d: -f2) + + # Check day match (* = any day) + if [ "$day_part" = "*" ] || [ "$day_part" = "$current_day" ]; then + local start_time=$(echo "$time_part" | cut -d- -f1) + local end_time=$(echo "$time_part" | cut -d- -f2) + + # Simple hour comparison (could be enhanced for minutes) + local start_hour=$(echo "$start_time" | cut -d: -f1) + local end_hour=$(echo "$end_time" | cut -d: -f1) + + if [ "$current_hour" -ge "$start_hour" ] && [ "$current_hour" -le "$end_hour" ]; then + return 0 + fi + fi + done + + return 1 +} + +check_active_admin_session() { + local hours_ago=${1:-1} + + # Check if any admin is currently logged in via SSH + local active_sessions=$(w -h 2>/dev/null | awk '{print $1}' | sort -u) + + if [ -n "$active_sessions" ]; then + # Check if any active session is a whitelisted user or root + for session_user in $active_sessions; do + if [ "$session_user" = "root" ] || is_whitelisted_user "$session_user"; then + echo "active_admin_session:$session_user" + return 0 + fi + done + fi + + # Check recent SSH logins in /var/log/secure + if [ -f /var/log/secure ]; then + local recent_admin=$(awk -v hours="$hours_ago" ' + BEGIN { + cmd = "date -d \"" hours " hours ago\" +%s" + cmd | getline threshold + close(cmd) + } + /sshd.*Accepted/ && /root/ { + timestamp = $1 " " $2 " " $3 + cmd = "date -d \"" timestamp "\" +%s 2>/dev/null" + cmd | getline epoch + close(cmd) + + if (epoch >= threshold) { + print "recent_admin_login:root" + exit + } + } + ' /var/log/secure 2>/dev/null) + + if [ -n "$recent_admin" ]; then + echo "$recent_admin" + return 0 + fi + fi + + echo "none" + return 1 +} + +get_account_age_days() { + local user=$1 + + # Check home directory creation date as proxy for account age + if [ -d "/home/$user" ]; then + local home_created=$(stat -c %Y "/home/$user" 2>/dev/null) + if [ -n "$home_created" ]; then + local age_seconds=$(( $(date +%s) - home_created )) + local age_days=$(( age_seconds / 86400 )) + echo "$age_days" + return 0 + fi + fi + + # Fallback: Check /etc/passwd modification (less accurate) + local passwd_age=$(( $(date +%s) - $(stat -c %Y /etc/passwd 2>/dev/null) )) + local passwd_days=$(( passwd_age / 86400 )) + echo "$passwd_days" + return 0 +} + +check_who_made_change() { + local file=$1 + local hours_ago=${2:-24} + + # Check audit logs for who modified the file + if [ -f /var/log/audit/audit.log ]; then + local audit_user=$(ausearch -f "$file" -ts recent 2>/dev/null | grep -oP 'acct="\K[^"]+' | head -1) + if [ -n "$audit_user" ]; then + echo "$audit_user" + return 0 + fi + fi + + # Fallback: Check /var/log/secure for context + local secure_context=$(tail -1000 /var/log/secure 2>/dev/null | grep -E "useradd|usermod|passwd|chage" | tail -1 | awk '{print $5}' | cut -d'[' -f1) + if [ -n "$secure_context" ]; then + echo "$secure_context" + return 0 + fi + + echo "unknown" + return 1 +} + # # COMPROMISE DETECTION - Check for actual root compromise indicators # @@ -1063,35 +1233,80 @@ check_recent_password_changes() { local pw_count=$(echo "$recent_pw_changes" | wc -l) local pw_users=$(echo "$recent_pw_changes" | cut -d: -f1 | tr '\n' ',' | sed 's/,$//') + # FALSE POSITIVE REDUCTION: Filter out whitelisted users + local filtered_users="" + local filtered_count=0 + for user in $(echo "$pw_users" | tr ',' ' '); do + if ! is_whitelisted_user "$user" && ! is_ignored_user "$user"; then + filtered_users="${filtered_users}${user}," + filtered_count=$((filtered_count + 1)) + fi + done + filtered_users=${filtered_users%,} # Remove trailing comma + + # If all users are whitelisted, skip + if [ "$filtered_count" -eq 0 ]; then + details="${details}(all-whitelisted) " + echo "$risk|$findings$details" + return 0 + fi + + # Check if admin is actively logged in (reduce risk) + local admin_session=$(check_active_admin_session 1) + local admin_active=0 + if [ "$admin_session" != "none" ]; then + admin_active=1 + details="${details}[$admin_session] " + fi + + # Check if in safe time window (reduce risk) + local safe_window=0 + if is_safe_time_window; then + safe_window=1 + details="${details}[safe-window] " + fi + # FALSE POSITIVE REDUCTION: Check if this is mass change (more suspicious) - if [ "$pw_count" -lt "$FP_PASSWORD_CHANGE_THRESHOLD" ]; then + if [ "$filtered_count" -lt "$FP_PASSWORD_CHANGE_THRESHOLD" ]; then # Small number of password changes - likely legitimate # Only flag if root is included OR if outside business hours - if echo "$recent_pw_changes" | grep -q "^root:"; then + if echo "$filtered_users" | grep -q "root"; then findings="${findings}Root-Password-Changed " details="${details}(root) " - # Check if during business hours (less suspicious) - if [ "$FP_IGNORE_BUSINESS_HOURS" = "yes" ] && is_business_hours; then - risk=$((risk + 20)) # Lower risk during business hours - details="${details}[business-hours] " - else - risk=$((risk + 35)) - fi - elif [ "$pw_count" -eq 1 ]; then - # Single non-root password change - very low risk - risk=$((risk + 5)) - details="${details}Single-user:$pw_users " + # Calculate risk with context + local base_risk=35 + # Reduce if admin active + [ "$admin_active" -eq 1 ] && base_risk=$((base_risk - 15)) + # Reduce if business hours + [ "$FP_IGNORE_BUSINESS_HOURS" = "yes" ] && is_business_hours && base_risk=$((base_risk - 10)) + # Reduce if safe window + [ "$safe_window" -eq 1 ] && base_risk=$((base_risk - 10)) + + risk=$((risk + base_risk)) + elif [ "$filtered_count" -eq 1 ]; then + # Single non-root password change + local base_risk=5 + [ "$admin_active" -eq 1 ] && base_risk=2 + [ "$safe_window" -eq 1 ] && base_risk=2 + risk=$((risk + base_risk)) + details="${details}Single-user:$filtered_users " else - # 2-4 password changes, no root - medium-low risk - risk=$((risk + 10)) - details="${details}$pw_count-users:$pw_users " + # 2-4 password changes, no root + local base_risk=10 + [ "$admin_active" -eq 1 ] && base_risk=5 + [ "$safe_window" -eq 1 ] && base_risk=5 + risk=$((risk + base_risk)) + details="${details}$filtered_count-users:$filtered_users " fi else # Mass password change (5+ accounts) - VERY suspicious - findings="${findings}Mass-Password-Changes:$pw_count-accounts " - details="${details}Users:$pw_users " - risk=$((risk + 45)) # High risk for mass changes + findings="${findings}Mass-Password-Changes:$filtered_count-accounts " + details="${details}Users:$filtered_users " + # Even with admin active, mass changes are suspicious + local base_risk=45 + [ "$admin_active" -eq 1 ] && base_risk=$((base_risk - 10)) + risk=$((risk + base_risk)) fi fi @@ -1148,20 +1363,50 @@ check_recent_user_changes() { done if [ -n "$new_users" ]; then + # FALSE POSITIVE REDUCTION: Filter out whitelisted/ignored users + local filtered_new_users="" + local filtered_new_count=0 + for user_entry in $new_users; do + local username=$(echo "$user_entry" | cut -d'(' -f1) + if ! is_whitelisted_user "$username" && ! is_ignored_user "$username"; then + filtered_new_users="${filtered_new_users}${user_entry} " + filtered_new_count=$((filtered_new_count + 1)) + fi + done + + # If all users are whitelisted, skip + if [ "$filtered_new_count" -eq 0 ]; then + return 0 + fi + # FALSE POSITIVE REDUCTION: Check if cPanel account creation local cpanel_activity=$(check_cpanel_account_creation 168) # 7 days - if [ "$cpanel_activity" = "cpanel_account_creation" ] && [ "$new_count" -le 3 ]; then + # Check if admin is actively logged in + local admin_session=$(check_active_admin_session 24) + local admin_active=0 + if [ "$admin_session" != "none" ]; then + admin_active=1 + fi + + if [ "$cpanel_activity" = "cpanel_account_creation" ] && [ "$filtered_new_count" -le 3 ]; then # Likely legitimate cPanel hosting account - findings="${findings}New-Users:$new_users[cpanel] " + findings="${findings}New-Users:$filtered_new_users[cpanel] " risk=$((risk + 5)) # Very low risk else # Not from cPanel or too many accounts - findings="${findings}Recently-Created-Users:$new_users " - if [ "$new_count" -eq 1 ]; then - risk=$((risk + 15)) # Single user, moderate risk + findings="${findings}Recently-Created-Users:$filtered_new_users " + if [ "$filtered_new_count" -eq 1 ]; then + # Single user creation + local base_risk=15 + [ "$admin_active" -eq 1 ] && base_risk=8 + is_business_hours && base_risk=$((base_risk - 3)) + risk=$((risk + base_risk)) else - risk=$((risk + 25)) # Multiple users, higher risk + # Multiple users + local base_risk=25 + [ "$admin_active" -eq 1 ] && base_risk=15 + risk=$((risk + base_risk)) fi fi fi @@ -1212,8 +1457,41 @@ check_backdoor_accounts() { ' /etc/passwd) if [ -n "$suspicious_users" ]; then - findings="${findings}Suspicious-Usernames:$(echo $suspicious_users | tr '\n' ',') " - risk=$((risk + 25)) + # Filter out whitelisted users + local filtered_suspicious="" + for user in $suspicious_users; do + if ! is_whitelisted_user "$user" && ! is_ignored_user "$user"; then + # Check account age - old accounts less suspicious + local account_age=$(get_account_age_days "$user") + if [ "$account_age" -lt "$FP_MIN_ACCOUNT_AGE_DAYS" ]; then + # New account with suspicious name - HIGH risk + filtered_suspicious="${filtered_suspicious}${user}(${account_age}d)," + elif [ "$account_age" -lt 365 ]; then + # Moderately old account - MEDIUM risk + filtered_suspicious="${filtered_suspicious}${user}(${account_age}d)," + # Lower risk for older accounts + fi + # Very old accounts (1+ year) with suspicious names ignored - likely legitimate + fi + done + + if [ -n "$filtered_suspicious" ]; then + findings="${findings}Suspicious-Usernames:${filtered_suspicious%,} " + # Risk based on newest account + local min_age=999 + for user in $suspicious_users; do + local age=$(get_account_age_days "$user") + [ "$age" -lt "$min_age" ] && min_age=$age + done + + if [ "$min_age" -lt 7 ]; then + risk=$((risk + 30)) # Very new suspicious account + elif [ "$min_age" -lt 30 ]; then + risk=$((risk + 20)) # Recent suspicious account + else + risk=$((risk + 10)) # Older but still flagged + fi + fi fi echo "$risk|$findings" @@ -1273,20 +1551,46 @@ check_system_file_tampering() { pkg_activity=$(check_package_manager_activity 24) fi + # Check if admin was active (reduce suspicion) + local admin_session=$(check_active_admin_session 24) + local admin_active=0 + if [ "$admin_session" != "none" ]; then + admin_active=1 + fi + + # Check if in safe time window + local safe_window=0 + if is_safe_time_window; then + safe_window=1 + fi + # Check /etc/passwd modification time (recent changes suspicious) local passwd_age=$(($(date +%s) - $(stat -c %Y /etc/passwd 2>/dev/null))) if [ "$passwd_age" -lt 86400 ]; then # Modified in last 24 hours local passwd_hours=$((passwd_age / 3600)) + # Build context string + local context="" + [ "$pkg_activity" != "none" ] && context="${context}$pkg_activity," + [ "$admin_active" -eq 1 ] && context="${context}admin-active," + [ "$safe_window" -eq 1 ] && context="${context}safe-window," + context=${context%,} # Remove trailing comma + + # Calculate risk + local base_risk=25 if [ "$pkg_activity" != "none" ]; then - # Package manager was active - likely legitimate - findings="${findings}/etc/passwd-Modified-${passwd_hours}h-ago[$pkg_activity] " - risk=$((risk + 5)) # Very low risk - else - # No package activity - more suspicious - findings="${findings}/etc/passwd-Modified-${passwd_hours}h-ago " - risk=$((risk + 25)) + base_risk=5 # Package manager activity + elif [ "$admin_active" -eq 1 ]; then + base_risk=12 # Admin was logged in fi + [ "$safe_window" -eq 1 ] && base_risk=$((base_risk / 2)) + + if [ -n "$context" ]; then + findings="${findings}/etc/passwd-Modified-${passwd_hours}h-ago[$context] " + else + findings="${findings}/etc/passwd-Modified-${passwd_hours}h-ago " + fi + risk=$((risk + base_risk)) fi # Check /etc/shadow modification time @@ -1294,13 +1598,20 @@ check_system_file_tampering() { if [ "$shadow_age" -lt 86400 ]; then local shadow_hours=$((shadow_age / 3600)) + local base_risk=25 if [ "$pkg_activity" != "none" ]; then - findings="${findings}/etc/shadow-Modified-${shadow_hours}h-ago[$pkg_activity] " - risk=$((risk + 5)) + base_risk=5 + elif [ "$admin_active" -eq 1 ]; then + base_risk=12 + fi + [ "$safe_window" -eq 1 ] && base_risk=$((base_risk / 2)) + + if [ -n "$context" ]; then + findings="${findings}/etc/shadow-Modified-${shadow_hours}h-ago[$context] " else findings="${findings}/etc/shadow-Modified-${shadow_hours}h-ago " - risk=$((risk + 25)) fi + risk=$((risk + base_risk)) fi # Check /etc/group modification time @@ -1308,13 +1619,20 @@ check_system_file_tampering() { if [ "$group_age" -lt 86400 ]; then local group_hours=$((group_age / 3600)) + local base_risk=20 if [ "$pkg_activity" != "none" ]; then - findings="${findings}/etc/group-Modified-${group_hours}h-ago[$pkg_activity] " - risk=$((risk + 3)) + base_risk=3 + elif [ "$admin_active" -eq 1 ]; then + base_risk=10 + fi + [ "$safe_window" -eq 1 ] && base_risk=$((base_risk / 2)) + + if [ -n "$context" ]; then + findings="${findings}/etc/group-Modified-${group_hours}h-ago[$context] " else findings="${findings}/etc/group-Modified-${group_hours}h-ago " - risk=$((risk + 20)) fi + risk=$((risk + base_risk)) fi # Check /etc/gshadow modification time @@ -1323,13 +1641,20 @@ check_system_file_tampering() { if [ "$gshadow_age" -lt 86400 ]; then local gshadow_hours=$((gshadow_age / 3600)) + local base_risk=20 if [ "$pkg_activity" != "none" ]; then - findings="${findings}/etc/gshadow-Modified-${gshadow_hours}h-ago[$pkg_activity] " - risk=$((risk + 3)) + base_risk=3 + elif [ "$admin_active" -eq 1 ]; then + base_risk=10 + fi + [ "$safe_window" -eq 1 ] && base_risk=$((base_risk / 2)) + + if [ -n "$context" ]; then + findings="${findings}/etc/gshadow-Modified-${gshadow_hours}h-ago[$context] " else findings="${findings}/etc/gshadow-Modified-${gshadow_hours}h-ago " - risk=$((risk + 20)) fi + risk=$((risk + base_risk)) fi fi