secubox-openwrt/package/secubox/secubox-auth-logger/files/auth-monitor.sh
CyberMind-FR 3b84c8a047 feat(secubox-auth-logger): Add auth failure monitoring for CrowdSec
- Create secubox-auth-logger package to monitor SSH/LuCI auth failures
- auth-monitor.sh watches logread for failed password attempts
- Supports OpenSSH, Dropbear, and uhttpd/LuCI authentication
- Logs failures to syslog with secubox-auth tag for CrowdSec parsing
- Fix wizard.js syntax error with computed property names
- Remove broken Dropbear verbose config (2024.86 doesn't support -v)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 09:35:20 +01:00

108 lines
3.6 KiB
Bash

#!/bin/sh
# SecuBox Auth Monitor - Lightweight auth failure detection
# Monitors SSH and LuCI login failures, logs to syslog for CrowdSec
# Copyright (C) 2024 CyberMind.fr
LOG_TAG="secubox-auth"
# Track recent IPs to avoid duplicate logging
TRACK_FILE="/tmp/auth-monitor-track"
touch "$TRACK_FILE"
log_failure() {
local service="$1"
local ip="$2"
local user="${3:-root}"
# Avoid duplicate logs within 60 seconds
local key="${service}:${ip}"
local now=$(date +%s)
if grep -q "^${key}:" "$TRACK_FILE" 2>/dev/null; then
local last=$(grep "^${key}:" "$TRACK_FILE" | cut -d: -f3)
if [ $((now - last)) -lt 60 ]; then
return
fi
sed -i "/^${key}:/d" "$TRACK_FILE"
fi
echo "${key}:${now}" >> "$TRACK_FILE"
# Log to syslog - CrowdSec will parse this
logger -t "$LOG_TAG" -p auth.warning "authentication failure for $user from $ip via $service"
}
# Monitor logread for auth failures
monitor_logs() {
logread -f 2>/dev/null | while read line; do
# OpenSSH failures
# Format: sshd[xxx]: Failed password for root from 1.2.3.4 port xxx
if echo "$line" | grep -qi "sshd.*failed.*password"; then
ip=$(echo "$line" | grep -oE 'from [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | awk '{print $2}')
user=$(echo "$line" | grep -oE 'for [^ ]+' | awk '{print $2}')
[ -n "$ip" ] && log_failure "ssh" "$ip" "$user"
fi
# OpenSSH invalid user
# Format: sshd[xxx]: Invalid user xxx from 1.2.3.4
if echo "$line" | grep -qi "sshd.*invalid.user"; then
ip=$(echo "$line" | grep -oE 'from [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | awk '{print $2}')
user=$(echo "$line" | grep -oE 'user [^ ]+' | awk '{print $2}')
[ -n "$ip" ] && log_failure "ssh" "$ip" "${user:-unknown}"
fi
# Dropbear failures (if ever enabled)
# Format: dropbear[xxx]: Bad password attempt for 'root' from x.x.x.x:port
if echo "$line" | grep -qi "dropbear.*bad.password"; then
ip=$(echo "$line" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)
user=$(echo "$line" | grep -oE "for '[^']+'" | tr -d "'" | awk '{print $2}')
[ -n "$ip" ] && log_failure "ssh" "$ip" "$user"
fi
# uhttpd/LuCI - Look for failed POST to login
# When uhttpd syslog is enabled, failed logins redirect with 302/403
if echo "$line" | grep -qi "uhttpd.*POST.*/cgi-bin/luci"; then
ip=$(echo "$line" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)
# Check if this is followed by a failure indicator
if echo "$line" | grep -qE "403|401"; then
[ -n "$ip" ] && log_failure "luci" "$ip"
fi
fi
# rpcd session errors
if echo "$line" | grep -qi "rpcd.*access.denied\|ubus.*error"; then
ip=$(echo "$line" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)
[ -n "$ip" ] && log_failure "luci" "$ip"
fi
done
}
# Cleanup old tracking entries (older than 5 minutes)
cleanup_tracking() {
while true; do
sleep 300
local now=$(date +%s)
local tmp=$(mktemp)
while read line; do
local ts=$(echo "$line" | cut -d: -f3)
if [ $((now - ts)) -lt 300 ]; then
echo "$line"
fi
done < "$TRACK_FILE" > "$tmp"
mv "$tmp" "$TRACK_FILE"
done
}
case "$1" in
start)
cleanup_tracking &
monitor_logs
;;
*)
echo "Usage: $0 start"
echo "Monitors auth failures and logs to syslog for CrowdSec"
exit 1
;;
esac