Files
Ninjaserver/pentest/realistic_enumeration.py
2025-09-23 14:13:24 +02:00

313 lines
12 KiB
Python

import requests
import time
import json
from datetime import datetime
import statistics
def test_admin_login_timing():
"""Detaillierte Timing-Analyse für Admin Login"""
base_url = "http://localhost:3000/api/v1/public/login"
# Erweiterte Liste von Admin-Usernamen
admin_usernames = [
"admin", "administrator", "root", "user", "test", "demo",
"admin1", "admin2", "superuser", "manager", "operator",
"ninja", "parkour", "system", "api", "service",
"backup", "support", "helpdesk", "it", "tech"
]
print("🔍 DETAILLIERTE ADMIN LOGIN TIMING-ANALYSE")
print("=" * 70)
print(f"Zeit: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"Target: {base_url}")
print("=" * 70)
results = []
# Teste jeden Username mehrfach für bessere Statistik
for username in admin_usernames:
times = []
print(f"\n👤 Testing: {username}")
print("-" * 50)
for attempt in range(5): # 5 Versuche pro Username
try:
start_time = time.time()
response = requests.post(
base_url,
json={"username": username, "password": "wrongpassword123"},
timeout=10
)
end_time = time.time()
response_time = (end_time - start_time) * 1000 # in ms
times.append(response_time)
print(f" Attempt {attempt+1}: {response_time:6.1f}ms | Status: {response.status_code}")
# Kleine Pause zwischen Requests
time.sleep(0.1)
except Exception as e:
print(f" Attempt {attempt+1}: ERROR - {e}")
continue
if times:
avg_time = statistics.mean(times)
std_dev = statistics.stdev(times) if len(times) > 1 else 0
min_time = min(times)
max_time = max(times)
results.append({
'username': username,
'avg_time': avg_time,
'std_dev': std_dev,
'min_time': min_time,
'max_time': max_time,
'times': times,
'suspicious': avg_time > 50 # Verdächtig wenn > 50ms
})
print(f" 📊 Stats: Avg={avg_time:.1f}ms, Std={std_dev:.1f}ms, Range={min_time:.1f}-{max_time:.1f}ms")
if avg_time > 50:
print(f" ⚠️ SUSPEKT: Deutlich längere Response-Zeit!")
# Sortiere nach durchschnittlicher Response-Zeit
results.sort(key=lambda x: x['avg_time'], reverse=True)
print("\n" + "=" * 70)
print("📈 TIMING-ANALYSE ERGEBNISSE")
print("=" * 70)
print(f"{'Username':<15} {'Avg(ms)':<8} {'Std(ms)':<8} {'Min(ms)':<8} {'Max(ms)':<8} {'Status'}")
print("-" * 70)
for result in results:
status = "⚠️ SUSPEKT" if result['suspicious'] else "✅ Normal"
print(f"{result['username']:<15} {result['avg_time']:<8.1f} {result['std_dev']:<8.1f} "
f"{result['min_time']:<8.1f} {result['max_time']:<8.1f} {status}")
# Speichere detaillierte Ergebnisse
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"timing_analysis_{timestamp}.json"
with open(filename, 'w', encoding='utf-8') as f:
json.dump(results, f, indent=2, ensure_ascii=False)
print(f"\n💾 Detaillierte Ergebnisse gespeichert in: {filename}")
return results
def test_rfid_creation_enumeration():
"""Teste RFID Enumeration über Spieler-Erstellung"""
base_url = "http://localhost:3000/api/v1/public/players/create-with-rfid"
print("\n🔍 RFID ENUMERATION ÜBER SPIELER-ERSTELLUNG")
print("=" * 70)
print(f"Zeit: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"Target: {base_url}")
print("=" * 70)
found_rfids = []
# Teste verschiedene RFID-Patterns
test_patterns = [
"AA:BB:CC:DD", "AA:BB:CC:DE", "AA:BB:CC:DF",
"11:22:33:44", "11:22:33:45", "11:22:33:46",
"FF:FF:FF:FF", "00:00:00:00", "12:34:56:78",
"AB:CD:EF:12", "DE:AD:BE:EF", "CA:FE:BA:BE"
]
for i, rfid in enumerate(test_patterns, 1):
try:
payload = {
"rfiduid": rfid,
"firstname": "Test",
"lastname": "User",
"birthdate": "1990-01-01"
}
response = requests.post(base_url, json=payload, timeout=5)
print(f"[{i:2d}] RFID: {rfid:<12} | Status: {response.status_code:3d}", end="")
if response.status_code == 400:
try:
data = response.json()
if "existiert bereits" in data.get("message", ""):
print(" | ✅ EXISTIERT!")
if "existingPlayer" in data.get("details", {}):
existing = data["details"]["existingPlayer"]
found_rfids.append({
"rfid": rfid,
"existing_player": existing
})
print(f" → Name: {existing.get('firstname')} {existing.get('lastname')}")
else:
print(" | ❌ Anderer Fehler")
except:
print(" | ❌ JSON Parse Error")
else:
print(" | ⚠️ Unexpected Status")
except Exception as e:
print(f"[{i:2d}] RFID: {rfid:<12} | ERROR: {e}")
print(f"\n📊 RFID Enumeration abgeschlossen: {len(found_rfids)} gefunden")
return found_rfids
def test_leaderboard_data_leak():
"""Teste Leaderboard auf sensible Daten"""
base_url = "http://localhost:3000/api/v1/public/times-with-details"
print("\n🔍 LEADERBOARD DATENLEAK-TEST")
print("=" * 70)
print(f"Zeit: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"Target: {base_url}")
print("=" * 70)
try:
response = requests.get(base_url, timeout=10)
print(f"Status: {response.status_code}")
if response.status_code == 200:
data = response.json()
if isinstance(data, list) and len(data) > 0:
print(f"✅ Leaderboard-Daten gefunden: {len(data)} Einträge")
# Analysiere erste paar Einträge
for i, entry in enumerate(data[:3]):
print(f"\n📋 Eintrag {i+1}:")
if 'player' in entry:
player = entry['player']
print(f" Name: {player.get('firstname')} {player.get('lastname')}")
print(f" RFID: {player.get('rfiduid')}")
print(f" ID: {player.get('id')}")
if 'location' in entry:
location = entry['location']
print(f" Location: {location.get('name')}")
print(f" Koordinaten: {location.get('latitude')}, {location.get('longitude')}")
if 'recorded_time_seconds' in entry:
print(f" Zeit: {entry['recorded_time_seconds']} Sekunden")
# Speichere alle Daten
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"leaderboard_data_{timestamp}.json"
with open(filename, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print(f"\n💾 Leaderboard-Daten gespeichert in: {filename}")
return data
else:
print("❌ Keine Leaderboard-Daten gefunden")
else:
print(f"❌ Fehler: HTTP {response.status_code}")
except Exception as e:
print(f"🔥 Fehler beim Abrufen der Leaderboard-Daten: {e}")
return None
def test_error_message_analysis():
"""Analysiere Error Messages auf Information Leakage"""
base_url = "http://localhost:3000/api/v1/public/user-player"
print("\n🔍 ERROR MESSAGE ANALYSE")
print("=" * 70)
test_uuids = [
"00000000-0000-0000-0000-000000000000", # Null UUID
"invalid-uuid-format", # Ungültiges Format
"12345678-1234-1234-1234-123456789012", # Gültiges Format, aber wahrscheinlich nicht existent
"../../../etc/passwd", # Path Traversal
"<script>alert('xss')</script>", # XSS Test
"'; DROP TABLE players; --" # SQL Injection Test
]
error_responses = {}
for i, test_input in enumerate(test_uuids, 1):
try:
response = requests.get(f"{base_url}/{test_input}", timeout=5)
status_code = response.status_code
print(f"[{i}] Input: {test_input:<30} | Status: {status_code}")
if status_code not in error_responses:
error_responses[status_code] = []
try:
json_data = response.json()
error_responses[status_code].append({
'input': test_input,
'response': json_data
})
except:
error_responses[status_code].append({
'input': test_input,
'response': response.text[:200] # Erste 200 Zeichen
})
except Exception as e:
print(f"[{i}] Input: {test_input:<30} | ERROR: {e}")
# Analysiere verschiedene Error-Messages
print(f"\n📊 Error-Message Analyse:")
print("-" * 50)
for status_code, responses in error_responses.items():
print(f"Status {status_code}: {len(responses)} Responses")
# Prüfe auf unterschiedliche Error-Messages
unique_messages = set()
for resp in responses:
if isinstance(resp['response'], dict):
message = resp['response'].get('message', 'No message')
else:
message = str(resp['response'])[:100]
unique_messages.add(message)
print(f" Unique messages: {len(unique_messages)}")
for msg in list(unique_messages)[:3]: # Zeige erste 3
print(f" - {msg}")
return error_responses
if __name__ == "__main__":
print("🚨 NINJA SERVER - REALISTISCHE SICHERHEITSTESTS")
print("⚠️ WARNUNG: Nur für autorisierte Sicherheitstests!")
print()
# 1. Admin Login Timing Analysis
timing_results = test_admin_login_timing()
# 2. RFID Enumeration über Spieler-Erstellung
rfid_results = test_rfid_creation_enumeration()
# 3. Leaderboard Datenleak-Test
leaderboard_data = test_leaderboard_data_leak()
# 4. Error Message Analysis
error_analysis = test_error_message_analysis()
print("\n" + "=" * 70)
print("🏁 REALISTISCHE SICHERHEITSTESTS ABGESCHLOSSEN")
print("=" * 70)
# Zusammenfassung
suspicious_users = [r for r in timing_results if r['suspicious']]
print(f"🔍 Timing-Suspicious Users: {len(suspicious_users)}")
print(f"🔍 Gefundene RFIDs: {len(rfid_results)}")
print(f"🔍 Leaderboard-Einträge: {len(leaderboard_data) if leaderboard_data else 0}")
if suspicious_users:
print(f"\n⚠️ SUSPEKTE USERNAMES (Timing):")
for user in suspicious_users:
print(f" - {user['username']}: {user['avg_time']:.1f}ms")
print(f"\n⏰ Abgeschlossen um: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")