Add extension enumeration detection and comprehensive SIP protection
Major features: - Extension enumeration detection with 3 detection algorithms: - Max unique extensions threshold (default: 20 in 5 min) - Sequential pattern detection (e.g., 100,101,102...) - Rapid-fire detection (many extensions in short window) - Prometheus metrics for all SIP Guardian operations - SQLite persistent storage for bans and attack history - Webhook notifications for ban/unban/suspicious events - GeoIP-based country blocking with continent shortcuts - Per-method rate limiting with token bucket algorithm Bug fixes: - Fix whitelist count always reporting zero in stats - Fix whitelisted connections metric never incrementing - Fix Caddyfile config not being applied to shared guardian New files: - enumeration.go: Extension enumeration detector - enumeration_test.go: 14 comprehensive unit tests - metrics.go: Prometheus metrics handler - storage.go: SQLite persistence layer - webhooks.go: Webhook notification system - geoip.go: MaxMind GeoIP integration - ratelimit.go: Per-method rate limiting Testing: - sandbox/ contains complete Docker Compose test environment - All 14 enumeration tests pass
This commit is contained in:
parent
0b0fb53c9c
commit
c73fa9d3d1
19 changed files with 4630 additions and 544 deletions
219
sandbox/docker-compose.yml
Normal file
219
sandbox/docker-compose.yml
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
# SIP Guardian Testing Sandbox
|
||||
#
|
||||
# This provides a complete testing environment with:
|
||||
# - FreePBX (real PBX for testing)
|
||||
# - Caddy with SIP Guardian (the proxy under test)
|
||||
# - Attack containers (sipvicious, custom scripts)
|
||||
# - Valid client containers (pjsip for legitimate traffic)
|
||||
#
|
||||
# Usage:
|
||||
# docker compose up -d
|
||||
# docker compose logs -f caddy
|
||||
# docker compose run --rm attacker sipvicious_svwar -e100-200 caddy
|
||||
# docker compose run --rm client pjsua --registrar=sip:caddy
|
||||
|
||||
services:
|
||||
# ============================================
|
||||
# FreePBX - The Protected PBX
|
||||
# ============================================
|
||||
freepbx:
|
||||
image: tiredofit/freepbx:latest
|
||||
container_name: sandbox-freepbx
|
||||
hostname: freepbx
|
||||
restart: unless-stopped
|
||||
privileged: true
|
||||
environment:
|
||||
- VIRTUAL_HOST=pbx.sandbox.local
|
||||
- VIRTUAL_NETWORK=sandbox
|
||||
- HTTP_PORT=80
|
||||
- HTTPS_PORT=443
|
||||
- UCP_FIRST_RUN=true
|
||||
- DB_HOST=mariadb
|
||||
- DB_PORT=3306
|
||||
- DB_NAME=asterisk
|
||||
- DB_USER=asterisk
|
||||
- DB_PASS=asteriskpass
|
||||
- ENABLE_FAIL2BAN=FALSE # We're replacing this!
|
||||
- TZ=UTC
|
||||
volumes:
|
||||
- freepbx_data:/data
|
||||
- freepbx_logs:/var/log
|
||||
- freepbx_www:/var/www/html
|
||||
depends_on:
|
||||
- mariadb
|
||||
networks:
|
||||
sandbox:
|
||||
ipv4_address: 10.55.0.10
|
||||
|
||||
mariadb:
|
||||
image: mariadb:10.11
|
||||
container_name: sandbox-mariadb
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=rootpass
|
||||
- MYSQL_DATABASE=asterisk
|
||||
- MYSQL_USER=asterisk
|
||||
- MYSQL_PASSWORD=asteriskpass
|
||||
volumes:
|
||||
- mariadb_data:/var/lib/mysql
|
||||
networks:
|
||||
sandbox:
|
||||
ipv4_address: 10.55.0.11
|
||||
|
||||
# ============================================
|
||||
# Caddy with SIP Guardian - The Proxy
|
||||
# ============================================
|
||||
caddy:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: Dockerfile
|
||||
container_name: sandbox-caddy
|
||||
hostname: caddy
|
||||
restart: unless-stopped
|
||||
# Override default command to use explicit Caddyfile (ENTRYPOINT is "caddy")
|
||||
command: ["run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]
|
||||
ports:
|
||||
# Expose SIP ports to host for external testing
|
||||
- "5060:5060/udp"
|
||||
- "5060:5060/tcp"
|
||||
- "5061:5061/tcp"
|
||||
# Admin API
|
||||
- "2020:2020"
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
environment:
|
||||
- SIP_UPSTREAM_HOST=freepbx
|
||||
- SIP_UPSTREAM_PORT=5060
|
||||
- SIP_UPSTREAM_TLS_PORT=5061
|
||||
networks:
|
||||
sandbox:
|
||||
ipv4_address: 10.55.0.2
|
||||
depends_on:
|
||||
- freepbx
|
||||
|
||||
# ============================================
|
||||
# Attack Simulation Containers
|
||||
# ============================================
|
||||
|
||||
# SIPVicious scanner - for testing scanner detection
|
||||
attacker:
|
||||
image: python:3.11-slim
|
||||
container_name: sandbox-attacker
|
||||
hostname: attacker
|
||||
profiles:
|
||||
- testing
|
||||
command: >
|
||||
bash -c "
|
||||
pip install sipvicious pysip3 &&
|
||||
echo 'SIPVicious and tools installed. Use: sipvicious_svwar, sipvicious_svcrack, sipvicious_svmap' &&
|
||||
tail -f /dev/null
|
||||
"
|
||||
networks:
|
||||
sandbox:
|
||||
ipv4_address: 10.55.0.100
|
||||
depends_on:
|
||||
- caddy
|
||||
|
||||
# Brute force simulation
|
||||
bruteforcer:
|
||||
image: python:3.11-slim
|
||||
container_name: sandbox-bruteforcer
|
||||
hostname: bruteforcer
|
||||
profiles:
|
||||
- testing
|
||||
volumes:
|
||||
- ./scripts:/scripts:ro
|
||||
command: >
|
||||
bash -c "
|
||||
pip install sipsimple requests &&
|
||||
echo 'Brute force tools ready. Run: python /scripts/bruteforce.py' &&
|
||||
tail -f /dev/null
|
||||
"
|
||||
networks:
|
||||
sandbox:
|
||||
ipv4_address: 10.55.0.101
|
||||
depends_on:
|
||||
- caddy
|
||||
|
||||
# ============================================
|
||||
# Legitimate Client Containers
|
||||
# ============================================
|
||||
|
||||
# PJSIP-based SIP client
|
||||
client:
|
||||
image: alpine:latest
|
||||
container_name: sandbox-client
|
||||
hostname: client
|
||||
profiles:
|
||||
- testing
|
||||
command: >
|
||||
sh -c "
|
||||
apk add --no-cache pjsua netcat-openbsd curl jq &&
|
||||
echo 'PJSIP client ready. Use pjsua for SIP registration.' &&
|
||||
tail -f /dev/null
|
||||
"
|
||||
networks:
|
||||
sandbox:
|
||||
ipv4_address: 10.55.0.50
|
||||
depends_on:
|
||||
- caddy
|
||||
|
||||
# Linphone CLI client
|
||||
linphone:
|
||||
image: alpine:latest
|
||||
container_name: sandbox-linphone
|
||||
hostname: linphone
|
||||
profiles:
|
||||
- testing
|
||||
command: >
|
||||
sh -c "
|
||||
apk add --no-cache linphone netcat-openbsd curl &&
|
||||
echo 'Linphone ready.' &&
|
||||
tail -f /dev/null
|
||||
"
|
||||
networks:
|
||||
sandbox:
|
||||
ipv4_address: 10.55.0.51
|
||||
depends_on:
|
||||
- caddy
|
||||
|
||||
# ============================================
|
||||
# Monitoring & Debugging
|
||||
# ============================================
|
||||
|
||||
# Network sniffer for SIP traffic analysis
|
||||
tcpdump:
|
||||
image: alpine:latest
|
||||
container_name: sandbox-tcpdump
|
||||
hostname: tcpdump
|
||||
profiles:
|
||||
- debug
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- NET_RAW
|
||||
network_mode: "service:caddy"
|
||||
command: >
|
||||
sh -c "
|
||||
apk add --no-cache tcpdump &&
|
||||
tcpdump -i any -n 'udp port 5060 or tcp port 5060 or tcp port 5061' -vvv
|
||||
"
|
||||
depends_on:
|
||||
- caddy
|
||||
|
||||
volumes:
|
||||
freepbx_data:
|
||||
freepbx_logs:
|
||||
freepbx_www:
|
||||
mariadb_data:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
|
||||
networks:
|
||||
sandbox:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 10.55.0.0/24
|
||||
gateway: 10.55.0.1
|
||||
Loading…
Add table
Add a link
Reference in a new issue