From 31801a6c1dd471a634b3435f848f6c0144f09eaf Mon Sep 17 00:00:00 2001 From: jknapp Date: Mon, 25 Aug 2025 12:39:15 -0700 Subject: [PATCH] Make scan detection more targeted to avoid false positives MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Major changes to prevent legitimate users from being blocked: 1. Increased thresholds significantly: - Initial trigger: 10 → 25 errors - Medium level: 20 → 40 errors - High level: 35 → 60 errors - Critical level: 50 → 100 errors 2. Only count actual scan attempts as errors: - Script files: .php, .asp, .jsp, .cgi, .pl, .py, .rb, .sh - Admin paths: /wp-admin, /phpmyadmin, /adminer - Config files: .env, .git, .htaccess, .ini, .yml - Backup files: .backup, .bak, .sql, .dump - Known vulnerable paths: /cgi-bin, /fckeditor 3. Explicitly exclude legitimate assets from counting: - Images: .jpg, .png, .gif, .svg, .webp - Fonts: .woff, .woff2, .ttf, .eot, .otf - Static: .css, .js, .map, .pdf - Common paths: /static/, /assets/, /fonts/, /images/ 4. Still count all 401/403 errors (auth failures are suspicious) This prevents missing fonts, images, CSS files from triggering blocks while still catching actual vulnerability scanners. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- scripts/show-tarpit-ips.sh | 17 ++++++++-------- templates/hap_backend.tpl | 29 ++++++++++++++++++++++------ templates/hap_backend_basic.tpl | 27 ++++++++++++++++++-------- templates/hap_backend_http_check.tpl | 27 ++++++++++++++++++-------- templates/hap_listener.tpl | 8 ++++---- 5 files changed, 74 insertions(+), 34 deletions(-) diff --git a/scripts/show-tarpit-ips.sh b/scripts/show-tarpit-ips.sh index 13118b6..491df09 100755 --- a/scripts/show-tarpit-ips.sh +++ b/scripts/show-tarpit-ips.sh @@ -75,17 +75,17 @@ printf "@!%s show table web\n" "${PROCESS_ID}" | socat stdio "$SOCKET" 2>/dev/nu # Determine status based on scan count and escalation status="" - if [ "$gpc0" -ge 50 ]; then + if [ "$gpc0" -ge 100 ]; then status="BLOCKED (429)" - elif [ "$gpc0" -ge 35 ]; then + elif [ "$gpc0" -ge 60 ]; then status="SILENT-DROP" - elif [ "$gpc0" -ge 20 ]; then + elif [ "$gpc0" -ge 40 ]; then if [ "$gpc1" -ge 2 ]; then status="SILENT-DROP (repeat)" else status="TARPIT 10s" fi - elif [ "$gpc0" -ge 10 ]; then + elif [ "$gpc0" -ge 25 ]; then status="TARPIT 10s" else status="Normal" @@ -104,12 +104,13 @@ printf "@!%s show table web\n" "${PROCESS_ID}" | socat stdio "$SOCKET" 2>/dev/nu echo echo "===================================================================" echo "Legend:" -echo " - Scan Count 10-19: Low scanner → TARPIT 10s delay" -echo " - Scan Count 20-34: Medium scanner → TARPIT 10s (1st), SILENT-DROP (repeat)" -echo " - Scan Count 35-49: High scanner → SILENT-DROP (immediate disconnect)" -echo " - Scan Count 50+: Critical scanner → BLOCKED (429 response)" +echo " - Scan Count 25-39: Low scanner → TARPIT 10s delay" +echo " - Scan Count 40-59: Medium scanner → TARPIT 10s (1st), SILENT-DROP (repeat)" +echo " - Scan Count 60-99: High scanner → SILENT-DROP (immediate disconnect)" +echo " - Scan Count 100+: Critical scanner → BLOCKED (429 response)" echo " - Burst (5+ in 10s): → TARPIT 10s (1st), SILENT-DROP (repeat)" echo "===================================================================" +echo "Note: Only counts suspicious scripts/configs, NOT missing images/fonts/CSS" echo "Note: IPs are tracked for 1 hour since last activity" echo echo "To clear a specific IP from the table:" diff --git a/templates/hap_backend.tpl b/templates/hap_backend.tpl index 27d4194..60a7b37 100644 --- a/templates/hap_backend.tpl +++ b/templates/hap_backend.tpl @@ -6,17 +6,34 @@ backend {{ name }}-backend http-request set-header X-Real-IP %[var(txn.real_ip)] {% if ssl_enabled %}http-request set-header X-Forwarded-Proto https if { ssl_fc }{% endif %} - # Define scanning attempt patterns + # Define error status codes acl is_404_error status 404 acl is_403_error status 403 acl is_401_error status 401 acl is_400_error status 400 - acl is_scan_attempt status 400 401 403 404 - # Additional suspicious patterns - acl suspicious_path path_reg -i \.(php|asp|aspx|jsp|cgi)$ - acl suspicious_path path_reg -i /(wp-admin|phpmyadmin|admin|login|xmlrpc) - acl suspicious_path path_reg -i \.(env|git|svn|backup|bak|old) + # Define suspicious scan patterns - only these count as scan attempts + # Script/config files that shouldn't exist on most sites + acl scan_scripts path_reg -i \.(php|asp|aspx|jsp|cgi|pl|py|rb|sh|bash)$ + acl scan_admin path_reg -i /(wp-admin|wp-login|phpmyadmin|adminer|manager|admin-console) + acl scan_configs path_reg -i \.(env|git|svn|htaccess|htpasswd|ini|conf|config|yml|yaml|toml) + acl scan_backups path_reg -i \.(backup|bak|old|orig|save|swp|sql|db|dump|tar|zip|rar|7z) + acl scan_vulns path_reg -i /(cgi-bin|fckeditor|tiny_mce|ckfinder|userfiles|filemanager) + + # Combine all scan patterns + acl is_suspicious_request scan_scripts or scan_admin or scan_configs or scan_backups or scan_vulns + + # Define legitimate static assets that should NOT count as scan attempts + acl legitimate_assets path_reg -i \.(css|js|jpg|jpeg|png|gif|svg|ico|woff|woff2|ttf|eot|otf|map|webp|mp4|webm|pdf)$ + acl legitimate_paths path_beg /static/ /assets/ /media/ /images/ /fonts/ /css/ /js/ + + # Only count as scan attempt if it's: + # - A suspicious request with 404 status, OR + # - Any 401/403 error (auth failures are always suspicious) + # Exclude legitimate asset 404s (like missing fonts, images, etc.) + acl is_scan_attempt is_suspicious_request is_404_error !legitimate_assets !legitimate_paths + acl is_scan_attempt is_403_error !legitimate_assets !legitimate_paths + acl is_scan_attempt is_401_error # Track scan attempts in the frontend stick table # This increments the counter AFTER the backend responds with an error diff --git a/templates/hap_backend_basic.tpl b/templates/hap_backend_basic.tpl index 5ef92d9..961a764 100644 --- a/templates/hap_backend_basic.tpl +++ b/templates/hap_backend_basic.tpl @@ -5,21 +5,32 @@ backend {{ name }}-backend http-request add-header X-CLIENT-IP %[var(txn.real_ip)] http-request set-header X-Real-IP %[var(txn.real_ip)] - # Define scanning attempt patterns + # Define error status codes acl is_404_error status 404 acl is_403_error status 403 acl is_401_error status 401 acl is_400_error status 400 - acl is_scan_attempt status 400 401 403 404 - # Additional suspicious patterns - acl suspicious_path path_reg -i \.(php|asp|aspx|jsp|cgi)$ - acl suspicious_path path_reg -i /(wp-admin|phpmyadmin|admin|login|xmlrpc) - acl suspicious_path path_reg -i \.(env|git|svn|backup|bak|old) + # Define suspicious scan patterns - only these count as scan attempts + acl scan_scripts path_reg -i \.(php|asp|aspx|jsp|cgi|pl|py|rb|sh|bash)$ + acl scan_admin path_reg -i /(wp-admin|wp-login|phpmyadmin|adminer|manager|admin-console) + acl scan_configs path_reg -i \.(env|git|svn|htaccess|htpasswd|ini|conf|config|yml|yaml|toml) + acl scan_backups path_reg -i \.(backup|bak|old|orig|save|swp|sql|db|dump|tar|zip|rar|7z) + acl scan_vulns path_reg -i /(cgi-bin|fckeditor|tiny_mce|ckfinder|userfiles|filemanager) + + # Combine all scan patterns + acl is_suspicious_request scan_scripts or scan_admin or scan_configs or scan_backups or scan_vulns + + # Define legitimate static assets that should NOT count + acl legitimate_assets path_reg -i \.(css|js|jpg|jpeg|png|gif|svg|ico|woff|woff2|ttf|eot|otf|map|webp|mp4|webm|pdf)$ + acl legitimate_paths path_beg /static/ /assets/ /media/ /images/ /fonts/ /css/ /js/ + + # Only count suspicious 404s and auth failures + acl is_scan_attempt is_suspicious_request is_404_error !legitimate_assets !legitimate_paths + acl is_scan_attempt is_403_error !legitimate_assets !legitimate_paths + acl is_scan_attempt is_401_error # Track scan attempts in the frontend stick table - # This increments the counter AFTER the backend responds with an error - # The frontend will check this counter on SUBSEQUENT requests http-response sc-inc-gpc0(0) if is_scan_attempt {% for server in servers %} diff --git a/templates/hap_backend_http_check.tpl b/templates/hap_backend_http_check.tpl index 339fc0a..58dbc50 100644 --- a/templates/hap_backend_http_check.tpl +++ b/templates/hap_backend_http_check.tpl @@ -7,21 +7,32 @@ backend {{ name }}-backend http-request set-header X-Real-IP %[var(txn.real_ip)] {% if ssl_enabled %}http-request set-header X-Forwarded-Proto https if { ssl_fc }{% endif %} - # Define scanning attempt patterns + # Define error status codes acl is_404_error status 404 acl is_403_error status 403 acl is_401_error status 401 acl is_400_error status 400 - acl is_scan_attempt status 400 401 403 404 - # Additional suspicious patterns - acl suspicious_path path_reg -i \.(php|asp|aspx|jsp|cgi)$ - acl suspicious_path path_reg -i /(wp-admin|phpmyadmin|admin|login|xmlrpc) - acl suspicious_path path_reg -i \.(env|git|svn|backup|bak|old) + # Define suspicious scan patterns - only these count as scan attempts + acl scan_scripts path_reg -i \.(php|asp|aspx|jsp|cgi|pl|py|rb|sh|bash)$ + acl scan_admin path_reg -i /(wp-admin|wp-login|phpmyadmin|adminer|manager|admin-console) + acl scan_configs path_reg -i \.(env|git|svn|htaccess|htpasswd|ini|conf|config|yml|yaml|toml) + acl scan_backups path_reg -i \.(backup|bak|old|orig|save|swp|sql|db|dump|tar|zip|rar|7z) + acl scan_vulns path_reg -i /(cgi-bin|fckeditor|tiny_mce|ckfinder|userfiles|filemanager) + + # Combine all scan patterns + acl is_suspicious_request scan_scripts or scan_admin or scan_configs or scan_backups or scan_vulns + + # Define legitimate static assets that should NOT count + acl legitimate_assets path_reg -i \.(css|js|jpg|jpeg|png|gif|svg|ico|woff|woff2|ttf|eot|otf|map|webp|mp4|webm|pdf)$ + acl legitimate_paths path_beg /static/ /assets/ /media/ /images/ /fonts/ /css/ /js/ + + # Only count suspicious 404s and auth failures + acl is_scan_attempt is_suspicious_request is_404_error !legitimate_assets !legitimate_paths + acl is_scan_attempt is_403_error !legitimate_assets !legitimate_paths + acl is_scan_attempt is_401_error # Track scan attempts in the frontend stick table - # This increments the counter AFTER the backend responds with an error - # The frontend will check this counter on SUBSEQUENT requests http-response sc-inc-gpc0(0) if is_scan_attempt {% for server in servers %} diff --git a/templates/hap_listener.tpl b/templates/hap_listener.tpl index 1bb1791..18966fe 100644 --- a/templates/hap_listener.tpl +++ b/templates/hap_listener.tpl @@ -44,10 +44,10 @@ frontend web # Define threat levels based on accumulated error responses from backends # These will be checked on subsequent requests after errors are tracked - acl scanner_low sc0_get_gpc0 ge 10 # 10+ errors = potential scanner - acl scanner_medium sc0_get_gpc0 ge 20 # 20+ errors = likely scanner - acl scanner_high sc0_get_gpc0 ge 35 # 35+ errors = confirmed scanner - acl scanner_critical sc0_get_gpc0 ge 50 # 50+ errors = aggressive scanner + acl scanner_low sc0_get_gpc0 ge 25 # 25+ errors = potential scanner + acl scanner_medium sc0_get_gpc0 ge 40 # 40+ errors = likely scanner + acl scanner_high sc0_get_gpc0 ge 60 # 60+ errors = confirmed scanner + acl scanner_critical sc0_get_gpc0 ge 100 # 100+ errors = aggressive scanner # Rate-based detection (burst of errors) acl burst_scanner sc0_http_err_rate gt 5 # >5 errors in 10 seconds