Merge pull request #17 from leonardobambini/feat/randomized-server-header

Feat/randomized server header
This commit is contained in:
Patrick Di Fazio
2025-12-30 00:14:28 +01:00
committed by GitHub
9 changed files with 54 additions and 11 deletions

View File

@@ -185,7 +185,7 @@ To customize the deception server installation several **environment variables**
| `CANARY_TOKEN_URL` | External canary token URL | None |
| `DASHBOARD_SECRET_PATH` | Custom dashboard path | Auto-generated |
| `PROBABILITY_ERROR_CODES` | Error response probability (0-100%) | `0` |
| `SERVER_HEADER` | HTTP Server header for deception | `Apache/2.2.22 (Ubuntu)` |
| `SERVER_HEADER` | HTTP Server header for deception, if not set use random server header | |
| `TIMEZONE` | IANA timezone for logs and dashboard (e.g., `America/New_York`, `Europe/Rome`) | System timezone |
## robots.txt

View File

@@ -20,7 +20,7 @@ services:
- MAX_COUNTER=10
- CANARY_TOKEN_TRIES=10
- PROBABILITY_ERROR_CODES=0
- SERVER_HEADER=Apache/2.2.22 (Ubuntu)
# - SERVER_HEADER=Apache/2.2.22 (Ubuntu)
# Optional: Set your canary token URL
# - CANARY_TOKEN_URL=http://canarytokens.com/api/users/YOUR_TOKEN/passwords.txt
# Optional: Set custom dashboard path (auto-generated if not set)

View File

@@ -14,8 +14,13 @@ data:
MAX_COUNTER: {{ .Values.config.maxCounter | quote }}
CANARY_TOKEN_TRIES: {{ .Values.config.canaryTokenTries | quote }}
PROBABILITY_ERROR_CODES: {{ .Values.config.probabilityErrorCodes | quote }}
SERVER_HEADER: {{ .Values.config.serverHeader | quote }}
CANARY_TOKEN_URL: {{ .Values.config.canaryTokenUrl | quote }}
{{- if .Values.config.dashboardSecretPath }}
DASHBOARD_SECRET_PATH: {{ .Values.config.dashboardSecretPath | quote }}
{{- end }}
{{- if .Values.config.serverHeader }}
SERVER_HEADER: {{ .Values.config.serverHeader | quote }}
{{- end }}
{{- if .Values.config.timezone }}
TIMEZONE: {{ .Values.config.timezone | quote }}
{{- end }}

View File

@@ -73,7 +73,9 @@ config:
maxCounter: 10
canaryTokenTries: 10
probabilityErrorCodes: 0
serverHeader: "Apache/2.2.22 (Ubuntu)"
# timezone: "UTC"
# serverHeader: "Apache/2.2.22 (Ubuntu)"
# dashboardSecretPath: "/my-secret-dashboard"
# canaryTokenUrl: set-your-canary-token-url-here
# timezone: "UTC" # IANA timezone (e.g., "America/New_York", "Europe/Rome"). If not set, system timezone is used.
@@ -269,6 +271,17 @@ wordlists:
- .git/
- keys/
- credentials/
server_headers:
- Apache/2.2.22 (Ubuntu)
- nginx/1.18.0
- Microsoft-IIS/10.0
- LiteSpeed
- Caddy
- Gunicorn/20.0.4
- uvicorn/0.13.4
- Express
- Flask/1.1.2
- Django/3.1
error_codes:
- 400
- 401

View File

@@ -23,7 +23,7 @@ class Config:
api_server_port: int = 8080
api_server_path: str = "/api/v2/users"
probability_error_codes: int = 0 # Percentage (0-100)
server_header: str = "Apache/2.2.22 (Ubuntu)"
server_header: Optional[str] = None
# Database settings
database_path: str = "data/krawl.db"
database_retention_days: int = 30
@@ -84,9 +84,10 @@ class Config:
api_server_url=os.getenv('API_SERVER_URL'),
api_server_port=int(os.getenv('API_SERVER_PORT', 8080)),
api_server_path=os.getenv('API_SERVER_PATH', '/api/v2/users'),
server_header=os.getenv('SERVER_HEADER', 'Apache/2.2.22 (Ubuntu)'),
probability_error_codes=int(os.getenv('PROBABILITY_ERROR_CODES', 0)),
server_header=os.getenv('SERVER_HEADER')
database_path=os.getenv('DATABASE_PATH', 'data/krawl.db'),
database_retention_days=int(os.getenv('DATABASE_RETENTION_DAYS', 30)),
probability_error_codes=int(os.getenv('PROBABILITY_ERROR_CODES', 0)),
timezone=os.getenv('TIMEZONE') # If not set, will use system timezone
)

View File

@@ -9,7 +9,8 @@ import string
import json
from templates import html_templates
from wordlists import get_wordlists
from config import Config
from logger import get_app_logger
def random_username() -> str:
"""Generate random username"""
@@ -36,6 +37,16 @@ def random_email(username: str = None) -> str:
username = random_username()
return f"{username}@{random.choice(wl.email_domains)}"
def random_server_header() -> str:
"""Generate random server header"""
if Config.from_env().server_header:
server_header = Config.from_env().server_header
else:
wl = get_wordlists()
server_header = random.choice(wl.server_headers)
return server_header
def random_api_key() -> str:
"""Generate random API key"""

View File

@@ -13,7 +13,7 @@ from templates import html_templates
from templates.dashboard_template import generate_dashboard
from generators import (
credentials_txt, passwords_txt, users_json, api_keys_json,
api_response, directory_listing
api_response, directory_listing, random_server_header
)
from wordlists import get_wordlists
@@ -52,7 +52,7 @@ class Handler(BaseHTTPRequestHandler):
def version_string(self) -> str:
"""Return custom server version for deception."""
return self.config.server_header
return random_server_header()
def _should_return_error(self) -> bool:
"""Check if we should return an error based on probability"""

View File

@@ -57,7 +57,8 @@ class Wordlists:
},
"users": {
"roles": ["Administrator", "User"]
}
},
"server_headers": ["Apache/2.4.41 (Ubuntu)", "nginx/1.18.0"]
}
@property
@@ -111,6 +112,10 @@ class Wordlists:
@property
def error_codes(self):
return self._data.get("error_codes", [])
@property
def server_headers(self):
return self._data.get("server_headers", [])
_wordlists_instance = None

View File

@@ -193,5 +193,13 @@
500,
502,
503
],
"server_headers": [
"Apache/2.4.41 (Ubuntu)",
"nginx/1.18.0",
"Microsoft-IIS/10.0",
"cloudflare",
"AmazonS3",
"gunicorn/20.1.0"
]
}