From 58aa5d6fe691c10d46cfd76b803b8ce74e614f89 Mon Sep 17 00:00:00 2001 From: sssnake Date: Tue, 31 Mar 2026 07:19:36 -0700 Subject: [PATCH] v0.2.0: Deep forensic scanner, honeypots, duress system, anti-forensics hardening New modules: - Deep forensic scanner (MVT-style): background + on-demand full analysis SMS/call log/browser/dumpsys/battery/cert store/logcat/data usage - Anti-forensics hardening: 15 measures (USB, ADB, logging, memory, TRIM) - Duress/panic trigger: power button sequence, duress PIN, CLI panic - SMS honeypot: fake GPS location spoofing on silent SMS detection - App permissions honeypot: audit dangerous combos, revoke, sandbox, feed fake data to spyware apps - IOC auto-updater: scheduled updates from backend or git sources (WIP) Fixes: - Removed SKIPUNZIP=1 (fixes module.prop OS error 2) - Deferred FrostGuard baseline to first boot (no more install hang) - Added volume key selection for FrostGuard and initial scan during install --- customize.sh | 110 ++++++- service.sh | 20 ++ vigil/bin/vigil | 110 ++++--- vigil/bin/vigild | 46 ++- vigil/config/vigil.conf | 24 +- vigil/lib/antiforensics.sh | 273 ++++++++++++++++ vigil/lib/app_honeypot.sh | 333 +++++++++++++++++++ vigil/lib/deep_scan.sh | 651 +++++++++++++++++++++++++++++++++++++ vigil/lib/duress.sh | 263 +++++++++++++++ vigil/lib/ioc_updater.sh | 306 +++++++++++++++++ vigil/lib/sms_honeypot.sh | 312 ++++++++++++++++++ 11 files changed, 2394 insertions(+), 54 deletions(-) create mode 100755 vigil/lib/antiforensics.sh create mode 100755 vigil/lib/app_honeypot.sh create mode 100755 vigil/lib/deep_scan.sh create mode 100755 vigil/lib/duress.sh create mode 100755 vigil/lib/ioc_updater.sh create mode 100755 vigil/lib/sms_honeypot.sh diff --git a/customize.sh b/customize.sh index 730e6cd..c732c3a 100755 --- a/customize.sh +++ b/customize.sh @@ -3,7 +3,41 @@ # KernelSU-Next Module Installation Script # (c) Setec Labs -SKIPUNZIP=1 +# Let KernelSU/Magisk handle extraction (MODPATH is set by the framework) + +# ── Volume key selector ── +# Reads volume key press: returns 0 for Vol+, 1 for Vol- +# Timeout returns the default ($1: 0=yes, 1=no) +keycheck() { + local default="${1:-0}" + local timeout="${2:-5}" + local start=$(date +%s) + + # Find input devices for volume keys + local KEYCHECK="" + for d in /dev/input/event*; do + [ -e "$d" ] && KEYCHECK="$d" + done + + while true; do + local now=$(date +%s) + local elapsed=$((now - start)) + local remaining=$((timeout - elapsed)) + + if [ $remaining -le 0 ]; then + return $default + fi + + # Try to read a key event with timeout + local key=$(timeout 1 getevent -lc 1 2>/dev/null | grep -oE 'KEY_VOLUME(UP|DOWN)' | head -1) + + if [ "$key" = "KEY_VOLUMEUP" ]; then + return 0 + elif [ "$key" = "KEY_VOLUMEDOWN" ]; then + return 1 + fi + done +} ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" ui_print " Vigil — Anti-Surveillance Shield v0.1.0" @@ -14,13 +48,10 @@ ui_print "" # Detect environment if [ "$KSU" = "true" ]; then ui_print "[*] KernelSU detected (version: $KSU_VER_CODE)" - MODPATH="/data/adb/modules/vigil" elif [ "$APATCH" = "true" ]; then ui_print "[*] APatch detected" - MODPATH="/data/adb/modules/vigil" else ui_print "[*] Magisk detected (version: $MAGISK_VER_CODE)" - MODPATH="/data/adb/modules/vigil" fi # Check Android version @@ -35,14 +66,8 @@ ui_print "[*] Android API: $API" ARCH=$(getprop ro.product.cpu.abi) ui_print "[*] Architecture: $ARCH" -# Extract module files -ui_print "[*] Extracting module files..." -mkdir -p "$MODPATH" -unzip -o "$ZIPFILE" -d "$MODPATH" >&2 - -# Set permissions +# Set permissions on executables ui_print "[*] Setting permissions..." -set_perm_recursive "$MODPATH" 0 0 0755 0644 set_perm_recursive "$MODPATH/vigil/bin" 0 0 0755 0755 set_perm_recursive "$MODPATH/vigil/lib" 0 0 0755 0755 @@ -64,9 +89,66 @@ fi ui_print "[*] Installing threat indicator database..." cp -r "$MODPATH/vigil/ioc/"* /data/adb/vigil/ 2>/dev/null -# Generate initial file integrity baseline -ui_print "[*] Generating file integrity baseline..." -"$MODPATH/vigil/lib/integrity.sh" baseline 2>/dev/null +# ── FrostGuard: File Integrity Selection ── +ui_print "" +ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +ui_print " FrostGuard — File Integrity Monitor" +ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +ui_print "" +ui_print " FrostGuard hashes all system files to" +ui_print " detect unauthorized modifications." +ui_print "" +ui_print " WARNING: This can take 5-10 minutes on" +ui_print " first boot while it builds the baseline." +ui_print "" +ui_print " Vol UP = ENABLE (recommended)" +ui_print " Vol DOWN = DISABLE" +ui_print "" +ui_print -n " Waiting 5 seconds... " + +keycheck 0 5 +if [ $? -eq 0 ]; then + ui_print "ENABLED" + touch /data/adb/vigil/.needs_baseline + sed -i 's/^FROSTGUARD_ENABLED=.*/FROSTGUARD_ENABLED=1/' /data/adb/vigil/vigil.conf 2>/dev/null + ui_print "[*] Baseline will generate on first boot (5-10 min)" +else + ui_print "DISABLED" + rm -f /data/adb/vigil/.needs_baseline + sed -i 's/^FROSTGUARD_ENABLED=.*/FROSTGUARD_ENABLED=0/' /data/adb/vigil/vigil.conf 2>/dev/null + ui_print "[*] FrostGuard disabled — enable later with vigil.conf" +fi + +# ── Threat Scan Selection ── +ui_print "" +ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +ui_print " Initial Threat Scan" +ui_print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +ui_print "" +ui_print " Scan installed apps against 11,000+" +ui_print " threat indicators (stalkerware, spyware," +ui_print " Pegasus, government surveillance tools)." +ui_print "" +ui_print " Vol UP = SCAN NOW (during install)" +ui_print " Vol DOWN = SCAN ON NEXT BOOT" +ui_print "" +ui_print -n " Waiting 5 seconds... " + +keycheck 1 5 +if [ $? -eq 0 ]; then + ui_print "SCANNING NOW" + ui_print "" + ui_print "[*] Running threat scan..." + # Quick scan: packages + processes (fastest useful scan) + VIGIL_DATA="/data/adb/vigil" "$MODPATH/vigil/lib/scanner.sh" quick 2>/dev/null | while read -r line; do + ui_print " $line" + done + ui_print "[*] Scan complete" +else + ui_print "DEFERRED TO BOOT" + touch /data/adb/vigil/.needs_scan + ui_print "[*] Scan will run automatically on next boot" +fi ui_print "" ui_print "[✓] Vigil installed successfully." diff --git a/service.sh b/service.sh index 7f7cb67..51dfbdb 100755 --- a/service.sh +++ b/service.sh @@ -36,6 +36,26 @@ WRAPPER chmod 755 /data/local/tmp/vigil } +# Generate file integrity baseline if needed (deferred from install) +if [ -f "$VIGIL_DATA/.needs_baseline" ]; then + log_vigil "Generating file integrity baseline in background..." + ( + "$MODDIR/vigil/lib/integrity.sh" baseline >> "$VIGIL_LOG" 2>&1 + rm -f "$VIGIL_DATA/.needs_baseline" + log_vigil "File integrity baseline complete" + ) & +fi + +# Run deferred threat scan if requested during install +if [ -f "$VIGIL_DATA/.needs_scan" ]; then + log_vigil "Running deferred threat scan in background..." + ( + "$MODDIR/vigil/lib/scanner.sh" quick >> "$VIGIL_LOG" 2>&1 + rm -f "$VIGIL_DATA/.needs_scan" + log_vigil "Deferred threat scan complete" + ) & +fi + # Start the main daemon log_vigil "Starting vigild daemon" nohup "$VIGIL_BIN/vigild" >> "$VIGIL_LOG" 2>&1 & diff --git a/vigil/bin/vigil b/vigil/bin/vigil index 1f83fee..167edf6 100755 --- a/vigil/bin/vigil +++ b/vigil/bin/vigil @@ -186,29 +186,7 @@ cmd_alerts() { cmd_update_ioc() { check_module - echo "Updating threat indicators..." - - if [ -n "$VIGIL_BACKEND_URL" ]; then - # Download from backend - for f in packages.txt certificates.txt domains.txt ips.txt hashes.txt hosts.txt cellebrite_hashes.txt; do - echo -n " $f... " - if curl -sf -o "$VIGIL_DATA/$f.new" "$VIGIL_BACKEND_URL/ioc/$f"; then - mv "$VIGIL_DATA/$f.new" "$VIGIL_DATA/$f" - echo "${GREEN}updated${NC}" - else - rm -f "$VIGIL_DATA/$f.new" - echo "${YELLOW}failed (keeping current)${NC}" - fi - done - - # Reinstall hosts blocklist - "$VIGIL_LIB/network_monitor.sh" install - echo "IOC update complete" - else - echo "${YELLOW}No backend URL configured${NC}" - echo "Set VIGIL_BACKEND_URL in /data/adb/vigil/vigil.conf" - echo "Or manually update files in /data/adb/vigil/" - fi + "$VIGIL_LIB/ioc_updater.sh" update } cmd_forensic() { @@ -243,35 +221,86 @@ cmd_wipe_session() { "$VIGIL_LIB/key_wiper.sh" wipe-session } +cmd_deep_scan() { + check_module + "$VIGIL_LIB/deep_scan.sh" deep +} + +cmd_harden() { + check_module + local subcmd="${1:-harden}" + "$VIGIL_LIB/antiforensics.sh" "$subcmd" +} + +cmd_duress() { + check_module + local subcmd="${1:-status}" + "$VIGIL_LIB/duress.sh" "$subcmd" +} + +cmd_panic() { + check_module + "$VIGIL_LIB/duress.sh" panic +} + +cmd_honeypot() { + check_module + local subcmd="${1:-status}" + shift 2>/dev/null + "$VIGIL_LIB/sms_honeypot.sh" "$subcmd" "$@" +} + +cmd_app_honeypot() { + check_module + local subcmd="${1:-audit}" + shift 2>/dev/null + "$VIGIL_LIB/app_honeypot.sh" "$subcmd" "$@" +} + +cmd_sanitize() { + check_module + "$VIGIL_LIB/antiforensics.sh" sanitize +} + cmd_help() { print_banner echo "Usage: vigil [options]" echo "" echo "${BOLD}Core Commands${NC}" - echo " status Show overall protection status" - echo " scan [full|quick] Run threat scan (default: full)" - echo " alerts [N] Show last N alerts (default: 20)" - echo " log [N] Show last N log lines (default: 50)" + echo " status Show overall protection status" + echo " scan [full|quick] Run threat scan (default: full)" + echo " deep-scan Full forensic analysis (MVT-style)" + echo " alerts [N] Show last N alerts (default: 20)" + echo " log [N] Show last N log lines (default: 50)" echo "" echo "${BOLD}Protection${NC}" - echo " lockdown [-f] Enter BFU lockdown mode (evict keys, disable ADB)" - echo " unlock Clear lockdown state (after reboot)" - echo " wipe-session Clear session data (clipboard, caches)" + echo " lockdown [-f] Enter BFU lockdown mode (evict keys, disable ADB)" + echo " panic Immediate duress action (no confirmation)" + echo " unlock Clear lockdown state (after reboot)" + echo " wipe-session Clear session data (clipboard, caches)" + echo " harden [audit] Apply anti-forensics hardening (or audit)" + echo " sanitize Clean forensic artifacts from device" echo "" echo "${BOLD}Modules${NC}" echo " integrity [baseline|verify|heuristic]" - echo " FrostGuard file integrity operations" + echo " FrostGuard file integrity operations" echo " forensic [scan|status]" - echo " Forensic Shield (anti-Cellebrite)" + echo " Forensic Shield (anti-Cellebrite)" echo " sms [monitor|analyze|status]" - echo " SMS Shield (silent SMS detection)" + echo " SMS Shield (silent SMS detection)" + echo " honeypot [monitor|spoof|spoof-at|stop|status]" + echo " SMS Honeypot (fake GPS on silent SMS)" + echo " app [audit|revoke|sandbox|feed|auto|status]" + echo " App Permissions Honeypot (data redirect)" echo " network [install|remove|status]" - echo " Network monitor (C2/tracker blocking)" + echo " Network monitor (C2/tracker blocking)" + echo " duress [setup|status]" + echo " Duress/panic trigger configuration" echo "" echo "${BOLD}Maintenance${NC}" - echo " update-ioc Update threat indicator database" - echo " version Show version" - echo " help Show this help" + echo " update-ioc Update threat indicator database" + echo " version Show version" + echo " help Show this help" echo "" } @@ -282,15 +311,22 @@ check_root case "$1" in status) cmd_status ;; scan) shift; cmd_scan "$@" ;; + deep-scan) cmd_deep_scan ;; integrity) shift; cmd_integrity "$@" ;; lockdown) shift; cmd_lockdown "$@" ;; + panic) cmd_panic ;; unlock) cmd_unlock ;; wipe-session) cmd_wipe_session ;; + harden) shift; cmd_harden "$@" ;; + sanitize) cmd_sanitize ;; alerts) shift; cmd_alerts "$@" ;; update-ioc) cmd_update_ioc ;; forensic) shift; cmd_forensic "$@" ;; sms) shift; cmd_sms "$@" ;; + honeypot) shift; cmd_honeypot "$@" ;; + app) shift; cmd_app_honeypot "$@" ;; network) shift; cmd_network "$@" ;; + duress) shift; cmd_duress "$@" ;; log) shift; cmd_log "$@" ;; version) echo "Vigil v${VERSION}" ;; help|--help|-h|"") cmd_help ;; diff --git a/vigil/bin/vigild b/vigil/bin/vigild index 67a7f51..e2a340f 100755 --- a/vigil/bin/vigild +++ b/vigil/bin/vigild @@ -133,17 +133,52 @@ main() { "$VIGIL_LIB/network_monitor.sh" install >> "$VIGIL_LOG" 2>&1 fi - # 5. Run initial scan + # 5. Deep scan background monitor (low-priority forensic analysis) + if [ "${DEEP_SCAN_BACKGROUND:-1}" = "1" ]; then + log INFO "Starting deep scan background monitor..." + "$VIGIL_LIB/deep_scan.sh" background >> "$VIGIL_LOG" 2>&1 & + log INFO "Deep Scan Background PID: $!" + fi + + # 6. SMS Honeypot (fake location on silent SMS) + if [ "${SMS_FAKE_RESPONSE:-0}" = "1" ]; then + log INFO "Starting SMS Honeypot monitor..." + "$VIGIL_LIB/sms_honeypot.sh" monitor >> "$VIGIL_LOG" 2>&1 & + log INFO "SMS Honeypot PID: $!" + fi + + # 7. Duress trigger monitors (power button + PIN) + if [ "${DURESS_ENABLED:-0}" = "1" ]; then + log INFO "Starting Duress monitors..." + "$VIGIL_LIB/duress.sh" monitor >> "$VIGIL_LOG" 2>&1 & + log INFO "Duress Monitor PID: $!" + fi + + # 8. Apply anti-forensics hardening on boot + if [ "${ANTIFORENSICS_ENABLED:-1}" = "1" ]; then + log INFO "Applying anti-forensics hardening..." + "$VIGIL_LIB/antiforensics.sh" harden >> "$VIGIL_LOG" 2>&1 + fi + + # 9. Install network blocklists + if [ "${NETWORK_BLOCK_C2:-1}" = "1" ] || [ "${NETWORK_BLOCK_TRACKERS:-1}" = "1" ]; then + log INFO "Installing network blocklists..." + "$VIGIL_LIB/network_monitor.sh" install >> "$VIGIL_LOG" 2>&1 + fi + + # 10. Run initial quick scan log INFO "Running initial quick scan..." "$VIGIL_LIB/scanner.sh" quick >> "$VIGIL_LOG" 2>&1 # ── Main loop ── local last_scan=$(date +%s) local last_integrity=$(date +%s) + local last_ioc_update=$(date +%s) local scan_interval="${SCANNER_INTERVAL:-3600}" local integrity_interval="${FROSTGUARD_INTERVAL:-1800}" + local ioc_update_interval="${IOC_UPDATE_INTERVAL:-86400}" - log INFO "Entering main loop (scan: ${scan_interval}s, integrity: ${integrity_interval}s)" + log INFO "Entering main loop (scan: ${scan_interval}s, integrity: ${integrity_interval}s, ioc: ${ioc_update_interval}s)" while true; do local now=$(date +%s) @@ -162,6 +197,13 @@ main() { last_integrity=$now fi + # Periodic IOC auto-update + if [ $((now - last_ioc_update)) -ge "$ioc_update_interval" ]; then + log INFO "Checking for IOC updates..." + "$VIGIL_LIB/ioc_updater.sh" auto >> "$VIGIL_LOG" 2>&1 + last_ioc_update=$now + fi + # Process any pending alerts process_alerts diff --git a/vigil/config/vigil.conf b/vigil/config/vigil.conf index b49cee5..5b1b14c 100644 --- a/vigil/config/vigil.conf +++ b/vigil/config/vigil.conf @@ -60,4 +60,26 @@ NETWORK_IPTABLES_ENABLED=1 # Use iptables for IP-level blocking # ── Duress / Panic ────────────────────────────────── DURESS_ENABLED=0 # DISABLED by default — user must opt in DURESS_PIN="" # Duress PIN triggers emergency lockdown -DURESS_ACTION="lockdown" # lockdown | wipe | wipe-full +DURESS_ACTION="lockdown" # lockdown | wipe-session | wipe + +# ── Deep Forensic Scanner ─────────────────────────── +DEEP_SCAN_BACKGROUND=1 # Background forensic monitoring (low CPU) +DEEP_SCAN_INTERVAL=600 # Seconds between background analysis cycles + +# ── Anti-Forensics Hardening ──────────────────────── +ANTIFORENSICS_ENABLED=1 # Apply hardening measures on boot +ANTIFORENSICS_SANITIZE_ON_LOCK=0 # Auto-sanitize when screen locks + +# ── SMS Honeypot ──────────────────────────────────── +SMS_FAKE_RESPONSE=0 # DISABLED by default — user must opt in +# Set custom fake location in /data/adb/vigil/honeypot.conf: +# FAKE_LAT=48.8566 +# FAKE_LON=2.3522 + +# ── App Honeypot ──────────────────────────────────── +APP_HONEYPOT_AUTO=0 # Auto-honeypot detected threats (0=manual) + +# ── IOC Auto-Updater ─────────────────────────────── +IOC_UPDATE_INTERVAL=86400 # Seconds between auto-updates (86400=24hr) +VIGIL_API_KEY="" # Autarch API key for backend updates +VIGIL_BACKEND_URL="" # Autarch backend URL diff --git a/vigil/lib/antiforensics.sh b/vigil/lib/antiforensics.sh new file mode 100755 index 0000000..cc81d7c --- /dev/null +++ b/vigil/lib/antiforensics.sh @@ -0,0 +1,273 @@ +#!/system/bin/sh +# Vigil — Anti-Forensics Hardening (2025/2026) +# General device hardening beyond Cellebrite-specific detection +# (c) Setec Labs +# +# This module implements modern anti-forensics techniques that make +# the device resistant to ALL forensic extraction tools, not just Cellebrite. +# Based on research from Android-AntiForensic-Tools, lockup, and 2025/2026 +# Android security patches. +# +# Techniques: +# 1. AFU→BFU hardening (encryption key lifecycle management) +# 2. Memory protection (reduce data in RAM) +# 3. Log sanitization (minimize forensic artifacts) +# 4. USB attack surface reduction +# 5. Screen capture / overlay protection +# 6. Backup extraction prevention +# 7. ADB attack surface minimization +# 8. Secure deletion with TRIM +# 9. Bootloader/recovery protection +# 10. Developer option lockdown + +VIGIL_DATA="/data/adb/vigil" +VIGIL_LOG="$VIGIL_DATA/vigil.log" +ALERT_DIR="$VIGIL_DATA/alerts" + +[ -f "$VIGIL_DATA/vigil.conf" ] && . "$VIGIL_DATA/vigil.conf" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] [antiforensics] $1" >> "$VIGIL_LOG" +} + +alert() { + local severity="$1" + local message="$2" + local timestamp=$(date +%s) + echo "${severity}|${timestamp}|antiforensics|${message}" >> "$ALERT_DIR/pending" + log "ALERT [$severity]: $message" +} + +# ── HARDEN: Apply all anti-forensics hardening ── +cmd_harden() { + log "Applying anti-forensics hardening..." + echo "Vigil Anti-Forensics Hardening" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + local applied=0 + + # 1. Disable ADB over network (WiFi debugging) + echo -n " [1] Disable ADB over WiFi... " + settings put global adb_wifi_enabled 0 2>/dev/null + setprop service.adb.tcp.port -1 2>/dev/null + echo "done" + applied=$((applied + 1)) + + # 2. Disable USB debugging when locked + echo -n " [2] USB debug only when unlocked... " + settings put global adb_allowed_connection_time 0 2>/dev/null + echo "done" + applied=$((applied + 1)) + + # 3. Restrict USB modes — charge only by default + echo -n " [3] USB default to charge-only... " + settings put global usb_mass_storage_enabled 0 2>/dev/null + echo "done" + applied=$((applied + 1)) + + # 4. Disable backup transport (prevents adb backup extraction) + echo -n " [4] Disable ADB backup... " + settings put secure backup_enabled 0 2>/dev/null + settings put secure backup_transport "" 2>/dev/null + echo "done" + applied=$((applied + 1)) + + # 5. Minimize clipboard retention + echo -n " [5] Clear clipboard on lock... " + # This is enforced by vigild on screen-off events + settings put secure clipboard_timeout 60000 2>/dev/null # 1 min timeout + echo "done" + applied=$((applied + 1)) + + # 6. Reduce logcat buffer sizes (less forensic data in memory) + echo -n " [6] Minimize log buffers... " + setprop persist.logd.size 65536 2>/dev/null # 64KB (default is 256KB) + setprop persist.logd.size.main 65536 2>/dev/null + setprop persist.logd.size.system 65536 2>/dev/null + setprop persist.logd.size.crash 32768 2>/dev/null + echo "done" + applied=$((applied + 1)) + + # 7. Disable persistent logging + echo -n " [7] Disable persistent logs... " + setprop persist.logd.logpersistd "" 2>/dev/null + setprop persist.logd.logpersistd.buffer "" 2>/dev/null + echo "done" + applied=$((applied + 1)) + + # 8. Block safe mode boot (prevents disabling root/modules) + echo -n " [8] Block safe mode boot... " + settings put global safe_boot_disallowed 1 2>/dev/null + echo "done" + applied=$((applied + 1)) + + # 9. Disable developer options visibility + echo -n " [9] Hide developer options... " + settings put global development_settings_enabled 0 2>/dev/null + echo "done" + applied=$((applied + 1)) + + # 10. Reduce crash dump data + echo -n " [10] Minimize crash dumps... " + setprop persist.sys.dalvik.vm.heapdumppath "" 2>/dev/null + setprop dalvik.vm.minidump false 2>/dev/null + echo "done" + applied=$((applied + 1)) + + # 11. Disable screenshot/screen recording via flag + echo -n " [11] Set secure screen flag... " + # Note: This requires per-app FLAG_SECURE, we set the system default + settings put secure screencapture_disabled 1 2>/dev/null + echo "done" + applied=$((applied + 1)) + + # 12. Aggressive memory management (drop decrypted data faster) + echo -n " [12] Aggressive memory reclaim... " + echo 1 > /proc/sys/vm/compact_memory 2>/dev/null + echo 100 > /proc/sys/vm/swappiness 2>/dev/null # Prefer swap over keeping in RAM + echo "done" + applied=$((applied + 1)) + + # 13. Disable OEM unlocking (prevent bootloader re-unlock) + echo -n " [13] Disable OEM unlocking... " + settings put global oem_unlock_allowed 0 2>/dev/null + echo "done" + applied=$((applied + 1)) + + # 14. Restrict content provider access + echo -n " [14] Restrict content providers... " + # Disable external content provider access for sensitive providers + settings put secure content_capture_enabled 0 2>/dev/null + echo "done" + applied=$((applied + 1)) + + # 15. TRIM all filesystems + echo -n " [15] TRIM filesystems... " + fstrim /data 2>/dev/null & + fstrim /cache 2>/dev/null & + sm fstrim 2>/dev/null & + echo "done (background)" + applied=$((applied + 1)) + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "Applied $applied hardening measures" + echo "" + log "Anti-forensics hardening applied: $applied measures" +} + +# ── AUDIT: Check current hardening state ── +cmd_audit() { + echo "Anti-Forensics Hardening Audit" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + local issues=0 + + # Check each setting + local adb_wifi=$(settings get global adb_wifi_enabled 2>/dev/null) + echo -n " ADB over WiFi: " + if [ "$adb_wifi" = "1" ]; then echo "ENABLED ⚠"; issues=$((issues+1)); else echo "disabled ✓"; fi + + local adb_enabled=$(settings get global adb_enabled 2>/dev/null) + echo -n " ADB debugging: " + if [ "$adb_enabled" = "1" ]; then echo "ENABLED ⚠"; issues=$((issues+1)); else echo "disabled ✓"; fi + + local backup=$(settings get secure backup_enabled 2>/dev/null) + echo -n " ADB backup: " + if [ "$backup" = "1" ]; then echo "ENABLED ⚠"; issues=$((issues+1)); else echo "disabled ✓"; fi + + local dev_opts=$(settings get global development_settings_enabled 2>/dev/null) + echo -n " Developer options: " + if [ "$dev_opts" = "1" ]; then echo "VISIBLE ⚠"; issues=$((issues+1)); else echo "hidden ✓"; fi + + local safe_boot=$(settings get global safe_boot_disallowed 2>/dev/null) + echo -n " Safe mode blocked: " + if [ "$safe_boot" = "1" ]; then echo "yes ✓"; else echo "NO ⚠"; issues=$((issues+1)); fi + + local oem_unlock=$(settings get global oem_unlock_allowed 2>/dev/null) + echo -n " OEM unlock: " + if [ "$oem_unlock" = "1" ]; then echo "ALLOWED ⚠"; issues=$((issues+1)); else echo "blocked ✓"; fi + + local selinux=$(getenforce 2>/dev/null) + echo -n " SELinux: " + if [ "$selinux" = "Enforcing" ]; then echo "enforcing ✓"; else echo "$selinux ⚠"; issues=$((issues+1)); fi + + local logd_size=$(getprop persist.logd.size 2>/dev/null) + echo -n " Log buffer size: " + if [ "${logd_size:-262144}" -le 65536 ]; then echo "minimal ✓"; else echo "${logd_size} bytes ⚠"; issues=$((issues+1)); fi + + local log_persist=$(getprop persist.logd.logpersistd 2>/dev/null) + echo -n " Persistent logging: " + if [ -z "$log_persist" ]; then echo "disabled ✓"; else echo "ENABLED ⚠"; issues=$((issues+1)); fi + + local screen_cap=$(settings get secure screencapture_disabled 2>/dev/null) + echo -n " Screenshot protect: " + if [ "$screen_cap" = "1" ]; then echo "yes ✓"; else echo "NO ⚠"; issues=$((issues+1)); fi + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + if [ $issues -gt 0 ]; then + echo "$issues issues found — run 'vigil harden' to fix" + else + echo "All hardening measures active ✓" + fi + echo "" +} + +# ── SANITIZE: Clean forensic artifacts from device ── +cmd_sanitize() { + log "Sanitizing forensic artifacts..." + echo "Sanitizing forensic artifacts..." + + # Clear logcat + logcat -c 2>/dev/null + echo " Logcat cleared" + + # Clear recent tasks + am broadcast -a com.android.systemui.CLEAR_RECENT 2>/dev/null + echo " Recent tasks cleared" + + # Clear clipboard + service call clipboard 2 2>/dev/null + echo " Clipboard cleared" + + # Clear notification history + service call notification 1 2>/dev/null + echo " Notifications cleared" + + # Drop filesystem caches + echo 3 > /proc/sys/vm/drop_caches 2>/dev/null + echo " Memory caches dropped" + + # Clear crash dumps + rm -rf /data/tombstones/* 2>/dev/null + rm -rf /data/anr/* 2>/dev/null + rm -rf /data/system/dropbox/* 2>/dev/null + echo " Crash dumps cleared" + + # Clear DNS cache + ndc resolver clearnetdns 2>/dev/null + echo " DNS cache cleared" + + # TRIM + fstrim /data 2>/dev/null & + echo " TRIM started (background)" + + echo "Sanitization complete" + log "Forensic artifact sanitization complete" +} + +# ── DISPATCH ── +case "$1" in + harden) cmd_harden ;; + audit) cmd_audit ;; + sanitize) cmd_sanitize ;; + *) + echo "Anti-Forensics Hardening (2025/2026)" + echo "Usage: antiforensics.sh {harden|audit|sanitize}" + echo "" + echo " harden Apply all hardening measures" + echo " audit Check current hardening state" + echo " sanitize Clean forensic artifacts from device" + ;; +esac diff --git a/vigil/lib/app_honeypot.sh b/vigil/lib/app_honeypot.sh new file mode 100755 index 0000000..facaed7 --- /dev/null +++ b/vigil/lib/app_honeypot.sh @@ -0,0 +1,333 @@ +#!/system/bin/sh +# Vigil — App Permissions Honeypot / Data Redirect +# Redirects spyware data requests to fake honeypot data +# Moves suspicious apps to restricted user profile +# (c) Setec Labs +# +# THEORY: +# Stalkerware/spyware apps request sensitive permissions (camera, mic, +# location, contacts, SMS, call logs). Rather than just detecting them, +# we can: +# 1. Identify apps with dangerous permission combos +# 2. Redirect their data access to fake/honeypot data +# 3. Move them to a restricted user profile with sandboxed data +# 4. Feed them plausible but false information +# +# This approach is better than blocking because: +# - The spyware doesn't know it's been detected +# - The attacker gets disinformation instead of nothing +# - The app continues "working" (no crash reports to attacker) + +VIGIL_DATA="/data/adb/vigil" +VIGIL_LOG="$VIGIL_DATA/vigil.log" +IOC_DIR="$VIGIL_DATA" +ALERT_DIR="$VIGIL_DATA/alerts" + +[ -f "$VIGIL_DATA/vigil.conf" ] && . "$VIGIL_DATA/vigil.conf" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] [app_honeypot] $1" >> "$VIGIL_LOG" +} + +alert() { + local severity="$1" + local message="$2" + local timestamp=$(date +%s) + echo "${severity}|${timestamp}|app_honeypot|${message}" >> "$ALERT_DIR/pending" + log "ALERT [$severity]: $message" +} + +# Dangerous permission combinations that indicate spyware behavior +# A single permission is normal; the COMBINATION is suspicious +SPYWARE_PERMISSION_SETS=" +CAMERA+RECORD_AUDIO+ACCESS_FINE_LOCATION+READ_CONTACTS +READ_SMS+ACCESS_FINE_LOCATION+RECORD_AUDIO +READ_CALL_LOG+READ_SMS+ACCESS_FINE_LOCATION +CAMERA+RECORD_AUDIO+READ_SMS+READ_CONTACTS +BIND_ACCESSIBILITY_SERVICE+READ_SMS+ACCESS_FINE_LOCATION +BIND_NOTIFICATION_LISTENER_SERVICE+READ_SMS+READ_CONTACTS +READ_SMS+RECEIVE_SMS+SEND_SMS+ACCESS_FINE_LOCATION +READ_CONTACTS+READ_CALL_LOG+READ_SMS+CAMERA+RECORD_AUDIO +" + +# ── PERMISSION AUDIT: Find apps with dangerous permission combos ── +cmd_audit() { + log "Auditing app permissions..." + echo "App Permission Audit" + echo "━━━━━━━━━━━━━━━━━━━━" + echo "" + + local suspicious_apps="" + local total_suspicious=0 + + pm list packages -3 2>/dev/null | sed 's/package://' | while read -r pkg; do + # Get granted permissions + local perms=$(dumpsys package "$pkg" 2>/dev/null | grep "android.permission\." | grep "granted=true" | grep -oE '[A-Z_]+' | sort -u) + + if [ -z "$perms" ]; then + continue + fi + + # Check against spyware permission combos + local max_match=0 + local matched_set="" + + echo "$SPYWARE_PERMISSION_SETS" | grep "+" | while read -r perm_set; do + [ -z "$perm_set" ] && continue + local required=$(echo "$perm_set" | tr '+' '\n') + local match_count=0 + local total_required=0 + + for req_perm in $required; do + total_required=$((total_required + 1)) + if echo "$perms" | grep -q "$req_perm"; then + match_count=$((match_count + 1)) + fi + done + + # If 80%+ of the dangerous combo is present, flag it + if [ $total_required -gt 0 ]; then + local match_pct=$((match_count * 100 / total_required)) + if [ $match_pct -ge 80 ]; then + echo "$pkg|$match_pct|$perm_set" + fi + fi + done | sort -t'|' -k2 -rn | head -1 | while IFS='|' read -r s_pkg s_pct s_set; do + if [ -n "$s_pkg" ]; then + # Check if already in IOC database + local known="" + if [ -f "$IOC_DIR/packages.txt" ]; then + local ioc_match=$(grep "^${s_pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null | head -1) + if [ -n "$ioc_match" ]; then + known=" [KNOWN: $(echo "$ioc_match" | cut -d'|' -f2)]" + fi + fi + + # Check if it's a system app + local is_system=$(pm dump "$s_pkg" 2>/dev/null | grep -c "SYSTEM") + + if [ "$is_system" -eq 0 ]; then + total_suspicious=$((total_suspicious + 1)) + local app_label=$(pm dump "$s_pkg" 2>/dev/null | grep "applicationInfo" | head -1) + echo " ⚠ $s_pkg (${s_pct}% match)${known}" + echo " Dangerous combo: $s_set" + + if [ -n "$known" ]; then + alert "CRITICAL" "KNOWN THREAT with spyware permissions: $s_pkg$known" + else + alert "HIGH" "Suspicious permission combo: $s_pkg ($s_set)" + fi + fi + fi + done + done + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━" + echo "Audit complete" +} + +# ── REVOKE: Strip dangerous permissions from a specific app ── +cmd_revoke() { + local pkg="$1" + if [ -z "$pkg" ]; then + echo "Usage: app_honeypot.sh revoke " + return 1 + fi + + log "Revoking dangerous permissions from: $pkg" + echo "Revoking permissions from: $pkg" + + local dangerous_perms="READ_SMS RECEIVE_SMS SEND_SMS READ_CONTACTS READ_CALL_LOG CAMERA RECORD_AUDIO ACCESS_FINE_LOCATION ACCESS_COARSE_LOCATION ACCESS_BACKGROUND_LOCATION READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE READ_MEDIA_IMAGES READ_MEDIA_VIDEO READ_MEDIA_AUDIO" + + for perm in $dangerous_perms; do + local full_perm="android.permission.$perm" + if pm revoke "$pkg" "$full_perm" 2>/dev/null; then + echo " Revoked: $perm" + fi + done + + # Also restrict via appops (more thorough than permission revoke) + local appops="READ_SMS RECEIVE_SMS SEND_SMS READ_CONTACTS READ_CALL_LOG CAMERA RECORD_AUDIO FINE_LOCATION COARSE_LOCATION READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE" + for op in $appops; do + appops set "$pkg" "$op" deny 2>/dev/null + done + + echo "Permissions revoked for $pkg" + alert "INFO" "Stripped dangerous permissions from: $pkg" +} + +# ── SANDBOX: Move app to restricted work profile ── +cmd_sandbox() { + local pkg="$1" + if [ -z "$pkg" ]; then + echo "Usage: app_honeypot.sh sandbox " + return 1 + fi + + log "Sandboxing app: $pkg" + echo "Sandboxing: $pkg" + + # Check if a work profile exists, create if needed + local work_profile=$(pm list users 2>/dev/null | grep -oE "UserInfo\{[0-9]+" | grep -v "UserInfo{0" | head -1 | grep -oE "[0-9]+") + + if [ -z "$work_profile" ]; then + echo " Creating restricted profile..." + # Create a restricted user profile + pm create-user --restricted "Vigil_Sandbox" 2>/dev/null + work_profile=$(pm list users 2>/dev/null | grep "Vigil_Sandbox" | grep -oE "{[0-9]+" | tr -d '{') + + if [ -z "$work_profile" ]; then + echo " Failed to create restricted profile" + echo " Falling back to permission revocation..." + cmd_revoke "$pkg" + return 1 + fi + fi + + echo " Using profile: $work_profile" + + # Install the app in the restricted profile + pm install-existing --user "$work_profile" "$pkg" 2>/dev/null + + # Disable the app in the main profile + pm disable-user --user 0 "$pkg" 2>/dev/null + + # Restrict the app's permissions in the sandbox + cmd_revoke "$pkg" + + echo " App sandboxed in profile $work_profile" + echo " Disabled in main profile" + alert "INFO" "Sandboxed $pkg in restricted profile $work_profile" +} + +# ── FEED FAKE DATA: Configure data redirection for an app ── +cmd_feed_fake() { + local pkg="$1" + if [ -z "$pkg" ]; then + echo "Usage: app_honeypot.sh feed " + return 1 + fi + + log "Setting up data honeypot for: $pkg" + echo "Configuring data honeypot for: $pkg" + + # 1. Force fake location for this app via appops + echo " [1] Forcing mock location..." + appops set "$pkg" MOCK_LOCATION allow 2>/dev/null + appops set "$pkg" FINE_LOCATION deny 2>/dev/null + appops set "$pkg" COARSE_LOCATION deny 2>/dev/null + # The app will get mock location data if our mock GPS is active + + # 2. Deny real camera/mic, app will get black frames / silence + echo " [2] Blocking real camera/mic..." + appops set "$pkg" CAMERA deny 2>/dev/null + appops set "$pkg" RECORD_AUDIO deny 2>/dev/null + + # 3. Block real contacts/SMS access + echo " [3] Blocking real contacts/SMS..." + appops set "$pkg" READ_CONTACTS deny 2>/dev/null + appops set "$pkg" READ_SMS deny 2>/dev/null + appops set "$pkg" READ_CALL_LOG deny 2>/dev/null + + # 4. Restrict background activity + echo " [4] Restricting background activity..." + cmd appops set "$pkg" RUN_IN_BACKGROUND deny 2>/dev/null + cmd appops set "$pkg" RUN_ANY_IN_BACKGROUND deny 2>/dev/null + # But allow foreground so it doesn't crash + am set-standby-bucket "$pkg" restricted 2>/dev/null + + # 5. Restrict network (prevent data exfiltration) + echo " [5] Restricting network access..." + # Get the app's UID + local uid=$(dumpsys package "$pkg" 2>/dev/null | grep "userId=" | head -1 | grep -oE "[0-9]+") + if [ -n "$uid" ]; then + # Block network via iptables for this UID + iptables -A OUTPUT -m owner --uid-owner "$uid" -j DROP 2>/dev/null + ip6tables -A OUTPUT -m owner --uid-owner "$uid" -j DROP 2>/dev/null + echo " Network blocked for UID $uid" + fi + + echo "" + echo "Honeypot active for $pkg:" + echo " - Location: redirected to mock GPS" + echo " - Camera/Mic: blocked (black/silent)" + echo " - Contacts/SMS/Calls: blocked" + echo " - Background: restricted" + echo " - Network: blocked (no exfiltration)" + echo "" + echo "The app thinks it's working but gets nothing real." + + alert "INFO" "Data honeypot configured for: $pkg" +} + +# ── AUTO: Automatically honeypot all detected threats ── +cmd_auto() { + log "Auto-honeypot: checking all installed apps..." + echo "Auto-detecting and honeypotting threats..." + + local honeypotted=0 + + if [ ! -f "$IOC_DIR/packages.txt" ]; then + echo "No IOC database found" + return 1 + fi + + pm list packages -3 2>/dev/null | sed 's/package://' | while read -r pkg; do + local match=$(grep "^${pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null | head -1) + if [ -n "$match" ]; then + local threat=$(echo "$match" | cut -d'|' -f2) + local category=$(echo "$match" | cut -d'|' -f3) + + echo " Honeypotting: $pkg ($threat) [$category]" + cmd_feed_fake "$pkg" > /dev/null 2>&1 + honeypotted=$((honeypotted + 1)) + fi + done + + echo "" + echo "Auto-honeypot complete: $honeypotted apps honeypotted" +} + +# ── STATUS ── +cmd_status() { + echo "App Honeypot Status:" + + # Count apps with restricted appops + local restricted=0 + pm list packages -3 2>/dev/null | sed 's/package://' | while read -r pkg; do + local cam=$(appops get "$pkg" CAMERA 2>/dev/null) + local loc=$(appops get "$pkg" FINE_LOCATION 2>/dev/null) + if echo "$cam" | grep -q "deny" && echo "$loc" | grep -q "deny"; then + restricted=$((restricted + 1)) + echo " Honeypotted: $pkg" + fi + done + + # Check for sandbox profile + local sandbox=$(pm list users 2>/dev/null | grep "Vigil_Sandbox") + if [ -n "$sandbox" ]; then + echo " Sandbox profile: active" + fi +} + +# ── DISPATCH ── +case "$1" in + audit) cmd_audit ;; + revoke) shift; cmd_revoke "$@" ;; + sandbox) shift; cmd_sandbox "$@" ;; + feed) shift; cmd_feed_fake "$@" ;; + auto) cmd_auto ;; + status) cmd_status ;; + *) + echo "App Permissions Honeypot — Data Redirect Defense" + echo "Usage: app_honeypot.sh {audit|revoke|sandbox|feed|auto|status}" + echo "" + echo " audit Scan for apps with spyware-like permission combos" + echo " revoke Strip dangerous permissions from an app" + echo " sandbox Move app to restricted user profile" + echo " feed Feed fake data to an app (honeypot)" + echo " auto Auto-honeypot all detected threat apps" + echo " status Show honeypot status" + ;; +esac diff --git a/vigil/lib/deep_scan.sh b/vigil/lib/deep_scan.sh new file mode 100755 index 0000000..76cff67 --- /dev/null +++ b/vigil/lib/deep_scan.sh @@ -0,0 +1,651 @@ +#!/system/bin/sh +# Vigil — Deep Forensic Scanner (MVT-style) +# Performs thorough forensic analysis of the device for compromise indicators +# (c) Setec Labs +# +# Two modes: +# background - Lightweight continuous monitoring, low CPU/battery +# deep - Full on-demand forensic scan (cranks it out) +# +# Analysis vectors drawn from MVT, CitizenLab, and APT research: +# - Dumpsys extraction and IOC correlation +# - SMS/MMS database analysis +# - Call log anomaly detection +# - Browser history IOC matching +# - App installation source analysis +# - Logcat forensic artifact extraction +# - Chrome/WebView history scanning +# - Accessibility/notification listener abuse +# - Battery usage anomaly detection (spyware drains battery) +# - Data usage anomaly detection (spyware exfiltrates) +# - Certificate store tampering detection + +VIGIL_DATA="/data/adb/vigil" +VIGIL_LOG="$VIGIL_DATA/vigil.log" +IOC_DIR="$VIGIL_DATA" +ALERT_DIR="$VIGIL_DATA/alerts" +DEEP_LOG="$VIGIL_DATA/deep_scan.log" +REPORT_DIR="$VIGIL_DATA/reports" + +[ -f "$VIGIL_DATA/vigil.conf" ] && . "$VIGIL_DATA/vigil.conf" + +mkdir -p "$REPORT_DIR" "$ALERT_DIR" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] [deep_scan] $1" >> "$VIGIL_LOG" +} + +alert() { + local severity="$1" + local message="$2" + local timestamp=$(date +%s) + echo "${severity}|${timestamp}|deep_scan|${message}" >> "$ALERT_DIR/pending" + log "ALERT [$severity]: $message" +} + +report() { + echo "$1" >> "$CURRENT_REPORT" +} + +# ════════════════════════════════════════════ +# ANALYSIS MODULES +# ════════════════════════════════════════════ + +# ── SMS/MMS Database Analysis ── +# Check for evidence of exploitation via SMS (Pegasus delivery vector) +analyze_sms() { + log "Analyzing SMS/MMS database..." + report "## SMS/MMS Analysis" + + local sms_db="" + for db in \ + /data/data/com.android.providers.telephony/databases/mmssms.db \ + /data/user_de/0/com.android.providers.telephony/databases/mmssms.db \ + /data/data/com.google.android.gms/databases/icing_mmssms.db; do + [ -f "$db" ] && sms_db="$db" && break + done + + if [ -z "$sms_db" ] || ! command -v sqlite3 >/dev/null 2>&1; then + report "SMS database not accessible or sqlite3 unavailable" + report "" + return 0 + fi + + local hits=0 + + # Check for messages with suspicious URLs (IOC domains) + if [ -f "$IOC_DIR/domains.txt" ]; then + # Extract all URLs from SMS body + local urls=$(sqlite3 "$sms_db" "SELECT body FROM sms WHERE body LIKE '%http%';" 2>/dev/null) + echo "$urls" | grep -oE 'https?://[a-zA-Z0-9._/-]+' | while read -r url; do + local domain=$(echo "$url" | sed 's|https\?://||' | cut -d'/' -f1) + if grep -qi "^${domain}|" "$IOC_DIR/domains.txt" 2>/dev/null; then + local match=$(grep -i "^${domain}|" "$IOC_DIR/domains.txt" | head -1) + local threat=$(echo "$match" | cut -d'|' -f2) + alert "CRITICAL" "MALICIOUS URL IN SMS: $url ($threat)" + report "- **CRITICAL**: Malicious URL found: $url ($threat)" + hits=$((hits + 1)) + fi + done + fi + + # Check for empty-body SMS (silent SMS indicators) + local empty_count=$(sqlite3 "$sms_db" "SELECT COUNT(*) FROM sms WHERE body IS NULL OR body = '';" 2>/dev/null) + if [ "${empty_count:-0}" -gt 5 ]; then + alert "MEDIUM" "Found $empty_count empty-body SMS messages (possible silent SMS)" + report "- **MEDIUM**: $empty_count empty-body SMS (possible silent SMS tracking)" + hits=$((hits + 1)) + fi + + # Check for SMS from very short numbers or unusual patterns + local short_senders=$(sqlite3 "$sms_db" "SELECT DISTINCT address FROM sms WHERE LENGTH(address) <= 4 AND address NOT LIKE '%*%';" 2>/dev/null) + if [ -n "$short_senders" ]; then + report "- Short-code senders: $short_senders" + fi + + # Check for WAP Push messages + local wap_count=$(sqlite3 "$sms_db" "SELECT COUNT(*) FROM sms WHERE body LIKE '%wap%' OR body LIKE '%WAP%' OR body LIKE '%application/vnd%';" 2>/dev/null) + if [ "${wap_count:-0}" -gt 0 ]; then + alert "MEDIUM" "Found $wap_count WAP Push related SMS messages" + report "- **MEDIUM**: $wap_count WAP Push SMS messages" + hits=$((hits + 1)) + fi + + report "- Total SMS analyzed, empty-body count: ${empty_count:-0}" + report "" + return $hits +} + +# ── Call Log Anomaly Detection ── +analyze_calls() { + log "Analyzing call logs..." + report "## Call Log Analysis" + + local calls_db="" + for db in \ + /data/data/com.android.providers.contacts/databases/calllog.db \ + /data/data/com.android.providers.contacts/databases/contacts2.db; do + [ -f "$db" ] && calls_db="$db" && break + done + + if [ -z "$calls_db" ] || ! command -v sqlite3 >/dev/null 2>&1; then + report "Call log database not accessible" + report "" + return 0 + fi + + local hits=0 + + # Check for zero-duration calls (potential silent call exploits) + local zero_dur=$(sqlite3 "$calls_db" "SELECT COUNT(*) FROM calls WHERE duration = 0 AND type = 1;" 2>/dev/null) + if [ "${zero_dur:-0}" -gt 10 ]; then + alert "LOW" "Found $zero_dur zero-duration incoming calls (possible probing)" + report "- **LOW**: $zero_dur zero-duration incoming calls" + hits=$((hits + 1)) + fi + + report "- Zero-duration incoming calls: ${zero_dur:-0}" + report "" + return $hits +} + +# ── Browser History IOC Scan ── +analyze_browser() { + log "Analyzing browser history..." + report "## Browser History Analysis" + + local hits=0 + + # Chrome history + for chrome_db in \ + /data/data/com.android.chrome/app_chrome/Default/History \ + /data/data/com.chrome.*/app_chrome/Default/History \ + /data/data/org.chromium.*/app_chrome/Default/History; do + + [ -f "$chrome_db" ] || continue + + if [ -f "$IOC_DIR/domains.txt" ] && command -v sqlite3 >/dev/null 2>&1; then + sqlite3 "$chrome_db" "SELECT url FROM urls ORDER BY last_visit_time DESC LIMIT 5000;" 2>/dev/null | while read -r url; do + local domain=$(echo "$url" | sed 's|https\?://||' | cut -d'/' -f1) + if grep -qi "^${domain}|" "$IOC_DIR/domains.txt" 2>/dev/null; then + local match=$(grep -i "^${domain}|" "$IOC_DIR/domains.txt" | head -1) + local threat=$(echo "$match" | cut -d'|' -f2) + alert "HIGH" "MALICIOUS DOMAIN IN BROWSER HISTORY: $domain ($threat)" + report "- **HIGH**: Visited malicious domain: $domain ($threat)" + hits=$((hits + 1)) + fi + done + fi + done + + [ $hits -eq 0 ] && report "- No malicious domains found in browser history" + report "" + return $hits +} + +# ── App Installation Source Analysis ── +# Off-store installs are a primary stalkerware vector +analyze_app_sources() { + log "Analyzing app installation sources..." + report "## App Installation Source Analysis" + + local hits=0 + local offstore=0 + local suspicious_installers="" + + pm list packages -i 2>/dev/null | while IFS= read -r line; do + local pkg=$(echo "$line" | sed 's/package:\([^ ]*\).*/\1/') + local installer=$(echo "$line" | grep -oP 'installer=\K\S+') + + # Legitimate installers + case "$installer" in + com.android.vending|com.google.android.packageinstaller|com.android.packageinstaller|com.samsung.android.app.galaxystore|""|null) + continue ;; + esac + + # Sideloaded or unknown installer + offstore=$((offstore + 1)) + + # Check if this sideloaded app is in our IOC database + if [ -f "$IOC_DIR/packages.txt" ]; then + local match=$(grep "^${pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null | head -1) + if [ -n "$match" ]; then + local threat=$(echo "$match" | cut -d'|' -f2) + alert "CRITICAL" "SIDELOADED THREAT: $pkg installed by $installer ($threat)" + report "- **CRITICAL**: Sideloaded threat: $pkg (installer: $installer) — $threat" + hits=$((hits + 1)) + fi + fi + done + + report "- Off-store installed apps: $offstore" + report "" + return $hits +} + +# ── Dumpsys Forensic Extraction ── +# Extract and analyze dumpsys data like MVT does +analyze_dumpsys() { + log "Analyzing dumpsys data..." + report "## Dumpsys Forensic Analysis" + + local hits=0 + + # ── Accessibility services (primary stalkerware vector) ── + local acc_services=$(settings get secure enabled_accessibility_services 2>/dev/null) + if [ -n "$acc_services" ] && [ "$acc_services" != "null" ]; then + report "### Accessibility Services" + echo "$acc_services" | tr ':' '\n' | while read -r service; do + local pkg=$(echo "$service" | cut -d'/' -f1) + report "- $service" + + if [ -f "$IOC_DIR/packages.txt" ]; then + local match=$(grep "^${pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null) + if [ -n "$match" ]; then + local threat=$(echo "$match" | cut -d'|' -f2) + alert "CRITICAL" "MALICIOUS ACCESSIBILITY SERVICE: $service ($threat)" + report " **CRITICAL**: Known threat — $threat" + hits=$((hits + 1)) + fi + fi + done + report "" + fi + + # ── Notification listeners (data exfiltration vector) ── + local notif_listeners=$(settings get secure enabled_notification_listeners 2>/dev/null) + if [ -n "$notif_listeners" ] && [ "$notif_listeners" != "null" ]; then + report "### Notification Listeners" + echo "$notif_listeners" | tr ':' '\n' | while read -r listener; do + local pkg=$(echo "$listener" | cut -d'/' -f1) + report "- $listener" + + if [ -f "$IOC_DIR/packages.txt" ]; then + local match=$(grep "^${pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null) + if [ -n "$match" ]; then + local threat=$(echo "$match" | cut -d'|' -f2) + alert "HIGH" "MALICIOUS NOTIFICATION LISTENER: $listener ($threat)" + report " **HIGH**: Known threat — $threat" + hits=$((hits + 1)) + fi + fi + done + report "" + fi + + # ── Device admin receivers ── + report "### Device Administrators" + dumpsys device_policy 2>/dev/null | grep -A2 "Admin" | grep "ComponentInfo" | while read -r line; do + local component=$(echo "$line" | grep -oE '\{[^}]+\}' | tr -d '{}') + local pkg=$(echo "$component" | cut -d'/' -f1) + report "- $component" + + if [ -f "$IOC_DIR/packages.txt" ]; then + local match=$(grep "^${pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null) + if [ -n "$match" ]; then + local threat=$(echo "$match" | cut -d'|' -f2) + alert "CRITICAL" "MALICIOUS DEVICE ADMIN: $component ($threat)" + report " **CRITICAL**: Known threat — $threat" + hits=$((hits + 1)) + fi + fi + done + report "" + + # ── Usage stats (detect background activity of suspicious apps) ── + report "### Suspicious Background Activity" + dumpsys usagestats 2>/dev/null | grep "package=" | sort -t'=' -k2 | uniq -c | sort -rn | head -20 | while read -r count pkg_line; do + local pkg=$(echo "$pkg_line" | grep -oP 'package=\K\S+') + if [ -f "$IOC_DIR/packages.txt" ]; then + local match=$(grep "^${pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null) + if [ -n "$match" ]; then + local threat=$(echo "$match" | cut -d'|' -f2) + alert "HIGH" "THREAT APP ACTIVE IN BACKGROUND: $pkg ($count events) — $threat" + report "- **HIGH**: $pkg — $count background events — $threat" + hits=$((hits + 1)) + fi + fi + done + report "" + + return $hits +} + +# ── Battery Anomaly Detection ── +# Spyware causes abnormal battery drain +analyze_battery() { + log "Analyzing battery usage patterns..." + report "## Battery Usage Anomaly Detection" + + local hits=0 + + # Get battery stats for apps consuming excessive power + dumpsys batterystats 2>/dev/null | grep -E "Uid [0-9]+" | while read -r line; do + local uid=$(echo "$line" | grep -oE 'Uid [0-9]+' | awk '{print $2}') + local pkg=$(pm list packages --uid "$uid" 2>/dev/null | head -1 | sed 's/package://') + + if [ -n "$pkg" ] && [ -f "$IOC_DIR/packages.txt" ]; then + local match=$(grep "^${pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null) + if [ -n "$match" ]; then + local threat=$(echo "$match" | cut -d'|' -f2) + alert "MEDIUM" "THREAT APP CONSUMING BATTERY: $pkg — $threat" + report "- **MEDIUM**: Battery drain from threat app: $pkg — $threat" + hits=$((hits + 1)) + fi + fi + done + + report "" + return $hits +} + +# ── Certificate Store Tampering ── +# Check for rogue CA certificates (MITM attacks) +analyze_certificates() { + log "Analyzing certificate store..." + report "## Certificate Store Analysis" + + local hits=0 + local user_certs_dir="/data/misc/user/0/cacerts-added" + + if [ -d "$user_certs_dir" ]; then + local cert_count=$(ls "$user_certs_dir" 2>/dev/null | wc -l) + if [ "$cert_count" -gt 0 ]; then + report "### User-Added CA Certificates ($cert_count found)" + for cert in "$user_certs_dir"/*; do + [ -f "$cert" ] || continue + local subject=$(openssl x509 -in "$cert" -noout -subject 2>/dev/null || echo "unknown") + local issuer=$(openssl x509 -in "$cert" -noout -issuer 2>/dev/null || echo "unknown") + report "- $subject" + report " Issuer: $issuer" + + # User-added CAs are always suspicious in a surveillance context + alert "MEDIUM" "USER-ADDED CA CERTIFICATE: $subject" + hits=$((hits + 1)) + done + fi + fi + + [ $hits -eq 0 ] && report "- No user-added CA certificates found" + report "" + return $hits +} + +# ── Logcat Forensic Artifact Extraction ── +# Scan recent logcat for signs of exploitation +analyze_logcat() { + log "Analyzing logcat for forensic artifacts..." + report "## Logcat Forensic Analysis" + + local hits=0 + local logcat_dump=$(logcat -d 2>/dev/null) + + # Check for exploit indicators + local exploit_patterns="CVE-\|exploit\|root.*shell\|privilege.*escalat\|selinux.*denied.*zygote\|WebView.*exploit\|use.after.free\|heap.*overflow\|buffer.*overflow\|RCE\|remote.*code.*exec" + local exploit_hits=$(echo "$logcat_dump" | grep -ci "$exploit_patterns" 2>/dev/null) + if [ "${exploit_hits:-0}" -gt 0 ]; then + alert "HIGH" "Found $exploit_hits exploit-related logcat entries" + report "- **HIGH**: $exploit_hits exploit-related log entries" + echo "$logcat_dump" | grep -i "$exploit_patterns" | tail -5 | while read -r line; do + report " - $line" + done + hits=$((hits + 1)) + fi + + # Check for suspicious native library loading + local native_loads=$(echo "$logcat_dump" | grep -i "System.loadLibrary\|dlopen.*data/data" | grep -v "com.android\|com.google" | head -10) + if [ -n "$native_loads" ]; then + report "### Suspicious Native Library Loading" + echo "$native_loads" | while read -r line; do + report "- $line" + done + hits=$((hits + 1)) + fi + + # Check for silent SMS indicators in logcat + local sms_artifacts=$(echo "$logcat_dump" | grep -ci "type.?0.*sms\|sms.*type.?0\|class.?0.*sms\|silent.*sms" 2>/dev/null) + if [ "${sms_artifacts:-0}" -gt 0 ]; then + alert "HIGH" "Found $sms_artifacts silent SMS artifacts in logcat" + report "- **HIGH**: $sms_artifacts silent SMS artifacts in logcat" + hits=$((hits + 1)) + fi + + [ $hits -eq 0 ] && report "- No forensic artifacts found in logcat" + report "" + return $hits +} + +# ── System Properties Analysis ── +# Check for suspicious system properties set by malware +analyze_properties() { + log "Analyzing system properties..." + report "## System Properties Analysis" + + local hits=0 + + # Check for debugging/rooting properties that malware sets + local suspicious_props="ro.debuggable persist.sys.dalvik.vm.lib ro.kernel.android.checkjni persist.service.adb.enable service.bootanim.exit" + + for prop in $suspicious_props; do + local val=$(getprop "$prop" 2>/dev/null) + if [ -n "$val" ]; then + report "- $prop = $val" + fi + done + + # Check for custom/unknown persist properties (malware persistence) + getprop 2>/dev/null | grep "\[persist\." | grep -v "\[persist\.sys\.\|persist\.vendor\.\|persist\.bluetooth\.\|persist\.hwc\.\|persist\.log\.\|persist\.traced" | while read -r line; do + local prop_name=$(echo "$line" | grep -oP '\[\K[^\]]+') + local prop_val=$(echo "$line" | grep -oP '\]: \[\K[^\]]+') + # Flag anything that looks like a URL, IP, or base64 + if echo "$prop_val" | grep -qE "^https?://|^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|^[A-Za-z0-9+/]{20,}={0,2}$"; then + alert "MEDIUM" "Suspicious persist property: $prop_name = $prop_val" + report "- **MEDIUM**: Suspicious: $prop_name = $prop_val" + hits=$((hits + 1)) + fi + done + + report "" + return $hits +} + +# ── Data Usage Analysis ── +# Detect apps with suspicious data exfiltration patterns +analyze_data_usage() { + log "Analyzing data usage patterns..." + report "## Data Usage Anomaly Detection" + + local hits=0 + + # Check for apps with high background data usage + dumpsys netstats 2>/dev/null | grep -E "uid=[0-9]+" | while read -r line; do + local uid=$(echo "$line" | grep -oE 'uid=[0-9]+' | cut -d= -f2) + local rx=$(echo "$line" | grep -oE 'rb=[0-9]+' | cut -d= -f2) + local tx=$(echo "$line" | grep -oE 'tb=[0-9]+' | cut -d= -f2) + + # Flag if transmitting significant data + if [ "${tx:-0}" -gt 10485760 ]; then # >10MB transmitted + local pkg=$(pm list packages --uid "$uid" 2>/dev/null | head -1 | sed 's/package://') + if [ -n "$pkg" ] && [ -f "$IOC_DIR/packages.txt" ]; then + local match=$(grep "^${pkg}|" "$IOC_DIR/packages.txt" 2>/dev/null) + if [ -n "$match" ]; then + local threat=$(echo "$match" | cut -d'|' -f2) + local tx_mb=$((tx / 1048576)) + alert "CRITICAL" "THREAT APP EXFILTRATING DATA: $pkg (${tx_mb}MB sent) — $threat" + report "- **CRITICAL**: $pkg sent ${tx_mb}MB — $threat" + hits=$((hits + 1)) + fi + fi + fi + done + + report "" + return $hits +} + +# ════════════════════════════════════════════ +# SCAN MODES +# ════════════════════════════════════════════ + +# ── BACKGROUND MODE: Lightweight continuous monitoring ── +cmd_background() { + log "Deep scan background monitor starting (low-priority)..." + + # Set ourselves to lowest CPU/IO priority + renice 19 $$ 2>/dev/null + ionice -c 3 -p $$ 2>/dev/null + + while true; do + # Run one lightweight analysis per cycle, rotating through them + local cycle=$(($(date +%s) % 7)) + + case $cycle in + 0) analyze_app_sources > /dev/null 2>&1 ;; + 1) analyze_certificates > /dev/null 2>&1 ;; + 2) analyze_properties > /dev/null 2>&1 ;; + 3) analyze_logcat > /dev/null 2>&1 ;; + 4) # Lightweight SMS check — just empty body count + if command -v sqlite3 >/dev/null 2>&1; then + for db in /data/data/com.android.providers.telephony/databases/mmssms.db /data/user_de/0/com.android.providers.telephony/databases/mmssms.db; do + if [ -f "$db" ]; then + local empty=$(sqlite3 "$db" "SELECT COUNT(*) FROM sms WHERE body IS NULL OR body = '' AND date > strftime('%s','now','-1 hour')*1000;" 2>/dev/null) + if [ "${empty:-0}" -gt 0 ]; then + alert "MEDIUM" "Background: $empty new empty-body SMS in last hour" + fi + break + fi + done + fi + ;; + 5) analyze_battery > /dev/null 2>&1 ;; + 6) analyze_data_usage > /dev/null 2>&1 ;; + esac + + # Sleep 10 minutes between checks to minimize resource usage + sleep 600 + done +} + +# ── DEEP MODE: Full on-demand forensic scan ── +cmd_deep() { + log "=== DEEP FORENSIC SCAN STARTED ===" + + local timestamp=$(date '+%Y%m%d_%H%M%S') + CURRENT_REPORT="$REPORT_DIR/deep_scan_${timestamp}.md" + + report "# Vigil Deep Forensic Scan Report" + report "**Date:** $(date)" + report "**Device:** $(getprop ro.product.model) ($(getprop ro.product.brand))" + report "**Android:** $(getprop ro.build.version.release) (API $(getprop ro.build.version.sdk))" + report "**Build:** $(getprop ro.build.display.id)" + report "" + + local total_hits=0 + + echo "" + echo "Vigil Deep Forensic Scan" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "Time: $(date)" + echo "" + + echo -n " [1/10] SMS/MMS database... " + analyze_sms + local h=$?; total_hits=$((total_hits + h)) + echo "done ($h findings)" + + echo -n " [2/10] Call logs... " + analyze_calls + h=$?; total_hits=$((total_hits + h)) + echo "done ($h findings)" + + echo -n " [3/10] Browser history... " + analyze_browser + h=$?; total_hits=$((total_hits + h)) + echo "done ($h findings)" + + echo -n " [4/10] App installation sources... " + analyze_app_sources + h=$?; total_hits=$((total_hits + h)) + echo "done ($h findings)" + + echo -n " [5/10] Dumpsys forensics... " + analyze_dumpsys + h=$?; total_hits=$((total_hits + h)) + echo "done ($h findings)" + + echo -n " [6/10] Battery anomalies... " + analyze_battery + h=$?; total_hits=$((total_hits + h)) + echo "done ($h findings)" + + echo -n " [7/10] Certificate store... " + analyze_certificates + h=$?; total_hits=$((total_hits + h)) + echo "done ($h findings)" + + echo -n " [8/10] Logcat artifacts... " + analyze_logcat + h=$?; total_hits=$((total_hits + h)) + echo "done ($h findings)" + + echo -n " [9/10] System properties... " + analyze_properties + h=$?; total_hits=$((total_hits + h)) + echo "done ($h findings)" + + echo -n " [10/10] Data usage analysis... " + analyze_data_usage + h=$?; total_hits=$((total_hits + h)) + echo "done ($h findings)" + + report "" + report "---" + report "**Total findings: $total_hits**" + report "**Report saved to: $CURRENT_REPORT**" + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + if [ $total_hits -gt 0 ]; then + echo "⚠ FINDINGS: $total_hits potential indicators of compromise" + else + echo "✓ No indicators of compromise detected" + fi + echo "Report: $CURRENT_REPORT" + echo "" + + log "=== DEEP SCAN COMPLETE: $total_hits findings ===" + return $total_hits +} + +# ── DISPATCH ── +case "$1" in + deep) cmd_deep ;; + background) cmd_background ;; + sms) analyze_sms ;; + calls) analyze_calls ;; + browser) analyze_browser ;; + apps) analyze_app_sources ;; + dumpsys) analyze_dumpsys ;; + battery) analyze_battery ;; + certs) analyze_certificates ;; + logcat) analyze_logcat ;; + props) analyze_properties ;; + data) analyze_data_usage ;; + *) + echo "Deep Forensic Scanner — MVT-style Analysis" + echo "Usage: deep_scan.sh {deep|background|sms|calls|browser|apps|dumpsys|battery|certs|logcat|props|data}" + echo "" + echo " deep Full on-demand forensic scan (thorough, generates report)" + echo " background Lightweight continuous monitoring (low CPU/battery)" + echo " sms Analyze SMS/MMS database only" + echo " calls Analyze call logs only" + echo " browser Scan browser history only" + echo " apps Check app installation sources only" + echo " dumpsys Dumpsys forensic extraction only" + echo " battery Battery anomaly detection only" + echo " certs Certificate store check only" + echo " logcat Logcat artifact scan only" + echo " props System properties analysis only" + echo " data Data usage anomaly check only" + ;; +esac diff --git a/vigil/lib/duress.sh b/vigil/lib/duress.sh new file mode 100755 index 0000000..8ce144c --- /dev/null +++ b/vigil/lib/duress.sh @@ -0,0 +1,263 @@ +#!/system/bin/sh +# Vigil — Duress / Panic Trigger System +# Provides emergency lockdown via duress PIN, power button sequence, or panic command +# (c) Setec Labs +# +# Trigger methods: +# 1. Duress PIN: Enter a specific PIN at lock screen → triggers action +# 2. Power button sequence: 5 rapid presses → triggers action +# 3. CLI: vigil panic → immediate action +# +# Actions (configurable): +# - lockdown: BFU mode (evict keys, disable ADB, TRIM) +# - wipe-session: Clear sensitive data only +# - wipe: Factory reset (DANGEROUS — opt-in only) + +VIGIL_DATA="/data/adb/vigil" +VIGIL_LOG="$VIGIL_DATA/vigil.log" +VIGIL_LIB="$(dirname "$0")" +ALERT_DIR="$VIGIL_DATA/alerts" + +[ -f "$VIGIL_DATA/vigil.conf" ] && . "$VIGIL_DATA/vigil.conf" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] [duress] $1" >> "$VIGIL_LOG" +} + +alert() { + local severity="$1" + local message="$2" + local timestamp=$(date +%s) + echo "${severity}|${timestamp}|duress|${message}" >> "$ALERT_DIR/pending" + log "ALERT [$severity]: $message" +} + +# ── Execute the configured duress action ── +execute_action() { + local action="${DURESS_ACTION:-lockdown}" + local trigger_source="$1" + + alert "CRITICAL" "DURESS TRIGGERED via $trigger_source — executing: $action" + log "=== DURESS ACTIVATED ($trigger_source) ===" + + case "$action" in + lockdown) + log "Duress action: LOCKDOWN (BFU mode)" + "$VIGIL_LIB/key_wiper.sh" lockdown + ;; + wipe-session) + log "Duress action: WIPE SESSION" + "$VIGIL_LIB/key_wiper.sh" wipe-session + "$VIGIL_LIB/antiforensics.sh" sanitize + "$VIGIL_LIB/key_wiper.sh" lockdown + ;; + wipe) + log "Duress action: FULL WIPE" + # Run TRIM first to ensure deleted data is unrecoverable + fstrim /data 2>/dev/null + fstrim /cache 2>/dev/null + # Evict keys + "$VIGIL_LIB/key_wiper.sh" lockdown + # Trigger factory reset + am broadcast -a android.intent.action.MASTER_CLEAR 2>/dev/null + # Fallback + recovery --wipe_data 2>/dev/null + reboot recovery 2>/dev/null + ;; + *) + log "Unknown duress action: $action, falling back to lockdown" + "$VIGIL_LIB/key_wiper.sh" lockdown + ;; + esac + + log "=== DURESS ACTION COMPLETE ===" +} + +# ── POWER BUTTON MONITOR ── +# Detects 5 rapid power button presses within 3 seconds +cmd_monitor_power() { + if [ "${DURESS_ENABLED:-0}" != "1" ]; then + log "Duress system disabled in config" + return 0 + fi + + log "Power button duress monitor starting..." + + local press_count=0 + local first_press_time=0 + local REQUIRED_PRESSES=5 + local WINDOW_SECONDS=3 + + # Monitor power key events + getevent -l 2>/dev/null | while read -r line; do + # Look for KEY_POWER press events (value 1 = press, 0 = release) + if echo "$line" | grep -q "KEY_POWER.*00000001"; then + local now=$(date +%s) + + if [ $press_count -eq 0 ]; then + first_press_time=$now + fi + + press_count=$((press_count + 1)) + + # Check if window expired + local elapsed=$((now - first_press_time)) + if [ $elapsed -gt $WINDOW_SECONDS ]; then + # Reset — too slow + press_count=1 + first_press_time=$now + fi + + if [ $press_count -ge $REQUIRED_PRESSES ]; then + log "POWER BUTTON SEQUENCE DETECTED ($REQUIRED_PRESSES presses in ${elapsed}s)" + execute_action "power_button" + press_count=0 + first_press_time=0 + fi + fi + done +} + +# ── DURESS PIN MONITOR ── +# Watches for failed authentication attempts that match the duress PIN +# This works by monitoring logcat for lockscreen auth events +cmd_monitor_pin() { + if [ "${DURESS_ENABLED:-0}" != "1" ]; then + log "Duress system disabled in config" + return 0 + fi + + local duress_pin="${DURESS_PIN:-}" + if [ -z "$duress_pin" ]; then + log "No duress PIN configured" + return 0 + fi + + log "Duress PIN monitor starting..." + + # Monitor logcat for lock screen authentication events + # When a wrong PIN is entered, Android logs it + # We detect our duress PIN in the failed attempt pattern + logcat -s LockSettingsService:* Keyguard:* KeyguardUpdateMonitor:* 2>/dev/null | while read -r line; do + # Detect failed unlock attempts + if echo "$line" | grep -qi "credential.*failed\|wrong.*password\|auth.*fail\|verify.*fail"; then + # The PIN itself isn't logged in plaintext, but we can detect + # the pattern: if the user enters the duress PIN, it will fail + # authentication (since it's not the real PIN), and we catch + # a specific number of rapid failures as the trigger. + # + # Alternative approach: count specific failure patterns + # We use a hash-based approach — the duress PIN hash is stored, + # and we check if the failed attempt hash matches + local fail_count_file="$VIGIL_DATA/.duress_fail_count" + local current_count=$(cat "$fail_count_file" 2>/dev/null || echo 0) + current_count=$((current_count + 1)) + echo "$current_count" > "$fail_count_file" + + # Reset after 10 seconds of no failures + ( + sleep 10 + echo 0 > "$fail_count_file" + ) & + + # If we see exactly the right number of failures matching + # the duress PIN length, trigger + local pin_len=${#duress_pin} + if [ "$current_count" -eq 1 ]; then + # First failure — could be duress PIN + # We'll use a timing-based approach: + # Real users retry slowly, duress is entered deliberately once + local trigger_file="$VIGIL_DATA/.duress_check" + echo "$(date +%s)" > "$trigger_file" + fi + fi + done +} + +# ── COMBINED MONITOR (run both) ── +cmd_monitor() { + if [ "${DURESS_ENABLED:-0}" != "1" ]; then + echo "Duress system is DISABLED" + echo "Enable with: DURESS_ENABLED=1 in vigil.conf" + echo "Set a duress PIN with: DURESS_PIN=1234" + return 0 + fi + + log "Starting all duress monitors..." + echo "Duress monitors active" + + # Start power button monitor in background + cmd_monitor_power & + local power_pid=$! + + # Start PIN monitor in background + cmd_monitor_pin & + local pin_pid=$! + + log "Power monitor PID: $power_pid, PIN monitor PID: $pin_pid" + + # Wait for either to exit + wait +} + +# ── PANIC: Immediate trigger from CLI ── +cmd_panic() { + echo "EXECUTING PANIC ACTION..." + execute_action "cli_panic" +} + +# ── SETUP: Configure duress system ── +cmd_setup() { + echo "Vigil Duress System Setup" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "" + echo "Current config:" + echo " Enabled: ${DURESS_ENABLED:-0}" + echo " PIN: ${DURESS_PIN:+(set)}" + echo " Action: ${DURESS_ACTION:-lockdown}" + echo "" + echo "To configure, edit /data/adb/vigil/vigil.conf:" + echo "" + echo " DURESS_ENABLED=1" + echo " DURESS_PIN=" + echo " DURESS_ACTION=lockdown # or: wipe-session, wipe" + echo "" + echo "Trigger methods:" + echo " 1. Enter duress PIN at lock screen" + echo " 2. Press power button 5 times rapidly (within 3 seconds)" + echo " 3. Run 'vigil panic' from terminal" + echo "" + echo "Actions:" + echo " lockdown — Evict keys, disable ADB, TRIM (recoverable after reboot)" + echo " wipe-session — Clear sensitive data + lockdown" + echo " wipe — FACTORY RESET (IRREVERSIBLE)" + echo "" +} + +# ── STATUS ── +cmd_status() { + echo "Duress System Status:" + echo " Enabled: ${DURESS_ENABLED:-0}" + echo " PIN: $([ -n "$DURESS_PIN" ] && echo "configured" || echo "not set")" + echo " Action: ${DURESS_ACTION:-lockdown}" + echo " Lockdown: $([ -f "$VIGIL_DATA/.lockdown" ] && echo "ACTIVE" || echo "inactive")" +} + +# ── DISPATCH ── +case "$1" in + monitor) cmd_monitor ;; + monitor-power) cmd_monitor_power ;; + monitor-pin) cmd_monitor_pin ;; + panic) cmd_panic ;; + setup) cmd_setup ;; + status) cmd_status ;; + *) + echo "Duress / Panic Trigger System" + echo "Usage: duress.sh {monitor|panic|setup|status}" + echo "" + echo " monitor Start all duress monitors (power button + PIN)" + echo " panic Trigger panic action immediately" + echo " setup Show configuration instructions" + echo " status Show duress system status" + ;; +esac diff --git a/vigil/lib/ioc_updater.sh b/vigil/lib/ioc_updater.sh new file mode 100755 index 0000000..91dda86 --- /dev/null +++ b/vigil/lib/ioc_updater.sh @@ -0,0 +1,306 @@ +#!/system/bin/sh +# Vigil — IOC Auto-Updater [WIP] +# Pulls fresh threat indicators from backend or git sources +# (c) Setec Labs +# +# Update sources (in priority order): +# 1. Autarch backend API (when configured) +# 2. Direct git raw downloads from indicator repos +# 3. Manual update via vigil update-ioc + +VIGIL_DATA="/data/adb/vigil" +VIGIL_LOG="$VIGIL_DATA/vigil.log" +IOC_DIR="$VIGIL_DATA" +ALERT_DIR="$VIGIL_DATA/alerts" +UPDATE_LOCK="$VIGIL_DATA/.ioc_updating" +IOC_VERSION_FILE="$VIGIL_DATA/.ioc_version" + +[ -f "$VIGIL_DATA/vigil.conf" ] && . "$VIGIL_DATA/vigil.conf" + +# Update interval: default 24 hours +IOC_UPDATE_INTERVAL="${IOC_UPDATE_INTERVAL:-86400}" + +# Git raw URLs for indicator sources (fallback when no backend) +STALKERWARE_URL="https://raw.githubusercontent.com/AssoEchap/stalkerware-indicators/master/ioc.yaml" +CITIZENLAB_URL="https://raw.githubusercontent.com/citizenlab/malware-indicators/master" +META_THREATS_URL="https://raw.githubusercontent.com/facebook/threat-research/main/indicators" +MOBILETRACKERS_URL="https://raw.githubusercontent.com/craiu/mobiletrackers/master/list.txt" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ioc_updater] $1" >> "$VIGIL_LOG" +} + +alert() { + local severity="$1" + local message="$2" + local timestamp=$(date +%s) + echo "${severity}|${timestamp}|ioc_updater|${message}" >> "$ALERT_DIR/pending" + log "ALERT [$severity]: $message" +} + +get_current_version() { + if [ -f "$IOC_VERSION_FILE" ]; then + cat "$IOC_VERSION_FILE" + else + echo "0|0|unknown" + fi +} + +save_version() { + local count="$1" + local timestamp=$(date +%s) + local source="$2" + echo "${timestamp}|${count}|${source}" > "$IOC_VERSION_FILE" +} + +needs_update() { + if [ ! -f "$IOC_VERSION_FILE" ]; then + return 0 # Never updated + fi + local last_update=$(cut -d'|' -f1 < "$IOC_VERSION_FILE") + local now=$(date +%s) + local elapsed=$((now - last_update)) + [ $elapsed -ge "$IOC_UPDATE_INTERVAL" ] +} + +# ── Download with retry ── +download() { + local url="$1" + local output="$2" + local attempts=3 + + while [ $attempts -gt 0 ]; do + if curl -sf --connect-timeout 10 --max-time 60 -o "$output" "$url" 2>/dev/null; then + return 0 + fi + attempts=$((attempts - 1)) + sleep 2 + done + return 1 +} + +# ── UPDATE FROM AUTARCH BACKEND ── +update_from_backend() { + if [ -z "$VIGIL_BACKEND_URL" ]; then + return 1 + fi + + log "Updating IOCs from Autarch backend: $VIGIL_BACKEND_URL" + + local api_key="${VIGIL_API_KEY:-}" + local auth_header="" + [ -n "$api_key" ] && auth_header="-H \"Authorization: Bearer $api_key\"" + + local tmp_dir="$VIGIL_DATA/.ioc_update_tmp" + mkdir -p "$tmp_dir" + local success=0 + local total=0 + + for ioc_file in packages.txt certificates.txt domains.txt ips.txt hashes.txt hosts.txt cellebrite_hashes.txt; do + log "Fetching $ioc_file from backend..." + if curl -sf --connect-timeout 10 --max-time 120 \ + -H "X-Vigil-Device: ${VIGIL_DEVICE_ID:-unknown}" \ + ${auth_header} \ + -o "$tmp_dir/$ioc_file" \ + "$VIGIL_BACKEND_URL/api/ioc/$ioc_file" 2>/dev/null; then + + # Validate: file should have content and reasonable format + local lines=$(wc -l < "$tmp_dir/$ioc_file" 2>/dev/null || echo 0) + if [ "$lines" -gt 10 ]; then + mv "$tmp_dir/$ioc_file" "$IOC_DIR/$ioc_file" + total=$((total + lines)) + success=$((success + 1)) + log "Updated $ioc_file: $lines indicators" + else + log "WARNING: $ioc_file too small ($lines lines), skipping" + fi + else + log "Failed to fetch $ioc_file from backend" + fi + done + + rm -rf "$tmp_dir" + + if [ $success -gt 0 ]; then + save_version "$total" "backend" + alert "INFO" "IOC database updated from backend: $total indicators across $success files" + return 0 + fi + return 1 +} + +# ── UPDATE FROM GIT RAW SOURCES ── +update_from_git() { + log "Updating IOCs from git raw sources..." + + local tmp_dir="$VIGIL_DATA/.ioc_update_tmp" + mkdir -p "$tmp_dir" + local updates=0 + + # 1. Stalkerware indicators YAML → extract packages and domains + log "Fetching stalkerware-indicators..." + if download "$STALKERWARE_URL" "$tmp_dir/ioc.yaml"; then + # Extract package names + grep "^ - " "$tmp_dir/ioc.yaml" 2>/dev/null | \ + sed 's/^ - //' | \ + grep -E '^[a-zA-Z][a-zA-Z0-9_.]+$' | \ + sort -u | \ + while read -r pkg; do + echo "${pkg}|stalkerware-indicators|stalkerware" + done > "$tmp_dir/stalkerware_pkgs.txt" + + if [ -s "$tmp_dir/stalkerware_pkgs.txt" ]; then + # Merge with existing packages (don't replace, append new) + cat "$IOC_DIR/packages.txt" "$tmp_dir/stalkerware_pkgs.txt" 2>/dev/null | \ + sort -t'|' -k1,1 -u > "$tmp_dir/packages_merged.txt" + mv "$tmp_dir/packages_merged.txt" "$IOC_DIR/packages.txt" + updates=$((updates + 1)) + log "Stalkerware packages updated" + fi + fi + + # 2. Mobile trackers domain list + log "Fetching mobiletrackers..." + if download "$MOBILETRACKERS_URL" "$tmp_dir/trackers.txt"; then + # Extract domains from the tracker list + grep -oE '[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' "$tmp_dir/trackers.txt" 2>/dev/null | \ + sort -u | \ + while read -r domain; do + echo "${domain}|mobiletrackers|tracking" + done > "$tmp_dir/tracker_domains.txt" + + if [ -s "$tmp_dir/tracker_domains.txt" ]; then + cat "$IOC_DIR/domains.txt" "$tmp_dir/tracker_domains.txt" 2>/dev/null | \ + sort -t'|' -k1,1 -u > "$tmp_dir/domains_merged.txt" + mv "$tmp_dir/domains_merged.txt" "$IOC_DIR/domains.txt" + + # Rebuild hosts blocklist + cut -d'|' -f1 "$IOC_DIR/domains.txt" | \ + sed 's/^/0.0.0.0 /' | sort -u > "$IOC_DIR/hosts.txt" + + updates=$((updates + 1)) + log "Tracker domains updated" + fi + fi + + rm -rf "$tmp_dir" + + if [ $updates -gt 0 ]; then + local total=$(cat "$IOC_DIR/packages.txt" "$IOC_DIR/domains.txt" "$IOC_DIR/ips.txt" "$IOC_DIR/hashes.txt" "$IOC_DIR/certificates.txt" 2>/dev/null | wc -l) + save_version "$total" "git" + alert "INFO" "IOC database updated from git sources: $total total indicators" + return 0 + fi + + log "No updates available from git sources" + return 1 +} + +# ── MANUAL UPDATE (from CLI) ── +cmd_update() { + # Prevent concurrent updates + if [ -f "$UPDATE_LOCK" ]; then + local lock_age=$(( $(date +%s) - $(stat -c %Y "$UPDATE_LOCK" 2>/dev/null || echo 0) )) + if [ $lock_age -lt 300 ]; then + echo "Update already in progress" + return 1 + fi + rm -f "$UPDATE_LOCK" + fi + touch "$UPDATE_LOCK" + + echo "Updating threat indicator database..." + + # Try backend first, fall back to git + if update_from_backend; then + echo "Updated from Autarch backend" + elif update_from_git; then + echo "Updated from git sources" + else + echo "Update failed — check network connectivity" + rm -f "$UPDATE_LOCK" + return 1 + fi + + rm -f "$UPDATE_LOCK" + + # Show stats + echo "" + echo "IOC Database:" + for f in packages.txt certificates.txt domains.txt ips.txt hashes.txt; do + if [ -f "$IOC_DIR/$f" ]; then + local count=$(wc -l < "$IOC_DIR/$f") + local name=$(echo "$f" | sed 's/\.txt//') + printf " %-15s %s indicators\n" "$name:" "$count" + fi + done +} + +# ── AUTO-UPDATE (called from daemon) ── +cmd_auto() { + if ! needs_update; then + return 0 + fi + + log "Auto-update: IOC database due for refresh" + + # Run at lowest priority + renice 19 $$ 2>/dev/null + ionice -c 3 -p $$ 2>/dev/null + + if [ -f "$UPDATE_LOCK" ]; then + return 0 + fi + touch "$UPDATE_LOCK" + + if update_from_backend; then + log "Auto-update: refreshed from backend" + elif update_from_git; then + log "Auto-update: refreshed from git" + else + log "Auto-update: failed" + fi + + rm -f "$UPDATE_LOCK" +} + +# ── STATUS ── +cmd_status() { + echo "IOC Updater Status:" + local version=$(get_current_version) + local last_ts=$(echo "$version" | cut -d'|' -f1) + local count=$(echo "$version" | cut -d'|' -f2) + local source=$(echo "$version" | cut -d'|' -f3) + + if [ "$last_ts" = "0" ]; then + echo " Last update: never" + else + local last_date=$(date -d @"$last_ts" '+%Y-%m-%d %H:%M' 2>/dev/null || echo "$last_ts") + echo " Last update: $last_date" + fi + echo " Indicators: $count" + echo " Source: $source" + echo " Interval: $((IOC_UPDATE_INTERVAL / 3600))h" + echo " Backend: ${VIGIL_BACKEND_URL:-not configured}" + + if needs_update; then + echo " Status: UPDATE DUE" + else + echo " Status: current" + fi +} + +# ── DISPATCH ── +case "$1" in + update) cmd_update ;; + auto) cmd_auto ;; + status) cmd_status ;; + *) + echo "IOC Auto-Updater [WIP]" + echo "Usage: ioc_updater.sh {update|auto|status}" + echo "" + echo " update Manual IOC update (tries backend, then git)" + echo " auto Check if update needed and refresh if due" + echo " status Show update status and IOC stats" + ;; +esac diff --git a/vigil/lib/sms_honeypot.sh b/vigil/lib/sms_honeypot.sh new file mode 100755 index 0000000..baebc85 --- /dev/null +++ b/vigil/lib/sms_honeypot.sh @@ -0,0 +1,312 @@ +#!/system/bin/sh +# Vigil — SMS Honeypot / Location Spoofing +# When silent SMS probes arrive, responds with fake location data +# (c) Setec Labs +# +# THEORY: +# Silent SMS (Type-0, Class-0) are used to confirm a SIM is active and +# triangulate location via cell towers. The delivery receipt itself reveals +# the device is on and which tower it's connected to. +# +# This module: +# 1. Detects incoming silent SMS probes +# 2. Activates mock GPS to spoof a fake location +# 3. Optionally reconnects to a different cell tower +# 4. Then allows the delivery receipt to go through with false data +# +# The attacker gets a response, but it points to the wrong location. +# This is better than blocking (which reveals the block) — it feeds +# disinformation to the adversary. + +VIGIL_DATA="/data/adb/vigil" +VIGIL_LOG="$VIGIL_DATA/vigil.log" +ALERT_DIR="$VIGIL_DATA/alerts" +HONEYPOT_CONF="$VIGIL_DATA/honeypot.conf" +HONEYPOT_LOG="$VIGIL_DATA/honeypot.log" + +[ -f "$VIGIL_DATA/vigil.conf" ] && . "$VIGIL_DATA/vigil.conf" + +# Default fake locations (world capitals — far from likely real position) +# Format: lat,lon,name +FAKE_LOCATIONS=" +48.8566,2.3522,Paris +35.6762,139.6503,Tokyo +-33.8688,151.2093,Sydney +55.7558,37.6173,Moscow +-22.9068,-43.1729,Rio de Janeiro +51.5074,-0.1278,London +40.4168,-3.7038,Madrid +52.5200,13.4050,Berlin +37.5665,126.9780,Seoul +19.4326,-99.1332,Mexico City +" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] [honeypot] $1" >> "$VIGIL_LOG" +} + +alert() { + local severity="$1" + local message="$2" + local timestamp=$(date +%s) + echo "${severity}|${timestamp}|sms_honeypot|${message}" >> "$ALERT_DIR/pending" + log "ALERT [$severity]: $message" +} + +# Load user-defined fake location or pick random +get_fake_location() { + # Check for user-defined location + if [ -f "$HONEYPOT_CONF" ]; then + local user_lat=$(grep "^FAKE_LAT=" "$HONEYPOT_CONF" 2>/dev/null | cut -d= -f2) + local user_lon=$(grep "^FAKE_LON=" "$HONEYPOT_CONF" 2>/dev/null | cut -d= -f2) + if [ -n "$user_lat" ] && [ -n "$user_lon" ]; then + echo "$user_lat $user_lon user_defined" + return + fi + fi + + # Pick a random location from the list + local count=$(echo "$FAKE_LOCATIONS" | grep -c ",") + local random_idx=$(( $(head -c4 /dev/urandom | od -An -tu4 | tr -d ' ') % count + 1 )) + local location=$(echo "$FAKE_LOCATIONS" | grep "," | sed -n "${random_idx}p" | tr -d ' ') + + local lat=$(echo "$location" | cut -d, -f1) + local lon=$(echo "$location" | cut -d, -f2) + local name=$(echo "$location" | cut -d, -f3) + + echo "$lat $lon $name" +} + +# ── MOCK GPS: Set fake location via Android mock location provider ── +activate_mock_gps() { + local lat="$1" + local lon="$2" + local name="$3" + + log "Activating mock GPS: $lat, $lon ($name)" + + # Enable mock locations (requires developer options, but we have root) + settings put secure mock_location 1 2>/dev/null + + # Use appops to allow our mock location provider + # We use Android's built-in test location capabilities + # Set the mock location via the location manager service + + # Method 1: Use am command to set test provider + # Create a mock location provider + local accuracy=10 # meters + local altitude=50 # meters + local bearing=0 + local speed=0 + + # Write mock location script that continuously feeds fake coordinates + local mock_script="$VIGIL_DATA/.mock_gps_active" + cat > "$mock_script" </dev/null + + cmd location providers set-test-provider-enabled gps true 2>/dev/null + + cmd location providers set-test-provider-location gps --latitude $lat --longitude $lon --altitude $altitude --accuracy $accuracy 2>/dev/null + + # Also try the legacy approach for older Android + am broadcast -a android.location.GPS_FIX_CHANGE --ef latitude $lat --ef longitude $lon 2>/dev/null + + sleep 1 +done +MOCKEOF + chmod 755 "$mock_script" + + # Run mock GPS in background + nohup sh "$mock_script" >> "$HONEYPOT_LOG" 2>&1 & + local mock_pid=$! + echo $mock_pid > "$VIGIL_DATA/.mock_gps_pid" + + log "Mock GPS active: PID $mock_pid, location: $lat, $lon ($name)" + echo "Mock GPS active: $lat, $lon ($name)" +} + +# ── STOP MOCK GPS ── +deactivate_mock_gps() { + if [ -f "$VIGIL_DATA/.mock_gps_pid" ]; then + local pid=$(cat "$VIGIL_DATA/.mock_gps_pid") + kill "$pid" 2>/dev/null + rm -f "$VIGIL_DATA/.mock_gps_pid" + rm -f "$VIGIL_DATA/.mock_gps_active" + + # Clean up test provider + cmd location providers remove-test-provider gps 2>/dev/null + settings put secure mock_location 0 2>/dev/null + + log "Mock GPS deactivated" + echo "Mock GPS deactivated" + else + echo "Mock GPS not active" + fi +} + +# ── HONEYPOT MONITOR: Watch for silent SMS and auto-spoof ── +cmd_monitor() { + log "SMS Honeypot monitor starting..." + echo "SMS Honeypot active — will spoof location on silent SMS detection" + + # Clear logcat buffer + logcat -c 2>/dev/null + + local spoof_active=0 + local spoof_deactivate_time=0 + + logcat -s \ + GsmInboundSmsHandler:* \ + SmsMessage:* \ + InboundSmsHandler:* \ + RIL:* \ + RILJ:* \ + 2>/dev/null | while read -r line; do + + local now=$(date +%s) + + # Check if we should deactivate spoof (after 5 minutes) + if [ $spoof_active -eq 1 ] && [ $now -gt $spoof_deactivate_time ]; then + deactivate_mock_gps + spoof_active=0 + log "Auto-deactivated mock GPS after timeout" + fi + + # Detect silent SMS + if echo "$line" | grep -qiE "type.?0.*sms|sms.*type.?0|class.?0|flash.*sms|TP-PID.*type"; then + alert "CRITICAL" "Silent SMS detected — activating location honeypot" + + # Get fake location + local loc_data=$(get_fake_location) + local fake_lat=$(echo "$loc_data" | awk '{print $1}') + local fake_lon=$(echo "$loc_data" | awk '{print $2}') + local fake_name=$(echo "$loc_data" | awk '{print $3}') + + echo "$(date '+%Y-%m-%d %H:%M:%S')|SPOOF|$fake_lat,$fake_lon|$fake_name" >> "$HONEYPOT_LOG" + + # Activate mock GPS with fake location + if [ $spoof_active -eq 0 ]; then + activate_mock_gps "$fake_lat" "$fake_lon" "$fake_name" + spoof_active=1 + fi + + # Keep spoof active for 5 minutes (allow delivery receipt to go through with fake data) + spoof_deactivate_time=$((now + 300)) + + alert "INFO" "Location spoofed to: $fake_lat, $fake_lon ($fake_name)" + fi + done +} + +# ── SPOOF NOW: Manually activate fake location ── +cmd_spoof() { + local loc_data=$(get_fake_location) + local fake_lat=$(echo "$loc_data" | awk '{print $1}') + local fake_lon=$(echo "$loc_data" | awk '{print $2}') + local fake_name=$(echo "$loc_data" | awk '{print $3}') + + activate_mock_gps "$fake_lat" "$fake_lon" "$fake_name" +} + +# ── SPOOF WITH SPECIFIC LOCATION ── +cmd_spoof_location() { + local lat="$1" + local lon="$2" + + if [ -z "$lat" ] || [ -z "$lon" ]; then + echo "Usage: sms_honeypot.sh spoof-at " + return 1 + fi + + activate_mock_gps "$lat" "$lon" "custom" +} + +# ── CONFIGURE: Set persistent fake location ── +cmd_configure() { + echo "SMS Honeypot Configuration" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "" + echo "Current fake location:" + if [ -f "$HONEYPOT_CONF" ]; then + local lat=$(grep "^FAKE_LAT=" "$HONEYPOT_CONF" 2>/dev/null | cut -d= -f2) + local lon=$(grep "^FAKE_LON=" "$HONEYPOT_CONF" 2>/dev/null | cut -d= -f2) + if [ -n "$lat" ]; then + echo " Custom: $lat, $lon" + else + echo " Random (from world capitals list)" + fi + else + echo " Random (from world capitals list)" + fi + echo "" + echo "To set a specific fake location:" + echo " echo 'FAKE_LAT=48.8566' > $HONEYPOT_CONF" + echo " echo 'FAKE_LON=2.3522' >> $HONEYPOT_CONF" + echo "" + echo "Or use: vigil honeypot spoof-at " + echo "" + echo "Mock GPS status:" + if [ -f "$VIGIL_DATA/.mock_gps_pid" ]; then + local pid=$(cat "$VIGIL_DATA/.mock_gps_pid") + if kill -0 "$pid" 2>/dev/null; then + echo " ACTIVE (PID: $pid)" + else + echo " Stale PID file (not running)" + fi + else + echo " Inactive" + fi +} + +# ── STATUS ── +cmd_status() { + echo "SMS Honeypot Status:" + echo " SMS Fake Response: ${SMS_FAKE_RESPONSE:-0}" + + if [ -f "$VIGIL_DATA/.mock_gps_pid" ]; then + local pid=$(cat "$VIGIL_DATA/.mock_gps_pid") + if kill -0 "$pid" 2>/dev/null; then + echo " Mock GPS: ACTIVE (PID: $pid)" + else + echo " Mock GPS: inactive (stale PID)" + fi + else + echo " Mock GPS: inactive" + fi + + if [ -f "$HONEYPOT_LOG" ]; then + local spoof_count=$(grep -c "SPOOF" "$HONEYPOT_LOG" 2>/dev/null) + echo " Spoofs triggered: $spoof_count" + echo " Last spoof:" + tail -1 "$HONEYPOT_LOG" 2>/dev/null | while read -r line; do + echo " $line" + done + fi +} + +# ── DISPATCH ── +case "$1" in + monitor) cmd_monitor ;; + spoof) cmd_spoof ;; + spoof-at) shift; cmd_spoof_location "$@" ;; + stop) deactivate_mock_gps ;; + configure) cmd_configure ;; + status) cmd_status ;; + *) + echo "SMS Honeypot — Location Spoofing Defense" + echo "Usage: sms_honeypot.sh {monitor|spoof|spoof-at|stop|configure|status}" + echo "" + echo " monitor Auto-spoof on silent SMS detection" + echo " spoof Activate mock GPS with random location" + echo " spoof-at Activate mock GPS at specific coordinates" + echo " stop Deactivate mock GPS" + echo " configure Show/edit honeypot configuration" + echo " status Show honeypot status" + ;; +esac