feat(crowdsec): Add custom CrowdSec scenarios package for SecuBox
- Add secubox-app-crowdsec-custom package with: - HTTP auth bruteforce detection - Path scanning detection - LuCI/uhttpd auth monitoring - Trusted IP whitelist for private networks - Fix Lyrion Docker image path to ghcr.io/lms-community/lyrionmusicserver:stable Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
a23038f779
commit
3e52444a73
113
package/secubox/secubox-app-crowdsec-custom/Makefile
Normal file
113
package/secubox/secubox-app-crowdsec-custom/Makefile
Normal file
@ -0,0 +1,113 @@
|
||||
# Copyright (C) 2024-2025 CyberMind.fr
|
||||
# Licensed under Apache-2.0
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=secubox-app-crowdsec-custom
|
||||
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-app-crowdsec-custom
|
||||
SECTION:=secubox
|
||||
CATEGORY:=SecuBox
|
||||
TITLE:=CrowdSec Custom Scenarios for SecuBox
|
||||
DEPENDS:=+crowdsec +crowdsec-firewall-bouncer
|
||||
PKGARCH:=all
|
||||
PROVIDES:=secubox-crowdsec-custom
|
||||
endef
|
||||
|
||||
define Package/secubox-app-crowdsec-custom/description
|
||||
Custom CrowdSec configurations for SecuBox web interface protection.
|
||||
Includes:
|
||||
- HTTP authentication bruteforce detection
|
||||
- Path scanning/enumeration detection
|
||||
- LuCI/uhttpd auth failure monitoring
|
||||
- Nginx reverse proxy monitoring (if used)
|
||||
- Whitelist for trusted networks
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/secubox-app-crowdsec-custom/install
|
||||
# Acquisition configs
|
||||
$(INSTALL_DIR) $(1)/etc/crowdsec/acquis.d
|
||||
$(INSTALL_DATA) ./files/acquis.d/secubox-uhttpd.yaml $(1)/etc/crowdsec/acquis.d/
|
||||
$(INSTALL_DATA) ./files/acquis.d/secubox-nginx.yaml $(1)/etc/crowdsec/acquis.d/
|
||||
$(INSTALL_DATA) ./files/acquis.d/secubox-auth.yaml $(1)/etc/crowdsec/acquis.d/
|
||||
|
||||
# Custom parsers
|
||||
$(INSTALL_DIR) $(1)/etc/crowdsec/parsers/s01-parse
|
||||
$(INSTALL_DATA) ./files/parsers/s01-parse/secubox-luci-auth.yaml $(1)/etc/crowdsec/parsers/s01-parse/
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/crowdsec/parsers/s02-enrich
|
||||
$(INSTALL_DATA) ./files/parsers/s02-enrich/secubox-whitelist.yaml $(1)/etc/crowdsec/parsers/s02-enrich/
|
||||
|
||||
# Custom scenarios
|
||||
$(INSTALL_DIR) $(1)/etc/crowdsec/scenarios
|
||||
$(INSTALL_DATA) ./files/scenarios/secubox-auth-bruteforce.yaml $(1)/etc/crowdsec/scenarios/
|
||||
$(INSTALL_DATA) ./files/scenarios/secubox-http-bruteforce.yaml $(1)/etc/crowdsec/scenarios/
|
||||
|
||||
# UCI defaults for first boot setup
|
||||
$(INSTALL_DIR) $(1)/etc/uci-defaults
|
||||
$(INSTALL_BIN) ./files/99-secubox-app-crowdsec-custom $(1)/etc/uci-defaults/
|
||||
endef
|
||||
|
||||
define Package/secubox-app-crowdsec-custom/postinst
|
||||
#!/bin/sh
|
||||
[ -n "$${IPKG_INSTROOT}" ] || {
|
||||
echo "Installing CrowdSec collections for SecuBox..."
|
||||
|
||||
# Install standard collections
|
||||
cscli collections install crowdsecurity/linux 2>/dev/null || true
|
||||
cscli collections install crowdsecurity/sshd 2>/dev/null || true
|
||||
cscli collections install crowdsecurity/base-http-scenarios 2>/dev/null || true
|
||||
cscli collections install crowdsecurity/http-cve 2>/dev/null || true
|
||||
cscli collections install crowdsecurity/nginx 2>/dev/null || true
|
||||
cscli collections install crowdsecurity/http-dos 2>/dev/null || true
|
||||
|
||||
# Install parsers
|
||||
cscli parsers install crowdsecurity/syslog-logs 2>/dev/null || true
|
||||
cscli parsers install crowdsecurity/http-logs 2>/dev/null || true
|
||||
cscli parsers install crowdsecurity/nginx-logs 2>/dev/null || true
|
||||
|
||||
# Run uci-defaults
|
||||
/etc/uci-defaults/99-secubox-app-crowdsec-custom 2>/dev/null || true
|
||||
|
||||
# Restart CrowdSec to load new configs
|
||||
/etc/init.d/crowdsec restart 2>/dev/null || true
|
||||
sleep 2
|
||||
|
||||
# Restart bouncer
|
||||
if [ -f /etc/init.d/crowdsec-firewall-bouncer ]; then
|
||||
/etc/init.d/crowdsec-firewall-bouncer restart 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "SecuBox CrowdSec protection installed!"
|
||||
echo "Protected paths: /secubox/, /cgi-bin/luci, /ubus"
|
||||
echo ""
|
||||
echo "Useful commands:"
|
||||
echo " cscli metrics - View detection metrics"
|
||||
echo " cscli alerts list - View security alerts"
|
||||
echo " cscli decisions list - View active bans"
|
||||
}
|
||||
exit 0
|
||||
endef
|
||||
|
||||
define Package/secubox-app-crowdsec-custom/postrm
|
||||
#!/bin/sh
|
||||
[ -n "$${IPKG_INSTROOT}" ] || {
|
||||
# Restart CrowdSec to unload configs
|
||||
/etc/init.d/crowdsec restart 2>/dev/null || true
|
||||
echo "SecuBox CrowdSec custom configs removed"
|
||||
}
|
||||
exit 0
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,secubox-app-crowdsec-custom))
|
||||
@ -0,0 +1,36 @@
|
||||
#!/bin/sh
|
||||
# SecuBox CrowdSec Custom - First boot setup
|
||||
# Configures logging for CrowdSec monitoring
|
||||
|
||||
# Enable uhttpd syslog logging
|
||||
if command -v uci >/dev/null 2>&1; then
|
||||
uci set uhttpd.main.syslog='1' 2>/dev/null
|
||||
uci commit uhttpd 2>/dev/null
|
||||
fi
|
||||
|
||||
# Ensure syslog writes to file for CrowdSec
|
||||
if [ -f /etc/config/system ]; then
|
||||
uci set system.@system[0].log_file='/var/log/messages' 2>/dev/null
|
||||
uci set system.@system[0].log_size='512' 2>/dev/null
|
||||
uci commit system 2>/dev/null
|
||||
fi
|
||||
|
||||
# Restart logging service
|
||||
/etc/init.d/log restart 2>/dev/null || true
|
||||
|
||||
# Restart uhttpd to apply logging changes
|
||||
/etc/init.d/uhttpd restart 2>/dev/null || true
|
||||
|
||||
# Register firewall bouncer if not already registered
|
||||
if [ -f /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml ]; then
|
||||
if command -v cscli >/dev/null 2>&1; then
|
||||
if ! cscli bouncers list 2>/dev/null | grep -q "firewall-bouncer"; then
|
||||
API_KEY=$(cscli bouncers add firewall-bouncer -o raw 2>/dev/null)
|
||||
if [ -n "$API_KEY" ]; then
|
||||
sed -i "s/^api_key:.*/api_key: $API_KEY/" /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@ -0,0 +1,17 @@
|
||||
# CrowdSec acquisition for SecuBox/LuCI authentication
|
||||
# Monitors syslog for auth failures
|
||||
|
||||
# Monitor OpenWrt syslog
|
||||
source: file
|
||||
filenames:
|
||||
- /var/log/messages
|
||||
- /tmp/log/messages
|
||||
labels:
|
||||
type: syslog
|
||||
---
|
||||
# Monitor auth.log if available
|
||||
source: file
|
||||
filenames:
|
||||
- /var/log/auth.log
|
||||
labels:
|
||||
type: syslog
|
||||
@ -0,0 +1,9 @@
|
||||
# CrowdSec acquisition for nginx reverse proxy (if used)
|
||||
# Monitors nginx logs for web attacks
|
||||
|
||||
filenames:
|
||||
- /var/log/nginx/access.log
|
||||
- /var/log/nginx/error.log
|
||||
- /var/log/nginx/*access*.log
|
||||
labels:
|
||||
type: nginx
|
||||
@ -0,0 +1,8 @@
|
||||
# CrowdSec acquisition for SecuBox web interface (uhttpd)
|
||||
# Monitors uhttpd logs for web attacks
|
||||
|
||||
filenames:
|
||||
- /var/log/uhttpd.log
|
||||
- /tmp/log/uhttpd.log
|
||||
labels:
|
||||
type: syslog
|
||||
@ -0,0 +1,43 @@
|
||||
# CrowdSec parser for SecuBox/LuCI authentication logs
|
||||
# Parses authentication events from uhttpd, luci, and rpcd
|
||||
|
||||
onsuccess: next_stage
|
||||
name: secubox/luci-auth-logs
|
||||
description: "Parse SecuBox/LuCI authentication events"
|
||||
filter: "evt.Parsed.program == 'uhttpd' || evt.Parsed.program == 'luci' || evt.Parsed.program == 'rpcd'"
|
||||
grok:
|
||||
pattern: "%{GREEDYDATA:message}"
|
||||
apply_on: message
|
||||
statics:
|
||||
- meta: log_type
|
||||
value: luci_auth
|
||||
- meta: service
|
||||
value: secubox
|
||||
---
|
||||
# Parse LuCI login failures
|
||||
onsuccess: next_stage
|
||||
name: secubox/luci-auth-failure
|
||||
description: "Parse LuCI authentication failures"
|
||||
filter: "evt.Parsed.program == 'luci' && evt.Parsed.message contains 'auth'"
|
||||
grok:
|
||||
pattern: "luci: %{WORD:action} from %{IP:source_ip}.*(?:failed|denied|invalid)"
|
||||
apply_on: message
|
||||
statics:
|
||||
- meta: auth_success
|
||||
value: "false"
|
||||
- meta: source_ip
|
||||
expression: evt.Parsed.source_ip
|
||||
---
|
||||
# Parse uhttpd/rpcd auth attempts
|
||||
onsuccess: next_stage
|
||||
name: secubox/uhttpd-auth
|
||||
description: "Parse uhttpd authentication events"
|
||||
filter: "evt.Parsed.program == 'uhttpd' || evt.Parsed.program == 'rpcd'"
|
||||
grok:
|
||||
pattern: "%{IP:source_ip}.*(?:login|auth|session).*(?:failed|denied|invalid|error)"
|
||||
apply_on: message
|
||||
statics:
|
||||
- meta: auth_success
|
||||
value: "false"
|
||||
- meta: log_type
|
||||
value: luci_auth
|
||||
@ -0,0 +1,18 @@
|
||||
# CrowdSec whitelist for SecuBox trusted networks
|
||||
# Prevents banning of internal/trusted IPs
|
||||
|
||||
name: crowdsecurity/secubox-whitelist
|
||||
description: "Whitelist trusted IPs for SecuBox admin access"
|
||||
whitelist:
|
||||
reason: "SecuBox trusted network"
|
||||
ip:
|
||||
# Localhost
|
||||
- "127.0.0.1"
|
||||
- "::1"
|
||||
cidr:
|
||||
# Private networks (RFC1918)
|
||||
- "192.168.0.0/16"
|
||||
- "172.16.0.0/12"
|
||||
- "10.0.0.0/8"
|
||||
# Add custom admin IPs here if needed
|
||||
# - "YOUR_ADMIN_IP/32"
|
||||
@ -0,0 +1,15 @@
|
||||
# CrowdSec scenario for SecuBox/LuCI authentication bruteforce
|
||||
# Detects repeated authentication failures
|
||||
|
||||
type: leaky
|
||||
name: secubox/luci-auth-bruteforce
|
||||
description: "Detect bruteforce attempts on SecuBox/LuCI web interface"
|
||||
filter: "evt.Meta.log_type == 'luci_auth' && evt.Meta.auth_success == 'false'"
|
||||
groupby: evt.Meta.source_ip
|
||||
capacity: 5
|
||||
leakspeed: 30s
|
||||
blackhole: 5m
|
||||
labels:
|
||||
service: secubox
|
||||
type: bruteforce
|
||||
remediation: true
|
||||
@ -0,0 +1,39 @@
|
||||
# CrowdSec scenario for SecuBox HTTP authentication bruteforce
|
||||
# Detects repeated 401/403 errors indicating auth failures
|
||||
|
||||
type: leaky
|
||||
name: secubox/http-auth-bruteforce
|
||||
description: "Detect HTTP authentication bruteforce on SecuBox web interface"
|
||||
filter: |
|
||||
evt.Meta.http_status in ['401', '403'] &&
|
||||
evt.Parsed.request contains '/cgi-bin/luci' ||
|
||||
evt.Parsed.request contains '/secubox/' ||
|
||||
evt.Parsed.request contains '/ubus'
|
||||
groupby: evt.Meta.source_ip
|
||||
capacity: 5
|
||||
leakspeed: 30s
|
||||
blackhole: 5m
|
||||
labels:
|
||||
service: secubox
|
||||
type: http_bruteforce
|
||||
remediation: true
|
||||
---
|
||||
# Detect path scanning/enumeration
|
||||
type: leaky
|
||||
name: secubox/path-scanning
|
||||
description: "Detect path scanning on SecuBox web interface"
|
||||
filter: |
|
||||
evt.Meta.http_status == '404' &&
|
||||
(evt.Parsed.request contains '/secubox/' ||
|
||||
evt.Parsed.request contains '/cgi-bin/' ||
|
||||
evt.Parsed.request contains '/admin' ||
|
||||
evt.Parsed.request contains '/wp-' ||
|
||||
evt.Parsed.request contains '.php')
|
||||
groupby: evt.Meta.source_ip
|
||||
capacity: 20
|
||||
leakspeed: 10s
|
||||
blackhole: 10m
|
||||
labels:
|
||||
service: secubox
|
||||
type: path_scan
|
||||
remediation: true
|
||||
@ -1,7 +1,7 @@
|
||||
config lyrion 'main'
|
||||
option enabled '0'
|
||||
option runtime 'auto'
|
||||
option image 'ghcr.io/lyrion/lyrion:latest'
|
||||
option image 'ghcr.io/lms-community/lyrionmusicserver:stable'
|
||||
option data_path '/srv/lyrion'
|
||||
option media_path '/srv/media'
|
||||
option port '9000'
|
||||
|
||||
@ -49,7 +49,7 @@ uci_set() { uci set ${CONFIG}.main.$1="$2" && uci commit ${CONFIG}; }
|
||||
# Load configuration with defaults
|
||||
load_config() {
|
||||
runtime="$(uci_get runtime || echo auto)"
|
||||
image="$(uci_get image || echo ghcr.io/lyrion/lyrion:latest)"
|
||||
image="$(uci_get image || echo ghcr.io/lms-community/lyrionmusicserver:stable)"
|
||||
data_path="$(uci_get data_path || echo /srv/lyrion)"
|
||||
media_path="$(uci_get media_path || echo /srv/media)"
|
||||
port="$(uci_get port || echo 9000)"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user