digital forensics

Analyzing Linux System Artifacts

Examine Linux system artifacts including auth logs, cron jobs, shell history, and system configuration to uncover evidence of compromise or unauthorized activity.

forensicsincident-investigationlinux-forensicslog-analysispersistence-detectionsystem-artifacts
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

When to Use

  • When investigating a compromised Linux server or workstation
  • For identifying persistence mechanisms (cron, systemd, SSH keys)
  • When tracing user activity through shell history and authentication logs
  • During incident response to determine the scope of a Linux-based breach
  • For detecting rootkits, backdoors, and unauthorized modifications

Prerequisites

  • Forensic image or live access to the Linux system (read-only)
  • Understanding of Linux file system hierarchy (FHS)
  • Knowledge of common Linux logging locations (/var/log/)
  • Tools: chkrootkit, rkhunter, AIDE, auditd logs
  • Familiarity with systemd, cron, and PAM configurations
  • Root access for complete artifact collection

Workflow

Step 1: Mount and Collect System Artifacts

# Mount forensic image read-only
mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/linux_evidence.dd /mnt/evidence
 
# Create collection directories
mkdir -p /cases/case-2024-001/linux/{logs,config,users,persistence,network}
 
# Collect authentication logs
cp /mnt/evidence/var/log/auth.log* /cases/case-2024-001/linux/logs/
cp /mnt/evidence/var/log/secure* /cases/case-2024-001/linux/logs/
cp /mnt/evidence/var/log/syslog* /cases/case-2024-001/linux/logs/
cp /mnt/evidence/var/log/kern.log* /cases/case-2024-001/linux/logs/
cp /mnt/evidence/var/log/audit/audit.log* /cases/case-2024-001/linux/logs/
cp /mnt/evidence/var/log/wtmp /cases/case-2024-001/linux/logs/
cp /mnt/evidence/var/log/btmp /cases/case-2024-001/linux/logs/
cp /mnt/evidence/var/log/lastlog /cases/case-2024-001/linux/logs/
cp /mnt/evidence/var/log/faillog /cases/case-2024-001/linux/logs/
 
# Collect user artifacts
for user_dir in /mnt/evidence/home/*/; do
    username=$(basename "$user_dir")
    mkdir -p /cases/case-2024-001/linux/users/$username
    cp "$user_dir"/.bash_history /cases/case-2024-001/linux/users/$username/ 2>/dev/null
    cp "$user_dir"/.zsh_history /cases/case-2024-001/linux/users/$username/ 2>/dev/null
    cp -r "$user_dir"/.ssh/ /cases/case-2024-001/linux/users/$username/ 2>/dev/null
    cp "$user_dir"/.bashrc /cases/case-2024-001/linux/users/$username/ 2>/dev/null
    cp "$user_dir"/.profile /cases/case-2024-001/linux/users/$username/ 2>/dev/null
    cp "$user_dir"/.viminfo /cases/case-2024-001/linux/users/$username/ 2>/dev/null
    cp "$user_dir"/.wget-hsts /cases/case-2024-001/linux/users/$username/ 2>/dev/null
    cp "$user_dir"/.python_history /cases/case-2024-001/linux/users/$username/ 2>/dev/null
done
 
# Collect root user artifacts
cp /mnt/evidence/root/.bash_history /cases/case-2024-001/linux/users/root/ 2>/dev/null
cp -r /mnt/evidence/root/.ssh/ /cases/case-2024-001/linux/users/root/ 2>/dev/null
 
# Collect system configuration
cp /mnt/evidence/etc/passwd /cases/case-2024-001/linux/config/
cp /mnt/evidence/etc/shadow /cases/case-2024-001/linux/config/
cp /mnt/evidence/etc/group /cases/case-2024-001/linux/config/
cp /mnt/evidence/etc/sudoers /cases/case-2024-001/linux/config/
cp -r /mnt/evidence/etc/sudoers.d/ /cases/case-2024-001/linux/config/
cp /mnt/evidence/etc/hosts /cases/case-2024-001/linux/config/
cp /mnt/evidence/etc/resolv.conf /cases/case-2024-001/linux/config/
cp -r /mnt/evidence/etc/ssh/ /cases/case-2024-001/linux/config/

Step 2: Analyze User Accounts and Authentication

# Analyze user accounts for anomalies
python3 << 'PYEOF'
print("=== USER ACCOUNT ANALYSIS ===\n")
 
# Parse /etc/passwd
with open('/cases/case-2024-001/linux/config/passwd') as f:
    for line in f:
        parts = line.strip().split(':')
        if len(parts) >= 7:
            username, _, uid, gid, comment, home, shell = parts[0], parts[1], int(parts[2]), int(parts[3]), parts[4], parts[5], parts[6]
 
            # Flag accounts with UID 0 (root equivalent)
            if uid == 0 and username != 'root':
                print(f"  ALERT: UID 0 account: {username} (shell: {shell})")
 
            # Flag accounts with login shells that shouldn't have them
            if shell not in ('/bin/false', '/usr/sbin/nologin', '/bin/sync') and uid >= 1000:
                print(f"  User: {username} (UID:{uid}, Shell:{shell}, Home:{home})")
 
            # Flag system accounts with login shells
            if uid < 1000 and uid > 0 and shell in ('/bin/bash', '/bin/sh', '/bin/zsh'):
                print(f"  WARNING: System account with shell: {username} (UID:{uid}, Shell:{shell})")
 
# Parse /etc/shadow for account status
print("\n=== PASSWORD STATUS ===")
with open('/cases/case-2024-001/linux/config/shadow') as f:
    for line in f:
        parts = line.strip().split(':')
        if len(parts) >= 3:
            username = parts[0]
            pwd_hash = parts[1]
            last_change = parts[2]
 
            if pwd_hash and pwd_hash not in ('*', '!', '!!', ''):
                hash_type = 'Unknown'
                if pwd_hash.startswith('$6$'): hash_type = 'SHA-512'
                elif pwd_hash.startswith('$5$'): hash_type = 'SHA-256'
                elif pwd_hash.startswith('$y$'): hash_type = 'yescrypt'
                elif pwd_hash.startswith('$1$'): hash_type = 'MD5 (WEAK)'
                print(f"  {username}: {hash_type} hash, last changed: day {last_change}")
PYEOF
 
# Analyze login history
last -f /cases/case-2024-001/linux/logs/wtmp > /cases/case-2024-001/linux/analysis/login_history.txt
lastb -f /cases/case-2024-001/linux/logs/btmp > /cases/case-2024-001/linux/analysis/failed_logins.txt 2>/dev/null

Step 3: Examine Persistence Mechanisms

# Check cron jobs for all users
echo "=== CRON JOBS ===" > /cases/case-2024-001/linux/persistence/cron_analysis.txt
 
# System cron
for cronfile in /mnt/evidence/etc/crontab /mnt/evidence/etc/cron.d/*; do
    echo "--- $cronfile ---" >> /cases/case-2024-001/linux/persistence/cron_analysis.txt
    cat "$cronfile" 2>/dev/null >> /cases/case-2024-001/linux/persistence/cron_analysis.txt
    echo "" >> /cases/case-2024-001/linux/persistence/cron_analysis.txt
done
 
# User cron tabs
for cronfile in /mnt/evidence/var/spool/cron/crontabs/*; do
    echo "--- User crontab: $(basename $cronfile) ---" >> /cases/case-2024-001/linux/persistence/cron_analysis.txt
    cat "$cronfile" 2>/dev/null >> /cases/case-2024-001/linux/persistence/cron_analysis.txt
    echo "" >> /cases/case-2024-001/linux/persistence/cron_analysis.txt
done
 
# Check systemd services for persistence
echo "=== SYSTEMD SERVICES ===" > /cases/case-2024-001/linux/persistence/systemd_analysis.txt
find /mnt/evidence/etc/systemd/system/ -name "*.service" -newer /mnt/evidence/etc/os-release \
   >> /cases/case-2024-001/linux/persistence/systemd_analysis.txt
 
for svc in /mnt/evidence/etc/systemd/system/*.service; do
    echo "--- $(basename $svc) ---" >> /cases/case-2024-001/linux/persistence/systemd_analysis.txt
    cat "$svc" >> /cases/case-2024-001/linux/persistence/systemd_analysis.txt
    echo "" >> /cases/case-2024-001/linux/persistence/systemd_analysis.txt
done
 
# Check authorized SSH keys (backdoor detection)
echo "=== SSH AUTHORIZED KEYS ===" > /cases/case-2024-001/linux/persistence/ssh_keys.txt
find /mnt/evidence/home/ /mnt/evidence/root/ -name "authorized_keys" -exec sh -c \
   'echo "--- {} ---"; cat {}; echo ""' \; >> /cases/case-2024-001/linux/persistence/ssh_keys.txt
 
# Check rc.local and init scripts
cat /mnt/evidence/etc/rc.local 2>/dev/null > /cases/case-2024-001/linux/persistence/rc_local.txt
 
# Check /etc/profile.d/ for login-triggered scripts
ls -la /mnt/evidence/etc/profile.d/ > /cases/case-2024-001/linux/persistence/profile_scripts.txt
 
# Check for LD_PRELOAD hijacking
grep -r "LD_PRELOAD" /mnt/evidence/etc/ 2>/dev/null > /cases/case-2024-001/linux/persistence/ld_preload.txt
cat /mnt/evidence/etc/ld.so.preload 2>/dev/null >> /cases/case-2024-001/linux/persistence/ld_preload.txt

Step 4: Analyze Shell History and Command Execution

# Analyze bash history for each user
python3 << 'PYEOF'
import os, glob
 
print("=== SHELL HISTORY ANALYSIS ===\n")
 
suspicious_commands = [
    'wget', 'curl', 'nc ', 'ncat', 'netcat', 'python -c', 'python3 -c',
    'perl -e', 'base64', 'chmod 777', 'chmod +s', '/dev/tcp', '/dev/udp',
    'nmap', 'masscan', 'hydra', 'john', 'hashcat', 'passwd', 'useradd',
    'iptables -F', 'ufw disable', 'history -c', 'rm -rf /', 'dd if=',
    'crontab', 'at ', 'systemctl enable', 'ssh-keygen', 'scp ', 'rsync',
    'tar czf', 'zip -r', 'openssl enc', 'gpg --encrypt', 'shred',
    'chattr', 'setfacl', 'awk', '/tmp/', '/dev/shm/'
]
 
for hist_file in glob.glob('/cases/case-2024-001/linux/users/*/.bash_history'):
    username = hist_file.split('/')[-2]
    print(f"User: {username}")
 
    with open(hist_file, 'r', errors='ignore') as f:
        lines = f.readlines()
 
    print(f"  Total commands: {len(lines)}")
    flagged = []
    for i, line in enumerate(lines):
        line = line.strip()
        for cmd in suspicious_commands:
            if cmd in line.lower():
                flagged.append((i+1, line))
                break
 
    if flagged:
        print(f"  Suspicious commands: {len(flagged)}")
        for lineno, cmd in flagged:
            print(f"    Line {lineno}: {cmd[:120]}")
    print()
PYEOF

Step 5: Check for Rootkits and Modified Binaries

# Check for known rootkit indicators
# Compare system binary hashes against known-good
find /mnt/evidence/usr/bin/ /mnt/evidence/usr/sbin/ /mnt/evidence/bin/ /mnt/evidence/sbin/ \
   -type f -executable -exec sha256sum {} \; > /cases/case-2024-001/linux/analysis/binary_hashes.txt
 
# Check for SUID/SGID binaries (potential privilege escalation)
find /mnt/evidence/ -perm -4000 -type f 2>/dev/null > /cases/case-2024-001/linux/analysis/suid_files.txt
find /mnt/evidence/ -perm -2000 -type f 2>/dev/null > /cases/case-2024-001/linux/analysis/sgid_files.txt
 
# Check for suspicious files in /tmp and /dev/shm
find /mnt/evidence/tmp/ /mnt/evidence/dev/shm/ -type f 2>/dev/null \
   -exec file {} \; > /cases/case-2024-001/linux/analysis/tmp_files.txt
 
# Check for hidden files and directories
find /mnt/evidence/ -name ".*" -not -path "*/\." -type f 2>/dev/null | \
   head -100 > /cases/case-2024-001/linux/analysis/hidden_files.txt
 
# Check kernel modules
ls -la /mnt/evidence/lib/modules/$(ls /mnt/evidence/lib/modules/ | head -1)/extra/ 2>/dev/null \
   > /cases/case-2024-001/linux/analysis/extra_modules.txt
 
# Check for modified PAM configuration (authentication backdoors)
diff /mnt/evidence/etc/pam.d/ /cases/baseline/pam.d/ 2>/dev/null \
   > /cases/case-2024-001/linux/analysis/pam_changes.txt

Key Concepts

Concept Description
/var/log/auth.log Primary authentication log on Debian/Ubuntu systems
/var/log/secure Primary authentication log on RHEL/CentOS systems
wtmp/btmp Binary logs recording successful and failed login sessions
.bash_history User command history file (can be cleared by attackers)
crontab Scheduled task system commonly used for persistence
authorized_keys SSH public keys granting passwordless access to an account
SUID bit File permission allowing execution as the file owner (privilege escalation vector)
LD_PRELOAD Environment variable that loads a shared library before all others (hooking technique)

Tools & Systems

Tool Purpose
chkrootkit Rootkit detection scanner for Linux systems
rkhunter Rootkit Hunter - checks for rootkits, backdoors, and local exploits
AIDE Advanced Intrusion Detection Environment - file integrity monitor
auditd Linux audit framework for system call and file access monitoring
last/lastb Parse wtmp/btmp for login and failed login history
Plaso/log2timeline Super-timeline creation including Linux artifacts
osquery SQL-based system querying for live forensic investigation
Velociraptor Endpoint agent with Linux artifact collection capabilities

Common Scenarios

Scenario 1: SSH Brute Force Followed by Compromise Analyze auth.log for failed SSH attempts followed by success, identify the attacking IP, check .bash_history for post-compromise commands, examine authorized_keys for added backdoor keys, check crontab for persistence, review network connections.

Scenario 2: Web Server Compromise via Application Vulnerability Examine web server access and error logs for exploitation attempts, check /tmp and /dev/shm for webshells, analyze the web server user's activity (www-data), check for privilege escalation via SUID binaries or kernel exploits, review outbound connections.

Scenario 3: Insider Threat on Database Server Analyze the suspect user's bash_history for database dump commands, check for large tar/zip files in home directory or /tmp, examine scp/rsync commands for data transfer, review cron jobs for automated exfiltration, check USB device logs.

Scenario 4: Crypto-Miner on Cloud Instance Check for high-CPU processes in /proc (live) or systemd service files, examine crontab entries for miner restart scripts, check /tmp for mining binaries, analyze network connections for mining pool communications, review authorized_keys for attacker access.

Output Format

Linux Forensics Summary:
  System: webserver01 (Ubuntu 22.04 LTS)
  Hostname: webserver01.corp.local
  Kernel: 5.15.0-91-generic
 
  User Accounts:
    Total: 25 (3 with UID 0 - 1 ANOMALOUS)
    Interactive shells: 8 users
    Recently created: admin2 (created 2024-01-15)
 
  Authentication Events:
    Successful SSH logins: 456
    Failed SSH attempts: 12,345 (from 23 unique IPs)
    Sudo executions: 89
 
  Persistence Mechanisms Found:
    Cron jobs: 3 suspicious (reverse shell, miner restart)
    Systemd services: 1 unknown (update-checker.service)
    SSH keys: 2 unauthorized keys in root authorized_keys
    rc.local: Modified with download cradle
 
  Suspicious Activity:
    - bash_history contains wget to pastebin URL
    - SUID binary /tmp/.hidden/escalate found
    - /dev/shm/ contains compiled ELF binary
    - LD_PRELOAD in /etc/ld.so.preload pointing to /lib/.hidden.so
 
  Report: /cases/case-2024-001/linux/analysis/
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 1

api-reference.md3.4 KB

API Reference: Linux Forensic Artifact Analysis Tools

Key Artifact Locations

Artifact Path Description
Auth logs /var/log/auth.log (Debian) /var/log/secure (RHEL) Authentication events
Login history /var/log/wtmp Successful logins (binary, use last)
Failed logins /var/log/btmp Failed logins (binary, use lastb)
Bash history ~/.bash_history Command history per user
SSH keys ~/.ssh/authorized_keys Authorized public keys
Crontab /etc/crontab, /var/spool/cron/crontabs/ Scheduled tasks
Systemd services /etc/systemd/system/ Service definitions
LD_PRELOAD /etc/ld.so.preload Shared library preloading
SUID binaries find / -perm -4000 Setuid executables

last / lastb - Login History

Syntax

last -f /var/log/wtmp              # Successful logins
lastb -f /var/log/btmp             # Failed logins
last -i -f /var/log/wtmp           # Show IP addresses
last -s 2024-01-15 -t 2024-01-20  # Date range filter

Output Format

user     pts/0   192.168.1.50  Mon Jan 15 09:00  still logged in

chkrootkit - Rootkit Scanner

Syntax

chkrootkit                    # Full scan
chkrootkit -r /mnt/evidence   # Scan mounted evidence
chkrootkit -q                 # Quiet (infected only)

rkhunter - Rootkit Hunter

Syntax

rkhunter --check                    # Full system check
rkhunter --check --rootdir /mnt/ev  # Check evidence root
rkhunter --list tests               # List available tests
rkhunter --propupd                  # Update file properties DB

Check Categories

Check Description
rootkits Known rootkit signatures
trojans Trojanized system binaries
properties File permission anomalies
filesystem Hidden files and directories

auditd Log Parsing

ausearch Syntax

ausearch -m execve -ts recent         # Recent command execution
ausearch -m USER_AUTH -ts today        # Authentication events
ausearch -k suspicious_activity       # Custom audit rule key
ausearch -ua 0 -ts today              # Root user actions

aureport Syntax

aureport --auth                       # Authentication summary
aureport --login                      # Login summary
aureport --file                       # File access summary
aureport --summary                    # Overall summary

osquery - SQL-based System Queries

Syntax

osqueryi "SELECT * FROM users WHERE uid = 0"
osqueryi "SELECT * FROM crontab"
osqueryi "SELECT * FROM authorized_keys"
osqueryi "SELECT * FROM suid_bin"
osqueryi "SELECT * FROM process_open_sockets"

Key Tables

Table Content
users User account information
crontab Cron job entries
authorized_keys SSH authorized keys
suid_bin SUID binaries
process_open_sockets Network connections by process
shell_history Command history entries

Plaso / log2timeline - Super Timeline

Syntax

log2timeline.py /cases/timeline.plaso /mnt/evidence
psort.py -o l2tcsv /cases/timeline.plaso > timeline.csv
psort.py -o l2tcsv /cases/timeline.plaso "date > '2024-01-15'"

AIDE - File Integrity

Syntax

aide --init                    # Initialize database
aide --check                   # Check for changes
aide --compare                 # Compare databases

Scripts 1

agent.py9.7 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Linux system artifact forensics agent for investigating compromised systems."""

import os
import sys
import glob
import shlex
import subprocess


def run_cmd(cmd):
    """Execute a command and return output."""
    if isinstance(cmd, str):
        cmd = shlex.split(cmd)
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
    return result.stdout.strip(), result.stderr.strip(), result.returncode


def analyze_passwd(passwd_path):
    """Analyze /etc/passwd for suspicious accounts."""
    findings = []
    with open(passwd_path, "r") as f:
        for line in f:
            parts = line.strip().split(":")
            if len(parts) < 7:
                continue
            username, _, uid, gid = parts[0], parts[1], int(parts[2]), int(parts[3])
            home, shell = parts[5], parts[6]
            if uid == 0 and username != "root":
                findings.append({
                    "severity": "CRITICAL",
                    "finding": f"UID 0 account: {username} (shell: {shell})",
                })
            login_shells = ["/bin/bash", "/bin/sh", "/bin/zsh", "/usr/bin/zsh"]
            if uid < 1000 and uid > 0 and shell in login_shells:
                findings.append({
                    "severity": "WARNING",
                    "finding": f"System account with login shell: {username} (UID:{uid})",
                })
            if uid >= 1000 and shell not in ["/bin/false", "/usr/sbin/nologin", "/bin/sync"]:
                findings.append({
                    "severity": "INFO",
                    "finding": f"Interactive user: {username} (UID:{uid}, Home:{home})",
                })
    return findings


def analyze_shadow(shadow_path):
    """Analyze /etc/shadow for password hash types and status."""
    findings = []
    with open(shadow_path, "r") as f:
        for line in f:
            parts = line.strip().split(":")
            if len(parts) < 3:
                continue
            username = parts[0]
            pwd_hash = parts[1]
            if pwd_hash and pwd_hash not in ("*", "!", "!!", ""):
                hash_type = "Unknown"
                if pwd_hash.startswith("$6$"):
                    hash_type = "SHA-512"
                elif pwd_hash.startswith("$5$"):
                    hash_type = "SHA-256"
                elif pwd_hash.startswith("$y$"):
                    hash_type = "yescrypt"
                elif pwd_hash.startswith("$1$"):
                    hash_type = "MD5 (WEAK)"
                    findings.append({
                        "severity": "WARNING",
                        "finding": f"{username} uses weak MD5 password hash",
                    })
                findings.append({
                    "severity": "INFO",
                    "finding": f"{username}: {hash_type} hash, last changed day {parts[2]}",
                })
    return findings


def analyze_bash_history(history_path, username="unknown"):
    """Analyze bash history for suspicious commands."""
    suspicious_patterns = [
        "wget", "curl", "nc ", "ncat", "netcat", "python -c", "python3 -c",
        "perl -e", "base64", "chmod 777", "chmod +s", "/dev/tcp", "/dev/udp",
        "nmap", "masscan", "hydra", "john", "hashcat", "passwd", "useradd",
        "iptables -F", "ufw disable", "history -c", "rm -rf", "dd if=",
        "crontab", "systemctl enable", "ssh-keygen", "scp ", "rsync",
        "/tmp/", "/dev/shm/", "mkfifo", "socat",
    ]
    findings = []
    with open(history_path, "r", errors="ignore") as f:
        lines = f.readlines()
    for i, line in enumerate(lines):
        line_stripped = line.strip()
        for pattern in suspicious_patterns:
            if pattern in line_stripped.lower():
                findings.append({
                    "user": username,
                    "line_number": i + 1,
                    "command": line_stripped[:200],
                    "matched_pattern": pattern,
                })
                break
    return findings


def check_cron_persistence(evidence_root):
    """Check cron jobs for persistence mechanisms."""
    findings = []
    cron_paths = [
        os.path.join(evidence_root, "etc/crontab"),
        *glob.glob(os.path.join(evidence_root, "etc/cron.d/*")),
        *glob.glob(os.path.join(evidence_root, "var/spool/cron/crontabs/*")),
    ]
    for cron_path in cron_paths:
        if os.path.exists(cron_path) and os.path.isfile(cron_path):
            with open(cron_path, "r", errors="ignore") as f:
                for line in f:
                    line = line.strip()
                    if line and not line.startswith("#"):
                        suspicious = any(
                            p in line.lower()
                            for p in ["wget", "curl", "/tmp/", "/dev/shm/", "base64",
                                      "python", "bash -i", "reverse", "nc ", "ncat"]
                        )
                        if suspicious:
                            findings.append({
                                "severity": "HIGH",
                                "source": cron_path,
                                "entry": line[:200],
                            })
    return findings


def check_ssh_keys(evidence_root):
    """Check for unauthorized SSH authorized_keys."""
    findings = []
    key_files = glob.glob(
        os.path.join(evidence_root, "home/*/.ssh/authorized_keys")
    ) + glob.glob(
        os.path.join(evidence_root, "root/.ssh/authorized_keys")
    )
    for key_file in key_files:
        if os.path.exists(key_file):
            with open(key_file, "r") as f:
                keys = [l.strip() for l in f if l.strip() and not l.startswith("#")]
            if keys:
                findings.append({
                    "file": key_file,
                    "key_count": len(keys),
                    "keys": [k[:80] + "..." for k in keys],
                })
    return findings


def check_systemd_persistence(evidence_root):
    """Check for suspicious systemd service files."""
    findings = []
    service_dirs = [
        os.path.join(evidence_root, "etc/systemd/system"),
        os.path.join(evidence_root, "usr/lib/systemd/system"),
    ]
    for svc_dir in service_dirs:
        if not os.path.exists(svc_dir):
            continue
        for svc_file in glob.glob(os.path.join(svc_dir, "*.service")):
            with open(svc_file, "r", errors="ignore") as f:
                content = f.read()
            suspicious = any(
                p in content.lower()
                for p in ["/tmp/", "/dev/shm/", "wget", "curl", "reverse",
                          "bash -i", "nc ", "python", "base64"]
            )
            if suspicious:
                findings.append({
                    "severity": "HIGH",
                    "file": svc_file,
                    "preview": content[:300],
                })
    return findings


def check_ld_preload(evidence_root):
    """Check for LD_PRELOAD rootkit indicators."""
    findings = []
    preload_path = os.path.join(evidence_root, "etc/ld.so.preload")
    if os.path.exists(preload_path):
        with open(preload_path, "r") as f:
            content = f.read().strip()
        if content:
            findings.append({
                "severity": "CRITICAL",
                "finding": f"/etc/ld.so.preload contains: {content}",
            })
    return findings


def find_suid_binaries(evidence_root):
    """Find SUID/SGID binaries (potential privilege escalation)."""
    result = subprocess.run(
        ["find", evidence_root, "-perm", "-4000", "-type", "f"],
        capture_output=True, text=True, timeout=30
    )
    stdout = result.stdout.strip()
    return stdout.splitlines() if result.returncode == 0 and stdout else []


def find_suspicious_tmp_files(evidence_root):
    """Find suspicious files in /tmp and /dev/shm."""
    findings = []
    for tmp_dir in ["tmp", "dev/shm"]:
        full_path = os.path.join(evidence_root, tmp_dir)
        if os.path.exists(full_path):
            for root, dirs, files in os.walk(full_path):
                for fname in files:
                    fpath = os.path.join(root, fname)
                    findings.append(fpath)
    return findings


if __name__ == "__main__":
    print("=" * 60)
    print("Linux System Artifacts Forensics Agent")
    print("User accounts, persistence, shell history, rootkit detection")
    print("=" * 60)

    evidence_root = sys.argv[1] if len(sys.argv) > 1 else "/mnt/evidence"

    if os.path.exists(evidence_root):
        print(f"\n[*] Examining evidence root: {evidence_root}")

        passwd_path = os.path.join(evidence_root, "etc/passwd")
        if os.path.exists(passwd_path):
            print("\n--- User Account Analysis ---")
            for f in analyze_passwd(passwd_path):
                print(f"  [{f['severity']}] {f['finding']}")

        print("\n--- Cron Persistence ---")
        cron = check_cron_persistence(evidence_root)
        for c in cron:
            print(f"  [{c['severity']}] {c['source']}: {c['entry'][:80]}")

        print("\n--- SSH Authorized Keys ---")
        ssh = check_ssh_keys(evidence_root)
        for s in ssh:
            print(f"  {s['file']}: {s['key_count']} keys")

        print("\n--- Systemd Persistence ---")
        systemd = check_systemd_persistence(evidence_root)
        for s in systemd:
            print(f"  [{s['severity']}] {s['file']}")

        print("\n--- LD_PRELOAD Rootkit Check ---")
        ld = check_ld_preload(evidence_root)
        for l in ld:
            print(f"  [{l['severity']}] {l['finding']}")

        print("\n--- Suspicious Temp Files ---")
        tmp = find_suspicious_tmp_files(evidence_root)
        for t in tmp[:20]:
            print(f"  {t}")
    else:
        print(f"\n[DEMO] Usage: python agent.py <evidence_mount_point>")
        print("[*] Mount a forensic image and provide the path for analysis.")
Keep exploring