"""Simulate category route - password audit, port scan, banner grab, payload generation, legendary creator."""
import json
import socket
import hashlib
from flask import Blueprint, render_template, request, jsonify, Response
from web.auth import login_required
simulate_bp = Blueprint('simulate', __name__, url_prefix='/simulate')
@simulate_bp.route('/')
@login_required
def index():
from core.menu import MainMenu
menu = MainMenu()
menu.load_modules()
modules = {k: v for k, v in menu.modules.items() if v.category == 'simulate'}
return render_template('simulate.html', modules=modules)
@simulate_bp.route('/password', methods=['POST'])
@login_required
def password_audit():
"""Audit password strength."""
data = request.get_json(silent=True) or {}
password = data.get('password', '')
if not password:
return jsonify({'error': 'No password provided'})
score = 0
feedback = []
# Length
if len(password) >= 16:
score += 3
feedback.append('+ Excellent length (16+)')
elif len(password) >= 12:
score += 2
feedback.append('+ Good length (12+)')
elif len(password) >= 8:
score += 1
feedback.append('~ Minimum length (8+)')
else:
feedback.append('- Too short (<8)')
# Character diversity
has_upper = any(c.isupper() for c in password)
has_lower = any(c.islower() for c in password)
has_digit = any(c.isdigit() for c in password)
has_special = any(c in '!@#$%^&*()_+-=[]{}|;:,.<>?' for c in password)
if has_upper:
score += 1; feedback.append('+ Contains uppercase')
else:
feedback.append('- No uppercase letters')
if has_lower:
score += 1; feedback.append('+ Contains lowercase')
else:
feedback.append('- No lowercase letters')
if has_digit:
score += 1; feedback.append('+ Contains numbers')
else:
feedback.append('- No numbers')
if has_special:
score += 2; feedback.append('+ Contains special characters')
else:
feedback.append('~ No special characters')
# Common patterns
common = ['password', '123456', 'qwerty', 'letmein', 'admin', 'welcome', 'monkey', 'dragon']
if password.lower() in common:
score = 0
feedback.append('- Extremely common password!')
# Sequential
if any(password[i:i+3].lower() in 'abcdefghijklmnopqrstuvwxyz' for i in range(len(password)-2)):
score -= 1; feedback.append('~ Contains sequential letters')
if any(password[i:i+3] in '0123456789' for i in range(len(password)-2)):
score -= 1; feedback.append('~ Contains sequential numbers')
# Keyboard patterns
for pattern in ['qwerty', 'asdf', 'zxcv', '1qaz', '2wsx']:
if pattern in password.lower():
score -= 1; feedback.append('~ Contains keyboard pattern')
break
score = max(0, min(10, score))
strength = 'STRONG' if score >= 8 else 'MODERATE' if score >= 5 else 'WEAK'
hashes = {
'md5': hashlib.md5(password.encode()).hexdigest(),
'sha1': hashlib.sha1(password.encode()).hexdigest(),
'sha256': hashlib.sha256(password.encode()).hexdigest(),
}
return jsonify({
'score': score,
'strength': strength,
'feedback': feedback,
'hashes': hashes,
})
@simulate_bp.route('/portscan', methods=['POST'])
@login_required
def port_scan():
"""TCP port scan."""
data = request.get_json(silent=True) or {}
target = data.get('target', '').strip()
port_range = data.get('ports', '1-1024').strip()
if not target:
return jsonify({'error': 'No target provided'})
try:
start_port, end_port = map(int, port_range.split('-'))
except Exception:
return jsonify({'error': 'Invalid port range (format: start-end)'})
# Limit scan range for web UI
if end_port - start_port > 5000:
return jsonify({'error': 'Port range too large (max 5000 ports)'})
try:
ip = socket.gethostbyname(target)
except Exception:
return jsonify({'error': f'Could not resolve {target}'})
services = {
21: 'ftp', 22: 'ssh', 23: 'telnet', 25: 'smtp', 53: 'dns',
80: 'http', 110: 'pop3', 143: 'imap', 443: 'https', 445: 'smb',
3306: 'mysql', 3389: 'rdp', 5432: 'postgresql', 8080: 'http-proxy',
}
open_ports = []
total = end_port - start_port + 1
for port in range(start_port, end_port + 1):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(0.5)
result = sock.connect_ex((ip, port))
if result == 0:
open_ports.append({
'port': port,
'service': services.get(port, 'unknown'),
'status': 'open',
})
sock.close()
return jsonify({
'target': target,
'ip': ip,
'open_ports': open_ports,
'scanned': total,
})
@simulate_bp.route('/banner', methods=['POST'])
@login_required
def banner_grab():
"""Grab service banner."""
data = request.get_json(silent=True) or {}
target = data.get('target', '').strip()
port = data.get('port', 80)
if not target:
return jsonify({'error': 'No target provided'})
try:
port = int(port)
except Exception:
return jsonify({'error': 'Invalid port'})
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5)
sock.connect((target, port))
if port in [80, 443, 8080, 8443]:
sock.send(b"HEAD / HTTP/1.1\r\nHost: " + target.encode() + b"\r\n\r\n")
else:
sock.send(b"\r\n")
banner = sock.recv(1024).decode('utf-8', errors='ignore')
sock.close()
return jsonify({'banner': banner or 'No banner received'})
except socket.timeout:
return jsonify({'error': 'Connection timed out'})
except ConnectionRefusedError:
return jsonify({'error': 'Connection refused'})
except Exception as e:
return jsonify({'error': str(e)})
@simulate_bp.route('/payloads', methods=['POST'])
@login_required
def generate_payloads():
"""Generate test payloads."""
data = request.get_json(silent=True) or {}
payload_type = data.get('type', 'xss').lower()
payloads_db = {
'xss': [
'',
'
',
'