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
This commit is contained in:
110
customize.sh
110
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."
|
||||
|
||||
20
service.sh
20
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 &
|
||||
|
||||
110
vigil/bin/vigil
110
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 <command> [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 ;;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
273
vigil/lib/antiforensics.sh
Executable file
273
vigil/lib/antiforensics.sh
Executable file
@@ -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
|
||||
333
vigil/lib/app_honeypot.sh
Executable file
333
vigil/lib/app_honeypot.sh
Executable file
@@ -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 <package_name>"
|
||||
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 <package_name>"
|
||||
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 <package_name>"
|
||||
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 <pkg> Strip dangerous permissions from an app"
|
||||
echo " sandbox <pkg> Move app to restricted user profile"
|
||||
echo " feed <pkg> Feed fake data to an app (honeypot)"
|
||||
echo " auto Auto-honeypot all detected threat apps"
|
||||
echo " status Show honeypot status"
|
||||
;;
|
||||
esac
|
||||
651
vigil/lib/deep_scan.sh
Executable file
651
vigil/lib/deep_scan.sh
Executable file
@@ -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
|
||||
263
vigil/lib/duress.sh
Executable file
263
vigil/lib/duress.sh
Executable file
@@ -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=<your-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
|
||||
306
vigil/lib/ioc_updater.sh
Executable file
306
vigil/lib/ioc_updater.sh
Executable file
@@ -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
|
||||
312
vigil/lib/sms_honeypot.sh
Executable file
312
vigil/lib/sms_honeypot.sh
Executable file
@@ -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" <<MOCKEOF
|
||||
#!/system/bin/sh
|
||||
# Mock GPS feeder — feeds fake location continuously
|
||||
# Kill this script's PID to stop
|
||||
|
||||
while true; do
|
||||
# Use Android's cmd location command (Android 12+)
|
||||
cmd location providers add-test-provider gps requiresNetwork=false requiresSatellite=false requiresCell=false hasMonetaryCost=false supportsAltitude=true supportsSpeed=false supportsBearing=false powerRequirement=1 accuracy=1 2>/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 <latitude> <longitude>"
|
||||
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 <lat> <lon>"
|
||||
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 <lat> <lon> Activate mock GPS at specific coordinates"
|
||||
echo " stop Deactivate mock GPS"
|
||||
echo " configure Show/edit honeypot configuration"
|
||||
echo " status Show honeypot status"
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user