|
| 1 | +# BunkerWeb Malware Scan Plugin |
| 2 | + |
| 3 | +**Version**: 0.8.0 | **Status**: Production Ready | **Release**: 2026-01-27 |
| 4 | + |
| 5 | +Multi-layer malware scanning plugin for BunkerWeb with advanced caching, webhook notifications, and modular architecture. |
| 6 | + |
| 7 | +## ✨ Key Features |
| 8 | + |
| 9 | +- **🛡️ Multi-layer scanning**: ClamAV (local) + VirusTotal + SentinelOne (cloud) |
| 10 | +- **⚡ Smart caching**: SHA256-based result caching with differential TTL (clean: 5min, malicious: 24h, max 7d, configurable) |
| 11 | +- **📢 Webhook notifications**: Real-time alerts to Discord and Microsoft Teams |
| 12 | +- **🔧 Modular architecture**: 21 specialized modules for maintainability |
| 13 | +- **🌐 Cluster-ready**: Works correctly on manager and worker nodes |
| 14 | + |
| 15 | +## ⚡ Performance Metrics (v0.8.0) |
| 16 | + |
| 17 | +| Metric | Result | Details | |
| 18 | +|--------|--------|---------| |
| 19 | +| **First scan (cache miss)** | ~4 seconds | Full ClamAV INSTREAM scan | |
| 20 | +| **Repeat scan (cache hit)** | ~1 second | 75% faster - hash calculation + cache lookup | |
| 21 | +| **Code maintainability** | 21 modules | Specialized components for scanning, caching, APIs | |
| 22 | +| **Webhook delivery** | Real-time | Discord & Microsoft Teams notifications | |
| 23 | +| **Module initialization** | 100% | All 21 modules load successfully | |
| 24 | + |
| 25 | +## 🎯 Real-World Examples |
| 26 | + |
| 27 | +### Example 1: First Upload (Cache Miss) - Full Scan |
| 28 | + |
| 29 | +Uploading EICAR test file for the first time: |
| 30 | + |
| 31 | +```log |
| 32 | +[MALWARE-SCAN] file upload detected, scanning for malware |
| 33 | +[MALWARE-SCAN] file SHA256: 2546dcffc5ad854d4ddc64fbf056871cd5a00f2471cb7a5bfd4ac23b6e9eedad |
| 34 | +[CACHE] ClamAV local cache MISS for checksum: 2546dcffc5ad854d... |
| 35 | +
|
| 36 | +# Full ClamAV INSTREAM scan performed |
| 37 | +[MALWARE-SCAN] scanning file via INSTREAM |
| 38 | +[MALWARE-SCAN] INSTREAM: Read chunk 1, size: 703 |
| 39 | +[MALWARE-SCAN] INSTREAM: All chunks sent - 1 chunks, 703 bytes total |
| 40 | +clamd[922]: instream(127.0.0.1@34668): Eicar-Test-Signature FOUND |
| 41 | +
|
| 42 | +# Detection and caching |
| 43 | +[MALWARE-SCAN] MALWARE DETECTED BY CLAMAV |
| 44 | +[MALWARE-SCAN] ClamAV signature: Eicar-Test-Signature |
| 45 | +[CACHE] Added ClamAV result to cache: 2546dcffc5ad854d... = Eicar-Test-Signature (TTL: 7776000s) |
| 46 | +
|
| 47 | +# Webhook notification |
| 48 | +[WEBHOOK] Processing Discord webhook |
| 49 | +[WEBHOOK] Cleaned URL: https://discord.co*** |
| 50 | +
|
| 51 | +# Request blocked |
| 52 | +POST /wp-admin/async-upload.php HTTP/3.0" 403 (4 seconds total) |
| 53 | +``` |
| 54 | + |
| 55 | +**Timeline**: 4 seconds (file buffering + ClamAV scan + webhook) |
| 56 | + |
| 57 | +--- |
| 58 | + |
| 59 | +### Example 2: Second Upload (Cache Hit) - Instant Block |
| 60 | + |
| 61 | +Uploading the same EICAR file again within 90 days: |
| 62 | + |
| 63 | +```log |
| 64 | +[MALWARE-SCAN] file upload detected, scanning for malware |
| 65 | +[MALWARE-SCAN] file SHA256: 2546dcffc5ad854d4ddc64fbf056871cd5a00f2471cb7a5bfd4ac23b6e9eedad |
| 66 | +[CACHE] ClamAV local cache HIT for checksum: 2546dcffc5ad854d... |
| 67 | +
|
| 68 | +# Cache hit - no ClamAV scan needed! |
| 69 | +[CACHE_HIT] ClamAV cache shows malicious - skipping ClamAV scan |
| 70 | +[MALWARE DETECTED BY CLAMAV (cached)] |
| 71 | +[MALWARE-SCAN] ClamAV signature: Eicar-Test-Signature (SHA256: 2546dcffc5ad854d...) |
| 72 | +
|
| 73 | +# Webhook notification (still fires) |
| 74 | +[WEBHOOK] Processing Discord webhook |
| 75 | +[WEBHOOK] Cleaned URL: https://discord.co*** |
| 76 | +
|
| 77 | +# Request blocked instantly |
| 78 | +POST /wp-admin/async-upload.php HTTP/3.0" 403 (1 second total) |
| 79 | +``` |
| 80 | + |
| 81 | +**Timeline**: 1 second (hash calculation + cache lookup + webhook) - **75% faster!** |
| 82 | + |
| 83 | +--- |
| 84 | + |
| 85 | +### Example 3: Multi-Layer Mode with Cloud Scanners |
| 86 | + |
| 87 | +Configuration: `MALWARE_SCAN_SKIP_OTHERS_ON_CLAMAV_DETECT=no` |
| 88 | + |
| 89 | +```log |
| 90 | +# ClamAV detects malware |
| 91 | +[MALWARE-SCAN] MALWARE DETECTED BY CLAMAV |
| 92 | +[MALWARE-SCAN] ClamAV signature: Eicar-Test-Signature |
| 93 | +
|
| 94 | +# Continue to cloud scanners for additional intelligence |
| 95 | +[MALWARE-SCAN] ClamAV detected malware, continuing to VirusTotal for additional analysis |
| 96 | +[MALWARE-SCAN] calculated SHA256: 2546dcffc5ad854d4ddc64fbf056871cd5a00f2471cb7a5bfd4ac23b6e9eedad |
| 97 | +
|
| 98 | +# VirusTotal confirmation |
| 99 | +[MALWARE-SCAN] checking file against VirusTotal API |
| 100 | +[MALWARE-SCAN] file checksum found in VT cache: 0 suspicious and 61 malicious |
| 101 | +
|
| 102 | +# Dual confirmation |
| 103 | +[MALWARE-SCAN] MALWARE DETECTED BY VIRUSTOTAL - BLOCKING REQUEST |
| 104 | +[MALWARE-SCAN] VirusTotal detection: 61 malicious engines confirmed |
| 105 | +
|
| 106 | +# Webhook with multiple detections |
| 107 | +[WEBHOOK] Processing Discord webhook |
| 108 | +Scanner: ClamAV → Eicar-Test-Signature |
| 109 | +Scanner: VirusTotal → 61/61 engines detected malware |
| 110 | +
|
| 111 | +POST /wp-admin/async-upload.php HTTP/3.0" 403 |
| 112 | +``` |
| 113 | + |
| 114 | +**Benefits**: |
| 115 | +- ✅ Dual confirmation from multiple sources |
| 116 | +- ✅ Rich threat intelligence |
| 117 | +- ✅ Lower false positive rate |
| 118 | +- ✅ Better for security research |
| 119 | + |
| 120 | +--- |
| 121 | + |
| 122 | +### Comparison: Fast vs Full Mode |
| 123 | + |
| 124 | +| Feature | Fast Mode (default) | Full Multi-Layer Mode | |
| 125 | +|---------|--------------------|-----------------------| |
| 126 | +| **Config** | `SKIP_OTHERS_ON_CLAMAV_DETECT=yes` | `SKIP_OTHERS_ON_CLAMAV_DETECT=no` | |
| 127 | +| **ClamAV scan** | ✅ Always | ✅ Always | |
| 128 | +| **Cache check** | ✅ Before ClamAV | ✅ Before ClamAV | |
| 129 | +| **Cloud scanners** | Only if ClamAV clean | Always (additional intelligence) | |
| 130 | +| **Response time** | ~1s cached, ~4s uncached | ~1s cached, ~5s uncached | |
| 131 | +| **Detection sources** | Single (ClamAV) | Multiple (ClamAV + VT + TF + S1) | |
| 132 | +| **API quota usage** | Lower | Higher | |
| 133 | +| **Best for** | Production speed | Security research | |
| 134 | + |
| 135 | +## 📥 Installation |
| 136 | + |
| 137 | +### Option 1: Docker ClamAV (Recommended for New Deployments) |
| 138 | + |
| 139 | +For production environments, use the automated Docker installation script for ClamAV: |
| 140 | + |
| 141 | +```bash |
| 142 | +# Supports: Debian 11+, Ubuntu 20.04+, CentOS 7+, Rocky 8+, AlmaLinux 8+, Fedora 33+ |
| 143 | +sudo ./install-docker-clamav.sh |
| 144 | + |
| 145 | +# Container runs on port 3310 with 4GB memory limit |
| 146 | +# Signature updates: Every 2 hours (12 checks per day) |
| 147 | +# Logging: JSON-file (docker logs clamav) |
| 148 | +``` |
| 149 | + |
| 150 | +**Features:** |
| 151 | +- ✅ Automatic OS detection (Debian/CentOS) |
| 152 | +- ✅ Auto-start on reboot (systemd service) |
| 153 | +- ✅ 24/7 availability (concurrent database reload) |
| 154 | +- ✅ Comprehensive troubleshooting guides included |
| 155 | + |
| 156 | +See [install-docker-clamav.md](install-docker-clamav.md) for detailed instructions. |
| 157 | + |
| 158 | +### Option 2: Plugin Installation |
| 159 | + |
| 160 | +```bash |
| 161 | +# Clone the repository |
| 162 | +git clone https://github.com/bunkerity/bunkerweb-plugins.git |
| 163 | +cd bunkerweb-plugins/malware-scan |
| 164 | + |
| 165 | +# Deploy files |
| 166 | +sudo cp *.lua plugin.json /etc/bunkerweb/plugins/malware-scan/ |
| 167 | +sudo chmod 644 /etc/bunkerweb/plugins/malware-scan/* |
| 168 | + |
| 169 | +# Restart BunkerWeb |
| 170 | +sudo systemctl restart bunkerweb |
| 171 | +``` |
| 172 | + |
| 173 | +### Verification |
| 174 | + |
| 175 | +Check that all modules loaded successfully: |
| 176 | + |
| 177 | +```bash |
| 178 | +journalctl -u bunkerweb -n 50 | grep -i "malware-scan" |
| 179 | +``` |
| 180 | + |
| 181 | +Expected output: |
| 182 | +``` |
| 183 | +[MALWARE-SCAN] cache module loaded successfully |
| 184 | +[MALWARE-SCAN] file_ops module loaded successfully |
| 185 | +[MALWARE-SCAN] clamav module loaded successfully |
| 186 | +[MALWARE-SCAN] virustotal module loaded successfully |
| 187 | +[MALWARE-SCAN] sentinelone module loaded successfully |
| 188 | +[MALWARE-SCAN] webhook module loaded successfully |
| 189 | +``` |
| 190 | + |
| 191 | +### ClamAV Debugging |
| 192 | + |
| 193 | +The install script automatically enables ClamAV debugging for detailed scanning logs. To manually enable or check: |
| 194 | + |
| 195 | +```bash |
| 196 | +# Check current ClamAV configuration |
| 197 | +grep -E "^(LogVerbose|Debug|LogClean)" /etc/clamav/clamd.conf |
| 198 | + |
| 199 | +# Enable debugging (if not already enabled) |
| 200 | +sudo sed -i 's/^LogVerbose false/LogVerbose true/' /etc/clamav/clamd.conf |
| 201 | +sudo sed -i 's/^Debug false/Debug true/' /etc/clamav/clamd.conf |
| 202 | +sudo sed -i 's/^LogClean false/LogClean true/' /etc/clamav/clamd.conf |
| 203 | +sudo systemctl restart clamav-daemon |
| 204 | + |
| 205 | +# View ClamAV logs |
| 206 | +sudo tail -f /var/log/clamav/clamav.log |
| 207 | + |
| 208 | +# View BunkerWeb malware-scan logs |
| 209 | +sudo journalctl -u bunkerweb -f | grep MALWARE |
| 210 | +``` |
| 211 | + |
| 212 | +**What you'll see with debugging enabled:** |
| 213 | +- `LogVerbose`: Detailed information about each scan (file paths, scan methods) |
| 214 | +- `Debug`: Daemon-level debugging (connections, protocol details) |
| 215 | +- `LogClean`: Logs for clean files (not just infected ones) |
| 216 | + |
| 217 | +## ⚙️ Configuration |
| 218 | + |
| 219 | +Edit `/etc/bunkerweb/variables.env`: |
| 220 | + |
| 221 | +### Core Settings |
| 222 | + |
| 223 | +```bash |
| 224 | +USE_MALWARE-SCAN=yes # Enable malware scanning |
| 225 | +MALWARE_SCAN_DEBUG=no # Debug logging (disable in production) |
| 226 | +``` |
| 227 | + |
| 228 | +### ClamAV (Local Scanning) |
| 229 | + |
| 230 | +```bash |
| 231 | +MALWARE_SCAN_CLAMAV_HOST=127.0.0.1 # ClamAV daemon host |
| 232 | +MALWARE_SCAN_CLAMAV_PORT=3310 # ClamAV daemon port |
| 233 | +MALWARE_SCAN_CLAMAV_TIMEOUT=10000 # Connection timeout (ms) |
| 234 | +MALWARE_SCAN_CLAMAV_MAX_SIZE=26214400 # Max file size (25MB) |
| 235 | +``` |
| 236 | + |
| 237 | +### Multi-Layer Scanning |
| 238 | + |
| 239 | +```bash |
| 240 | +MALWARE_SCAN_SKIP_OTHERS_ON_CLAMAV_DETECT=yes # Fast mode (skip cloud on ClamAV hit) |
| 241 | +MALWARE_SCAN_RESUME_SCAN_ON_FIRST_HIT=no # WARNING: DOS risk! Continue scanning after first detection |
| 242 | +MALWARE_SCAN_SCAN_FULL_MULTIPART_BODY=no # Skip full multipart body scan (recommended - see note below) |
| 243 | +MALWARE_SCAN_HASH_MAX_SIZE=67108864 # Max file size for hash scanning (64MB) |
| 244 | +``` |
| 245 | + |
| 246 | +**Note on SCAN_FULL_MULTIPART_BODY**: |
| 247 | + |
| 248 | +By default (`no`), the plugin skips scanning the entire multipart request body and only scans extracted individual files. This is **recommended** because: |
| 249 | +- HTTP multipart boundaries contain random strings that change on every upload |
| 250 | +- Full body SHA256 is different each time, making caching completely ineffective |
| 251 | +- Individual file extraction provides consistent SHA256s for reliable caching |
| 252 | +- Wastes ClamAV resources scanning the same files repeatedly |
| 253 | + |
| 254 | +Only enable (`yes`) if you suspect malware might be split across multipart boundaries (extremely rare). |
| 255 | + |
| 256 | +**Note on RESUME_SCAN_ON_FIRST_HIT**: |
| 257 | + |
| 258 | +The plugin performs **dual scanning** for comprehensive malware detection: |
| 259 | +1. **Full-body scan** (optional): Scans entire multipart upload - disabled by default (see SCAN_FULL_MULTIPART_BODY above) |
| 260 | +2. **Per-file scan** (when resume enabled): Parses multipart data and scans each uploaded file individually |
| 261 | + |
| 262 | +When `RESUME_SCAN_ON_FIRST_HIT=yes`: |
| 263 | +- All scanners complete even after detection (comprehensive threat intelligence) |
| 264 | +- Continues to next file after detecting malware in one file |
| 265 | +- Aggregates detections from whole-body + all individual files before blocking |
| 266 | + |
| 267 | +When `RESUME_SCAN_ON_FIRST_HIT=no` (default): |
| 268 | +- Blocks immediately on first detection (fast response, minimal resources) |
| 269 | + |
| 270 | +**DOS Risk**: Attackers can force expensive operations (multiple file scans, API calls) even after detection. Only enable for security research or when you need complete visibility into multi-file attacks. |
| 271 | + |
| 272 | +### VirusTotal (70+ AV Engines) |
| 273 | + |
| 274 | +```bash |
| 275 | +MALWARE_SCAN_API_USE_VIRUSTOTAL=yes # Enable VirusTotal |
| 276 | +MALWARE_SCAN_API_VIRUSTOTAL_KEY=your_api_key # API key (required) |
| 277 | +MALWARE_SCAN_API_VIRUSTOTAL_SUSPICIOUS=5 # Suspicious threshold |
| 278 | +MALWARE_SCAN_API_VIRUSTOTAL_MALICIOUS=3 # Malicious threshold |
| 279 | +MALWARE_SCAN_API_VIRUSTOTAL_UPLOAD_UNKNOWN=yes # Upload unknown malware |
| 280 | +MALWARE_SCAN_API_VIRUSTOTAL_AUTO_VOTE=yes # Auto-vote on uploads |
| 281 | +MALWARE_SCAN_API_VIRUSTOTAL_MAX_UPLOAD_SIZE=33554432 # Max upload size (32MB) |
| 282 | +``` |
| 283 | + |
| 284 | +### SentinelOne (Enterprise) |
| 285 | + |
| 286 | +```bash |
| 287 | +MALWARE_SCAN_API_USE_SENTINELONE=yes # Enable SentinelOne |
| 288 | +MALWARE_SCAN_API_SENTINELONE_URL=https://... # Console URL |
| 289 | +MALWARE_SCAN_API_SENTINELONE_TOKEN=your_token # API token |
| 290 | +``` |
| 291 | + |
| 292 | +### Webhooks (Discord & Teams) |
| 293 | + |
| 294 | +```bash |
| 295 | +MALWARE_SCAN_DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/... |
| 296 | +MALWARE_SCAN_TEAMS_WEBHOOK_URL=https://outlook.office.com/webhook/... |
| 297 | +``` |
| 298 | + |
| 299 | +### False Positive Handling |
| 300 | + |
| 301 | +```bash |
| 302 | +MALWARE_SCAN_ALLOWLIST_HASHES=sha256_hash1,sha256_hash2 # Comma-separated hashes |
| 303 | +MALWARE_SCAN_ALLOWLIST_FILE=/path/to/allowlist.txt # File with hashes (one per line) |
| 304 | +``` |
| 305 | + |
| 306 | +### Cleanup |
| 307 | + |
| 308 | +```bash |
| 309 | +MALWARE_SCAN_CLEANUP_FILES=yes # Delete temp files after scan |
| 310 | +MALWARE_SCAN_CLEANUP_ORPHANED=yes # Clean up old orphaned files |
| 311 | +MALWARE_SCAN_CLEANUP_AGE=3600 # Max age for orphaned files (seconds) |
| 312 | +``` |
| 313 | + |
| 314 | +## 🧪 Testing |
| 315 | + |
| 316 | +### Test with EICAR File |
| 317 | + |
| 318 | +```bash |
| 319 | +# Download EICAR standard test file |
| 320 | +curl -o eicar.txt https://secure.eicar.org/eicar.com.txt |
| 321 | + |
| 322 | +# Upload through your web application |
| 323 | +# Example: WordPress media uploader |
| 324 | +``` |
| 325 | + |
| 326 | +Expected result: |
| 327 | +``` |
| 328 | +HTTP 403 Forbidden |
| 329 | +malware detected by ClamAV: Eicar-Test-Signature |
| 330 | +``` |
| 331 | + |
| 332 | +### Test Caching |
| 333 | + |
| 334 | +1. Upload EICAR file - should take ~4 seconds (full scan) |
| 335 | +2. Upload same file again - should take ~1 second (cache hit) |
| 336 | +3. Check logs for `[CACHE_HIT]` messages |
| 337 | + |
| 338 | +## 📋 API Rate Limits |
| 339 | + |
| 340 | +### VirusTotal Public API |
| 341 | +- **Rate limits**: 4 requests/minute, 500 requests/day |
| 342 | +- **Free tier**: https://www.virustotal.com/gui/join-us |
| 343 | +- **Premium**: Unlimited requests |
| 344 | + |
| 345 | +### SentinelOne API |
| 346 | +- **Rate limits**: 10 req/sec (50 burst) |
| 347 | +- **License**: Requires SentinelOne subscription |
| 348 | + |
| 349 | +## 📚 Documentation |
| 350 | + |
| 351 | +- **[install-docker-clamav.md](install-docker-clamav.md)** - **NEW!** Automated Docker ClamAV setup (Debian & CentOS) |
| 352 | +- **[install-docker-clamav.sh](install-docker-clamav.sh)** - Deployment script with OS auto-detection |
| 353 | +- **[install.md](install.md)** - Detailed installation guide |
| 354 | +- **[TECHNICAL.md](TECHNICAL.md)** - Architecture, security features, development details |
| 355 | +- **[GDPR.md](GDPR.md)** - GDPR compliance guide with privacy policy template |
| 356 | +- **[SECURITY.md](SECURITY.md)** - Vulnerability reporting and security policy |
| 357 | +- **[all-features-enabled.md](all-features-enabled.md)** - Complete configuration with all scanners |
| 358 | +- **[variables.env.example](variables.env.example)** - Complete configuration reference |
| 359 | +- **[ALLOWLIST.md](ALLOWLIST.md)** - False positive handling with SHA256 allowlists |
| 360 | +- **[GRANULAR_CACHE_CLEANUP.md](GRANULAR_CACHE_CLEANUP.md)** - Per-scanner cache cleanup configuration |
| 361 | + |
| 362 | +## 🔒 Security |
| 363 | + |
| 364 | +### Security Best Practices |
| 365 | + |
| 366 | +- Keep ClamAV signatures updated: `sudo freshclam` |
| 367 | +- Use default settings: `BLOCK_ON_FILENAME_INJECTION_ATTACK=yes` |
| 368 | +- Avoid `RESUME_SCAN_ON_FIRST_HIT=yes` in production (DOS risk) |
| 369 | +- Store API keys in environment variables, never commit to git |
| 370 | +- Review logs regularly for attack patterns |
| 371 | + |
| 372 | +### Reporting Vulnerabilities |
| 373 | + |
| 374 | +See [SECURITY.md](SECURITY.md) for vulnerability disclosure policy and security contacts. |
| 375 | + |
| 376 | +## 💬 Support |
| 377 | + |
| 378 | +- **Documentation**: [docs.bunkerweb.io](https://docs.bunkerweb.io/) |
| 379 | +- **Issues**: Check logs first: `journalctl -u bunkerweb` |
| 380 | +- **ClamAV**: [docs.clamav.net](https://docs.clamav.net/) |
| 381 | +- **Security**: [SECURITY.md](SECURITY.md) |
| 382 | + |
| 383 | +## 📜 License |
| 384 | + |
| 385 | +This plugin is part of the BunkerWeb project. |
| 386 | + |
| 387 | +--- |
| 388 | + |
| 389 | +**User-Agent**: API requests include version: `bunkerweb - https://github.com/bunkerity/bunkerweb - malware-scan module v0.8.0` |
0 commit comments