From 99435ee3e02bf39cc5028a82d0d7dc88d3c39c6a Mon Sep 17 00:00:00 2001 From: jknapp Date: Sat, 23 Aug 2025 18:30:34 -0700 Subject: [PATCH] Fix HAProxy 3.0 compatibility issues in tarpit configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove gpc2 from stick-table (not supported in HAProxy 3.0) - Fix ACL syntax: Change sc_get_gpc0(0) to sc0_get_gpc0 - Fix ACL syntax: Change sc_http_err_rate(0,period) to sc0_http_err_rate(period) - Fix ACL syntax: Change sc_get_gpc1(0) to sc0_get_gpc1 - Reorder rules to place http-request rules before use_backend rules - Remove duplicate gpc2 increment rule These changes ensure compatibility with HAProxy 3.0.11 while maintaining the tarpit escalation functionality for exploit scanning protection. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- __pycache__/haproxy_manager.cpython-310.pyc | Bin 34191 -> 34934 bytes haproxy_tarpit_config.txt | 153 ++++++++++++++++++++ templates/hap_listener.tpl | 38 +++-- 3 files changed, 171 insertions(+), 20 deletions(-) create mode 100644 haproxy_tarpit_config.txt diff --git a/__pycache__/haproxy_manager.cpython-310.pyc b/__pycache__/haproxy_manager.cpython-310.pyc index cdeb214909d516f33bf2f39346b3792691540c81..69463da52aca1f2a5e796ba3da990b5035ab96eb 100644 GIT binary patch delta 2071 zcmai!du&r>6u|HK+I#ze)^2V0D6cyPVP&w5@dhQRBZClLqhoC4Rd&0rd$irh9i?T3 zjbS7Zgm_|%4iW}28vY<5HJX^1_y-A^h>218W07b`FwsBs4-@|YBc5|thKkYNQ08wxhGzBgzC`SQNzL+tr~;R-K8)?KWza>~^V4ZFsmn9{{N{A5S4gi739ER{w98pnL3tT+S#9Yh##gGbOW8`YBs;PlhwM6_orfp-W5yq#|=H! zWyYm`xIfj|mq>Q&TXyPFBm3OqO;V<0(U?!3xIgRg&_-UlppLs*L%4QVH_XC`U0t{< zAHeRY-n)Ua%S9w69hsO+QY`s4tA<$R-I6rp-7;Zjt$gw*DZ_4ggAJ;w4!MBELKdr7 zx12>CZ6{|Op_1d~!F0^*k@s1B3`e*5G1}sSy%=u^hlR}vGeHBpm?<>S9=k;a*hjoD zADkoNaljS=F9e_reE3$&ENt8E5pG5^j2oN1a0?%`+?qnOl+e8X7c|cinku2`&#M-i zfnn7`GidNrMrdlo8lhQEXkNE~tFQ>FB<-_keoA9^Ortr)TBQZMePZA#nvN3=3r+ej zqA4hu>z`;AH4LW4m=(cfzU;+B%$G21CMB8XOXVGwM1uIu4j;_L)sb`BQtEOpgg-|@ zct4UjX%QxCc@j%VMC3j0IjxA5Cv5y1T0_Za;ac+FaQ)pSSFV!+TUzTNgrlu%pdLSJ z)v+ZXfMqzC_lKA**~o=Wb2Y`06CbqdGgk1)Q$XA+Y45iw%8>|G@2Rc(KT0aVM~}tK zA97{kz#bE-)=-FM4pB;}gcW(nDbXZzBj4tCwkqMgM! z2ieD~Ce6@i*#_?(<3=QNl zTgWc_DYJGS)0-=aclM<8`9{27ABd&(>IPl%4H=O=_|mbgmY}ulr3U%~t7v(XJJH8F z-W6Z|@i7!|sDQ`sac2he8Ms~eF&`1I05^;rD4j{=oKXy*TV8aD-AdSo*GD#~38V=4 z%gAC+y-Mr|vYKhjHQ?rvDr_D-32D4NTH7+0&wO;|6HdCkoWcuEw--w7GE44ZF{zm` z*&R10H6s=uNG0VUsS_LLQHA_9${1U<%LZ=A78WKpo$B!MtS6mjd?4LL_r4s$8>gy# z76noEvSz;wzdQAgwvqQ4JUiCDoIe%GuuJAqMmU@`UY_jKjCr8a0+D+zS7F)d8ZE`k U?6s!T;Aj+d2YVZF>nlxv0-2;1UjP6A delta 1412 zcmZ8hT}&fY6rOY2nU+Fl2Pl7aaSJR$VOhZLg0f21z^X_DmlB|?6e?3n`Dx2#pg;Ur zQ`lvLy2cY9%(73!xccD6jPWPN#7&IugBpF1#F~9F@kQTEcvx5Cz0+#QcG7RoIrp4< z=R4n-Iedd$+a+?;Znp{S_uKBx*`I&bzHBJ7Z4VYf3h8SyB6P|xYh6KJp{1tB&QA^Z< z2b-0T@K#Bjc)nHkn5RrslP0f=ng1AzIWJeC79U|OZi)tDb~hN8r<#U>i_ulQ zGO`8DSTwrB*xSd>z%j=DF=)ZHF<0RV=eEkgE#ciU7w-2vY;BCW*~C=uzN7Fod>7^+Gy{JvJmfTZXwZ&NLY#>IXiDb+4LKtsO z?2#5gdw&gv{G~YPb-`)e^*7qHh0D?D`Jgr#3uv?WssCZIlO5HGzxbbrPTf8Etq4gx zRNsUR{c7+4;FdlWdY4qRaJddRn+671OFTd$;Ydh#&bd^)Khs zwLpY+#1Ki=($3R znVA#Z_v;s<-vc<%wd95X-d?NLLrYH+Na3A}C-Jl8Q_@R3tpk5wz9#ciXuv3AfUW5= zHf*j`HGZx=EB3HZJz7`d(4(hU1_93C539Wp#j^N!Fpj^*pM)p)jEcMyVeC${GKnLJ z`*0TLlON?af~T-M<%DzSOVx^}S>6VwQ*PGyNa8r5LA;ZC{KQ!nP8A2IXQQrKHMrnf z48&Y@Z7w>);=?qAuC-+2EVF5t!vjriXEEgD=lEi~etYc}fk}O7^DeNn2h(wQPyZ%8 zOhCfp8Ncz3*%4I8fLCx6d^K|c4>C=*Vv)@iVLi2?ZEK%V{9vnjNZ>(*1r=gt;#dij z#wJ6FnI_m-ZjzO>01XATtfU6m*hgrLg~R7hu;*Cf4>QHHe6)>A)yH8Oo43amE@IZI z1s7v8;e{a8@U86{#gKQLR~e#q;n&;mNZs6D#ih$W4}U`_e*-9=O=Fa(A)cSRhJsu! hY78asGi}GeFE>gNZYK7duYjeFut}5a@X?*#e*sQnU?Knj diff --git a/haproxy_tarpit_config.txt b/haproxy_tarpit_config.txt new file mode 100644 index 0000000..0c16413 --- /dev/null +++ b/haproxy_tarpit_config.txt @@ -0,0 +1,153 @@ +global + daemon + log stdout local0 info + chroot /var/lib/haproxy + stats socket /var/run/haproxy.sock mode 600 level admin + stats timeout 30s + user haproxy + group haproxy + + # SSL/TLS settings if using HTTPS + ssl-default-bind-ciphers ECDHE+AESGCM:ECDHE+CHACHA20:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS + ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets + +defaults + mode http + timeout connect 5000ms + timeout client 50000ms + timeout server 50000ms + timeout tarpit 60s # Maximum tarpit time + option httplog + option dontlognull + option log-health-checks + retries 3 + + # Error files (optional - customize as needed) + errorfile 400 /usr/local/etc/haproxy/errors/400.http + errorfile 403 /usr/local/etc/haproxy/errors/403.http + errorfile 408 /usr/local/etc/haproxy/errors/408.http + errorfile 500 /usr/local/etc/haproxy/errors/500.http + errorfile 502 /usr/local/etc/haproxy/errors/502.http + errorfile 503 /usr/local/etc/haproxy/errors/503.http + errorfile 504 /usr/local/etc/haproxy/errors/504.http + +frontend web_frontend + bind *:80 + bind *:443 ssl crt /etc/ssl/certs/haproxy.pem + + # Stick table for tracking attacks with escalating timeouts + # gpc0 = total scan attempts + # gpc1 = escalation level (0=none, 1=level1, 2=level2, 3=level3) + # gpc2 = total tarpit/block actions taken + stick-table type ip size 200k expire 2h store gpc0,gpc1,gpc2,http_err_rate(30s),http_err_rate(300s),http_err_rate(3600s) + + # Whitelist trusted networks and monitoring systems + acl trusted_networks src 127.0.0.1 192.168.0.0/16 10.0.0.0/8 172.16.0.0/12 + acl monitoring_systems src -f /etc/haproxy/monitoring_ips.txt + acl health_check path_beg /health /ping /status /.well-known/ + + # Allow trusted traffic to bypass all protection + http-request allow if trusted_networks or monitoring_systems or health_check + + # Define threat levels based on scan attempts and rates + acl low_threat sc_get_gpc0(0) ge 3 sc_get_gpc0(0) lt 10 + acl medium_threat sc_get_gpc0(0) ge 10 sc_get_gpc0(0) lt 25 + acl high_threat sc_get_gpc0(0) ge 25 sc_get_gpc0(0) lt 50 + acl critical_threat sc_get_gpc0(0) ge 50 + + # Rate-based detection (burst attacks) + acl burst_attack sc_http_err_rate(0,30s) gt 8 # >8 errors in 30 seconds + acl sustained_attack sc_http_err_rate(0,300s) gt 3 # >3 errors/min for 5 minutes + acl persistent_attack sc_http_err_rate(0,3600s) gt 1 # >1 error/min for 1 hour + + # Escalation levels (tracks how many times we've escalated this IP) + acl escalation_level_0 sc_get_gpc1(0) eq 0 + acl escalation_level_1 sc_get_gpc1(0) eq 1 + acl escalation_level_2 sc_get_gpc1(0) eq 2 + acl escalation_level_3 sc_get_gpc1(0) ge 3 + + # ESCALATING TARPIT RULES + # Level 1: Short tarpit (2-5 seconds) for first offense + http-request tarpit timeout 2s if low_threat escalation_level_0 + http-request tarpit timeout 3s if medium_threat escalation_level_0 + http-request tarpit timeout 5s if burst_attack escalation_level_0 + + # Level 2: Medium tarpit (8-15 seconds) for second offense + http-request tarpit timeout 8s if low_threat escalation_level_1 + http-request tarpit timeout 12s if medium_threat escalation_level_1 + http-request tarpit timeout 15s if high_threat escalation_level_1 + http-request tarpit timeout 10s if sustained_attack escalation_level_1 + + # Level 3: Long tarpit (20-45 seconds) for repeat offenders + http-request tarpit timeout 20s if low_threat escalation_level_2 + http-request tarpit timeout 30s if medium_threat escalation_level_2 + http-request tarpit timeout 45s if high_threat escalation_level_2 + http-request tarpit timeout 25s if persistent_attack escalation_level_2 + + # Level 4: Maximum tarpit (60 seconds) for persistent attackers + http-request tarpit timeout 60s if escalation_level_3 + + # Complete block for critical threats regardless of escalation level + http-request deny deny_status 429 if critical_threat + + # Increment escalation level when we apply tarpit/block + http-request sc-inc-gpc1(0) if low_threat or medium_threat or high_threat or burst_attack or sustained_attack or persistent_attack + http-request sc-inc-gpc2(0) if low_threat or medium_threat or high_threat or critical_threat or burst_attack or sustained_attack or persistent_attack + + # Capture useful headers for logging + capture request header User-Agent len 150 + capture request header X-Forwarded-For len 30 + capture request header Referer len 100 + + # Enhanced logging format with protection metrics + log-format "%ci:%cp [%t] %ft %b/%s %Tq/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS \"%r\" \"%[capture.req.hdr(0)]\" gpc0:%[sc_get_gpc0(0)] gpc1:%[sc_get_gpc1(0)] gpc2:%[sc_get_gpc2(0)] err_rate_30s:%[sc_http_err_rate(0,30s)]" + + # Redirect HTTP to HTTPS (optional) + redirect scheme https if !{ ssl_fc } + + default_backend web_servers + +backend web_servers + balance roundrobin + option httpchk GET /health HTTP/1.1\r\nHost:\ localhost + + # Define scanning attempt patterns + 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 (optional) + 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) + + # Track scan attempts in the frontend stick table + http-response sc-inc-gpc0(0) if is_scan_attempt + + # Optional: Track suspicious paths even if they return 200 + # http-response sc-inc-gpc0(0) if suspicious_path + + # Optional: Different weights for different error types + # http-response sc-add-gpc0(0) 2 if is_403_error # 403s count as 2 points + # http-response sc-add-gpc0(0) 3 if is_401_error # 401s count as 3 points + + # Server definitions - adjust as needed + server web1 backend-server-1:80 check maxconn 200 weight 100 + server web2 backend-server-2:80 check maxconn 200 weight 100 + # server web3 backend-server-3:80 check maxconn 200 weight 100 + +# Optional: Stats page for monitoring +frontend stats + bind *:8404 + # Restrict access to stats page + acl allowed_ips src 127.0.0.1 192.168.0.0/16 10.0.0.0/8 + http-request allow if allowed_ips + http-request deny + + stats enable + stats uri /stats + stats refresh 30s + stats show-legends + stats show-node \ No newline at end of file diff --git a/templates/hap_listener.tpl b/templates/hap_listener.tpl index 2bb34b5..97a892f 100644 --- a/templates/hap_listener.tpl +++ b/templates/hap_listener.tpl @@ -7,14 +7,7 @@ frontend web # Stick table for tracking attacks with escalating timeouts # gpc0 = total scan attempts # gpc1 = escalation level (0=none, 1=level1, 2=level2, 3=level3) - # gpc2 = total tarpit/block actions taken - stick-table type ip size 200k expire 2h store gpc0,gpc1,gpc2,http_err_rate(30s),http_err_rate(300s),http_err_rate(3600s) - - # IP blocking using map file (no word limit, runtime updates supported) - # Map file: /etc/haproxy/blocked_ips.map - # Runtime updates: echo "add map #0 IP_ADDRESS" | socat stdio /var/run/haproxy.sock - http-request set-path /blocked-ip if { src -f /etc/haproxy/blocked_ips.map } - use_backend default-backend if { src -f /etc/haproxy/blocked_ips.map } + stick-table type ip size 200k expire 2h store gpc0,gpc1,http_err_rate(30s),http_err_rate(300s),http_err_rate(3600s) # Whitelist trusted networks and monitoring systems acl trusted_networks src 127.0.0.1 192.168.0.0/16 10.0.0.0/8 172.16.0.0/12 @@ -26,22 +19,28 @@ frontend web # Track client in stick table http-request track-sc0 src + # IP blocking using map file (no word limit, runtime updates supported) + # Map file: /etc/haproxy/blocked_ips.map + # Runtime updates: echo "add map #0 IP_ADDRESS" | socat stdio /var/run/haproxy.sock + http-request set-path /blocked-ip if { src -f /etc/haproxy/blocked_ips.map } + use_backend default-backend if { src -f /etc/haproxy/blocked_ips.map } + # Define threat levels based on scan attempts and rates - acl low_threat sc_get_gpc0(0) ge 3 sc_get_gpc0(0) lt 10 - acl medium_threat sc_get_gpc0(0) ge 10 sc_get_gpc0(0) lt 25 - acl high_threat sc_get_gpc0(0) ge 25 sc_get_gpc0(0) lt 50 - acl critical_threat sc_get_gpc0(0) ge 50 + acl low_threat sc0_get_gpc0 ge 3 + acl medium_threat sc0_get_gpc0 ge 10 + acl high_threat sc0_get_gpc0 ge 25 + acl critical_threat sc0_get_gpc0 ge 50 # Rate-based detection (burst attacks) - acl burst_attack sc_http_err_rate(0,30s) gt 8 # >8 errors in 30 seconds - acl sustained_attack sc_http_err_rate(0,300s) gt 3 # >3 errors/min for 5 minutes - acl persistent_attack sc_http_err_rate(0,3600s) gt 1 # >1 error/min for 1 hour + acl burst_attack sc0_http_err_rate(30s) gt 8 # >8 errors in 30 seconds + acl sustained_attack sc0_http_err_rate(300s) gt 3 # >3 errors/min for 5 minutes + acl persistent_attack sc0_http_err_rate(3600s) gt 1 # >1 error/min for 1 hour # Escalation levels (tracks how many times we've escalated this IP) - acl escalation_level_0 sc_get_gpc1(0) eq 0 - acl escalation_level_1 sc_get_gpc1(0) eq 1 - acl escalation_level_2 sc_get_gpc1(0) eq 2 - acl escalation_level_3 sc_get_gpc1(0) ge 3 + acl escalation_level_0 sc0_get_gpc1 eq 0 + acl escalation_level_1 sc0_get_gpc1 eq 1 + acl escalation_level_2 sc0_get_gpc1 eq 2 + acl escalation_level_3 sc0_get_gpc1 ge 3 # ESCALATING TARPIT RULES # Level 1: Short tarpit (2-5 seconds) for first offense @@ -69,4 +68,3 @@ frontend web # Increment escalation level when we apply tarpit/block http-request sc-inc-gpc1(0) if low_threat or medium_threat or high_threat or burst_attack or sustained_attack or persistent_attack - http-request sc-inc-gpc2(0) if low_threat or medium_threat or high_threat or critical_threat or burst_attack or sustained_attack or persistent_attack