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>
This commit is contained in:
parent
f917b5412c
commit
3b84c8a047
@ -644,10 +644,10 @@ return view.extend({
|
||||
];
|
||||
|
||||
var renderCheckboxItem = function(item, type) {
|
||||
return E('div', {
|
||||
var attrs = {
|
||||
'class': 'collection-item',
|
||||
'data-' + type: item.name,
|
||||
'data-type': type,
|
||||
'data-name': item.name,
|
||||
'data-checked': item.preselected ? '1' : '0',
|
||||
'style': 'display: flex; align-items: center; cursor: pointer;',
|
||||
'click': function(ev) {
|
||||
@ -661,7 +661,8 @@ return view.extend({
|
||||
checkbox.style.color = newState ? '#22c55e' : '#94a3b8';
|
||||
}
|
||||
}
|
||||
}, [
|
||||
};
|
||||
return E('div', attrs, [
|
||||
E('span', {
|
||||
'class': 'checkbox-indicator',
|
||||
'style': 'display: inline-block; font-size: 28px; margin-right: 16px; user-select: none; color: ' + (item.preselected ? '#22c55e' : '#94a3b8') + '; line-height: 1; min-width: 28px;'
|
||||
@ -1143,16 +1144,16 @@ return view.extend({
|
||||
|
||||
handleInstallCollections: function() {
|
||||
// Read collections from data-checked attributes
|
||||
var collectionItems = document.querySelectorAll('.collection-item[data-collection]');
|
||||
var collectionItems = document.querySelectorAll('.collection-item[data-type="collection"]');
|
||||
var selectedCollections = Array.from(collectionItems)
|
||||
.filter(function(item) { return item.getAttribute('data-checked') === '1'; })
|
||||
.map(function(item) { return item.getAttribute('data-collection'); });
|
||||
.map(function(item) { return item.getAttribute('data-name'); });
|
||||
|
||||
// Read parsers from data-checked attributes
|
||||
var parserItems = document.querySelectorAll('.collection-item[data-parser]');
|
||||
var parserItems = document.querySelectorAll('.collection-item[data-type="parser"]');
|
||||
var selectedParsers = Array.from(parserItems)
|
||||
.filter(function(item) { return item.getAttribute('data-checked') === '1'; })
|
||||
.map(function(item) { return item.getAttribute('data-parser'); });
|
||||
.map(function(item) { return item.getAttribute('data-name'); });
|
||||
|
||||
console.log('[Wizard] Selected collections:', selectedCollections);
|
||||
console.log('[Wizard] Selected parsers:', selectedParsers);
|
||||
|
||||
@ -1364,15 +1364,11 @@ configure_acquisition() {
|
||||
uci commit crowdsec
|
||||
steps_done="${steps_done}Updated UCI settings; "
|
||||
|
||||
# Step 3: Enable verbose logging for services that need it
|
||||
# Dropbear SSH needs verbose mode to log authentication failures
|
||||
# Step 3: Note on Dropbear SSH logging
|
||||
# Dropbear 2024.86 does NOT support -v flag or verbose UCI option
|
||||
# Auth failures are detected via auth-monitor.sh parsing syslog messages
|
||||
if [ "$ssh_enabled" = "1" ]; then
|
||||
if uci -q get dropbear.@dropbear[0] >/dev/null 2>&1; then
|
||||
uci set dropbear.@dropbear[0].verbose='1'
|
||||
uci commit dropbear
|
||||
/etc/init.d/dropbear restart >/dev/null 2>&1
|
||||
steps_done="${steps_done}Enabled Dropbear verbose logging; "
|
||||
fi
|
||||
steps_done="${steps_done}SSH detection enabled via syslog monitoring; "
|
||||
fi
|
||||
|
||||
# Enable uhttpd syslog for HTTP auth logging
|
||||
|
||||
52
package/secubox/secubox-auth-logger/Makefile
Normal file
52
package/secubox/secubox-auth-logger/Makefile
Normal file
@ -0,0 +1,52 @@
|
||||
# Copyright (C) 2024 CyberMind.fr
|
||||
# Licensed under Apache-2.0
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=secubox-auth-logger
|
||||
PKG_VERSION:=1.0.0
|
||||
PKG_RELEASE:=1
|
||||
PKG_ARCH:=all
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
PKG_MAINTAINER:=CyberMind <contact@cybermind.fr>
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/secubox-auth-logger
|
||||
SECTION:=secubox
|
||||
CATEGORY:=SecuBox
|
||||
TITLE:=Authentication Failure Logger for CrowdSec
|
||||
DEPENDS:=+rpcd +uhttpd
|
||||
PKGARCH:=all
|
||||
endef
|
||||
|
||||
define Package/secubox-auth-logger/description
|
||||
Logs authentication failures from LuCI/rpcd and Dropbear SSH
|
||||
for CrowdSec detection. Patches rpcd to emit auth failure logs
|
||||
to syslog in a format CrowdSec can parse.
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/secubox-auth-logger/install
|
||||
$(INSTALL_DIR) $(1)/usr/lib/secubox
|
||||
$(INSTALL_BIN) ./files/auth-monitor.sh $(1)/usr/lib/secubox/
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_BIN) ./files/secubox-auth-logger.init $(1)/etc/init.d/secubox-auth-logger
|
||||
$(INSTALL_DIR) $(1)/etc/crowdsec/parsers/s01-parse
|
||||
$(INSTALL_DATA) ./files/openwrt-luci-auth.yaml $(1)/etc/crowdsec/parsers/s01-parse/
|
||||
$(INSTALL_DIR) $(1)/etc/uci-defaults
|
||||
$(INSTALL_BIN) ./files/99-secubox-auth-logger $(1)/etc/uci-defaults/
|
||||
endef
|
||||
|
||||
define Package/secubox-auth-logger/postinst
|
||||
#!/bin/sh
|
||||
[ -n "$${IPKG_INSTROOT}" ] || {
|
||||
/etc/init.d/secubox-auth-logger enable
|
||||
/etc/init.d/secubox-auth-logger start
|
||||
}
|
||||
exit 0
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,secubox-auth-logger))
|
||||
@ -0,0 +1,34 @@
|
||||
#!/bin/sh
|
||||
# SecuBox Auth Logger - Post-install configuration
|
||||
# Enables verbose logging for Dropbear and uhttpd
|
||||
|
||||
# Note: Dropbear 2024.86 does NOT support -v flag
|
||||
# Auth monitoring relies on parsing existing syslog messages
|
||||
# The auth-monitor.sh script watches logread for auth failures
|
||||
|
||||
# Enable uhttpd syslog
|
||||
if [ -f /etc/config/uhttpd ]; then
|
||||
uci set uhttpd.main.syslog='1'
|
||||
uci commit uhttpd
|
||||
/etc/init.d/uhttpd restart 2>/dev/null
|
||||
fi
|
||||
|
||||
# Create auth failures log file
|
||||
touch /var/log/auth-failures.log
|
||||
chmod 644 /var/log/auth-failures.log
|
||||
|
||||
# Add acquisition for CrowdSec if installed
|
||||
if [ -d /etc/crowdsec/acquis.d ]; then
|
||||
cat > /etc/crowdsec/acquis.d/secubox-auth.yaml << 'EOF'
|
||||
# SecuBox Auth Failure Acquisition
|
||||
# Reads from /var/log/messages for secubox-auth tagged messages
|
||||
filenames:
|
||||
- /var/log/messages
|
||||
labels:
|
||||
type: syslog
|
||||
EOF
|
||||
# Restart CrowdSec to pick up new acquisition
|
||||
/etc/init.d/crowdsec restart 2>/dev/null
|
||||
fi
|
||||
|
||||
exit 0
|
||||
107
package/secubox/secubox-auth-logger/files/auth-monitor.sh
Normal file
107
package/secubox/secubox-auth-logger/files/auth-monitor.sh
Normal file
@ -0,0 +1,107 @@
|
||||
#!/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
|
||||
@ -0,0 +1,20 @@
|
||||
# CrowdSec Parser for SecuBox Auth Logger
|
||||
# Parses authentication failures from LuCI/uhttpd and Dropbear
|
||||
# Format: secubox-auth: Authentication failure for <user> from <ip> via <service>
|
||||
|
||||
name: secubox/openwrt-luci-auth
|
||||
description: "Parse SecuBox auth failure logs for LuCI and SSH"
|
||||
filter: "evt.Parsed.program == 'secubox-auth'"
|
||||
onsuccess: next_stage
|
||||
|
||||
nodes:
|
||||
- grok:
|
||||
pattern: "Authentication failure for %{USERNAME:user} from %{IP:source_ip} via %{WORD:service}"
|
||||
apply_on: message
|
||||
statics:
|
||||
- meta: log_type
|
||||
value: auth_failure
|
||||
- meta: service
|
||||
expression: evt.Parsed.service
|
||||
- meta: source_ip
|
||||
expression: evt.Parsed.source_ip
|
||||
@ -0,0 +1,23 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# SecuBox Authentication Logger
|
||||
# Monitors SSH and LuCI auth failures for CrowdSec
|
||||
# Copyright (C) 2024 CyberMind.fr
|
||||
|
||||
START=99
|
||||
STOP=10
|
||||
USE_PROCD=1
|
||||
|
||||
PROG=/usr/lib/secubox/auth-monitor.sh
|
||||
|
||||
start_service() {
|
||||
procd_open_instance
|
||||
procd_set_param command "$PROG" start
|
||||
procd_set_param respawn
|
||||
procd_set_param stdout 0
|
||||
procd_set_param stderr 1
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "secubox-auth-logger"
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user