Merge pull request #17 from leonardobambini/feat/randomized-server-header
Feat/randomized server header
This commit is contained in:
@@ -185,7 +185,7 @@ To customize the deception server installation several **environment variables**
|
|||||||
| `CANARY_TOKEN_URL` | External canary token URL | None |
|
| `CANARY_TOKEN_URL` | External canary token URL | None |
|
||||||
| `DASHBOARD_SECRET_PATH` | Custom dashboard path | Auto-generated |
|
| `DASHBOARD_SECRET_PATH` | Custom dashboard path | Auto-generated |
|
||||||
| `PROBABILITY_ERROR_CODES` | Error response probability (0-100%) | `0` |
|
| `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 |
|
| `TIMEZONE` | IANA timezone for logs and dashboard (e.g., `America/New_York`, `Europe/Rome`) | System timezone |
|
||||||
|
|
||||||
## robots.txt
|
## robots.txt
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ services:
|
|||||||
- MAX_COUNTER=10
|
- MAX_COUNTER=10
|
||||||
- CANARY_TOKEN_TRIES=10
|
- CANARY_TOKEN_TRIES=10
|
||||||
- PROBABILITY_ERROR_CODES=0
|
- PROBABILITY_ERROR_CODES=0
|
||||||
- SERVER_HEADER=Apache/2.2.22 (Ubuntu)
|
# - SERVER_HEADER=Apache/2.2.22 (Ubuntu)
|
||||||
# Optional: Set your canary token URL
|
# Optional: Set your canary token URL
|
||||||
# - CANARY_TOKEN_URL=http://canarytokens.com/api/users/YOUR_TOKEN/passwords.txt
|
# - CANARY_TOKEN_URL=http://canarytokens.com/api/users/YOUR_TOKEN/passwords.txt
|
||||||
# Optional: Set custom dashboard path (auto-generated if not set)
|
# Optional: Set custom dashboard path (auto-generated if not set)
|
||||||
|
|||||||
@@ -14,8 +14,13 @@ data:
|
|||||||
MAX_COUNTER: {{ .Values.config.maxCounter | quote }}
|
MAX_COUNTER: {{ .Values.config.maxCounter | quote }}
|
||||||
CANARY_TOKEN_TRIES: {{ .Values.config.canaryTokenTries | quote }}
|
CANARY_TOKEN_TRIES: {{ .Values.config.canaryTokenTries | quote }}
|
||||||
PROBABILITY_ERROR_CODES: {{ .Values.config.probabilityErrorCodes | quote }}
|
PROBABILITY_ERROR_CODES: {{ .Values.config.probabilityErrorCodes | quote }}
|
||||||
SERVER_HEADER: {{ .Values.config.serverHeader | quote }}
|
|
||||||
CANARY_TOKEN_URL: {{ .Values.config.canaryTokenUrl | 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 }}
|
{{- if .Values.config.timezone }}
|
||||||
TIMEZONE: {{ .Values.config.timezone | quote }}
|
TIMEZONE: {{ .Values.config.timezone | quote }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -73,7 +73,9 @@ config:
|
|||||||
maxCounter: 10
|
maxCounter: 10
|
||||||
canaryTokenTries: 10
|
canaryTokenTries: 10
|
||||||
probabilityErrorCodes: 0
|
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
|
# 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.
|
# timezone: "UTC" # IANA timezone (e.g., "America/New_York", "Europe/Rome"). If not set, system timezone is used.
|
||||||
|
|
||||||
@@ -269,6 +271,17 @@ wordlists:
|
|||||||
- .git/
|
- .git/
|
||||||
- keys/
|
- keys/
|
||||||
- credentials/
|
- 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:
|
error_codes:
|
||||||
- 400
|
- 400
|
||||||
- 401
|
- 401
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class Config:
|
|||||||
api_server_port: int = 8080
|
api_server_port: int = 8080
|
||||||
api_server_path: str = "/api/v2/users"
|
api_server_path: str = "/api/v2/users"
|
||||||
probability_error_codes: int = 0 # Percentage (0-100)
|
probability_error_codes: int = 0 # Percentage (0-100)
|
||||||
server_header: str = "Apache/2.2.22 (Ubuntu)"
|
server_header: Optional[str] = None
|
||||||
# Database settings
|
# Database settings
|
||||||
database_path: str = "data/krawl.db"
|
database_path: str = "data/krawl.db"
|
||||||
database_retention_days: int = 30
|
database_retention_days: int = 30
|
||||||
@@ -84,9 +84,10 @@ class Config:
|
|||||||
api_server_url=os.getenv('API_SERVER_URL'),
|
api_server_url=os.getenv('API_SERVER_URL'),
|
||||||
api_server_port=int(os.getenv('API_SERVER_PORT', 8080)),
|
api_server_port=int(os.getenv('API_SERVER_PORT', 8080)),
|
||||||
api_server_path=os.getenv('API_SERVER_PATH', '/api/v2/users'),
|
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_path=os.getenv('DATABASE_PATH', 'data/krawl.db'),
|
||||||
database_retention_days=int(os.getenv('DATABASE_RETENTION_DAYS', 30)),
|
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
|
timezone=os.getenv('TIMEZONE') # If not set, will use system timezone
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import string
|
|||||||
import json
|
import json
|
||||||
from templates import html_templates
|
from templates import html_templates
|
||||||
from wordlists import get_wordlists
|
from wordlists import get_wordlists
|
||||||
|
from config import Config
|
||||||
|
from logger import get_app_logger
|
||||||
|
|
||||||
def random_username() -> str:
|
def random_username() -> str:
|
||||||
"""Generate random username"""
|
"""Generate random username"""
|
||||||
@@ -36,6 +37,16 @@ def random_email(username: str = None) -> str:
|
|||||||
username = random_username()
|
username = random_username()
|
||||||
return f"{username}@{random.choice(wl.email_domains)}"
|
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:
|
def random_api_key() -> str:
|
||||||
"""Generate random API key"""
|
"""Generate random API key"""
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from templates import html_templates
|
|||||||
from templates.dashboard_template import generate_dashboard
|
from templates.dashboard_template import generate_dashboard
|
||||||
from generators import (
|
from generators import (
|
||||||
credentials_txt, passwords_txt, users_json, api_keys_json,
|
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
|
from wordlists import get_wordlists
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
|
|
||||||
def version_string(self) -> str:
|
def version_string(self) -> str:
|
||||||
"""Return custom server version for deception."""
|
"""Return custom server version for deception."""
|
||||||
return self.config.server_header
|
return random_server_header()
|
||||||
|
|
||||||
def _should_return_error(self) -> bool:
|
def _should_return_error(self) -> bool:
|
||||||
"""Check if we should return an error based on probability"""
|
"""Check if we should return an error based on probability"""
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ class Wordlists:
|
|||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"roles": ["Administrator", "User"]
|
"roles": ["Administrator", "User"]
|
||||||
}
|
},
|
||||||
|
"server_headers": ["Apache/2.4.41 (Ubuntu)", "nginx/1.18.0"]
|
||||||
}
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -112,6 +113,10 @@ class Wordlists:
|
|||||||
def error_codes(self):
|
def error_codes(self):
|
||||||
return self._data.get("error_codes", [])
|
return self._data.get("error_codes", [])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def server_headers(self):
|
||||||
|
return self._data.get("server_headers", [])
|
||||||
|
|
||||||
|
|
||||||
_wordlists_instance = None
|
_wordlists_instance = None
|
||||||
|
|
||||||
|
|||||||
@@ -193,5 +193,13 @@
|
|||||||
500,
|
500,
|
||||||
502,
|
502,
|
||||||
503
|
503
|
||||||
|
],
|
||||||
|
"server_headers": [
|
||||||
|
"Apache/2.4.41 (Ubuntu)",
|
||||||
|
"nginx/1.18.0",
|
||||||
|
"Microsoft-IIS/10.0",
|
||||||
|
"cloudflare",
|
||||||
|
"AmazonS3",
|
||||||
|
"gunicorn/20.1.0"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user