#!/usr/bin/env python3
-- coding: utf-8 --
#!/usr/bin/env python3
-- coding: utf-8 --
"""
╔══════════════════════════════════════════════════════════════════════════════╗
║ CamXploit GUI - Cyberpunk Edition v2.0 ║
║ Camera Exploitation & CCTV Scanner with PyQt6 Interface ║
║ ║
║ 🔥 Advanced CCTV/DVR/NVR Scanner with Beautiful Cyberpunk GUI ║
║ 🎨 Modern dark theme with neon accents ║
║ ⚡ High-performance threading for responsive UI ║
║ 🔍 Comprehensive port scanning and device detection ║
║ 🔐 Automatic credential testing ║
║ 🎥 RTSP stream detection ║
║ 📊 Real-time progress and logging ║
║ ║
║ Original CamXploit by Spyboy: https://github.com/spyboy-productions ║
║ GUI Version by: Security Researcher Community ║
║ License: Educational Use Only ║
╚══════════════════════════════════════════════════════════════════════════════╝
"""
import sys
import requests
import socket
import threading
import warnings
import base64
import time
import ipaddress
import json
from xml.etree import ElementTree as ET
from datetime import datetime
from urllib.parse import quote
import re
from PyQt6.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLineEdit, QPushButton, QTextEdit, QTabWidget, QTableWidget,
QTableWidgetItem, QLabel, QComboBox, QSpinBox, QProgressBar,
QDialog, QMessageBox, QScrollArea, QFrame, QListWidget, QListWidgetItem,
QHeaderView, QSplitter, QStatusBar, QMenuBar, QMenu, QFileDialog,
QCheckBox, QGroupBox, QGridLayout, QDoubleSpinBox
)
from PyQt6.QtCore import Qt, QThread, pyqtSignal, QTimer, QSize, QRect, QSettings
from PyQt6.QtGui import (
QFont, QColor, QIcon, QPixmap, QTextCursor, QLinearGradient, QPalette,
QTextCharFormat, QBrush, QPen
)
from PyQt6.QtWidgets import QSizePolicy, QApplication
from PyQt6.QtCore import QPropertyAnimation
warnings.filterwarnings("ignore")
requests.packages.urllib3.disable_warnings()
============================================================================
CONSTANTS & CONFIGURATION
============================================================================
COMMON_PORTS = [
# Standard ports
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 443, 8080, 8443, 8000, 8001, 8008,
8081, 8082, 8083, 8084, 8085, 8086, 8087, 8088, 8089, 8090, 8091, 8092,
# RTSP
554, 8554, 10554, 1554, 2554, 3554, 4554, 5554, 6554, 7554, 9554,
# RTMP
1935, 1936, 1937, 1938, 1939,
# Custom camera ports
37777, 37778, 37779, 37780, 37781, 37782, 37783, 37784, 37785,
# ONVIF
3702, 3703, 3704, 3705, 3706, 3707, 3708, 3709, 3710,
# Common ports
21, 22, 23, 25, 53, 110, 143, 993, 995, 1024, 1025, 1026, 1027, 1028,
2000, 2001, 2002, 2003, 2004, 2005, 3000, 3001, 3002, 3003, 3004, 3005,
4000, 4001, 4002, 4003, 4004, 4005, 5000, 5001, 5002, 5003, 5004, 5005,
6000, 6001, 6002, 6003, 6004, 6005, 7000, 7001, 7002, 7003, 7004, 7005,
9000, 9001, 9002, 9003, 9004, 9005, 8888, 8889, 8890, 8891, 8892,
9999, 9998, 9997, 9996, 9995, 1755, 1756, 1757, 1758, 1759,
10000, 10001, 10002, 10003, 10004, 10005, 10006, 10007, 10008, 10009,
11000, 11001, 11002, 11003, 11004, 11005, 20000, 20001, 20002, 20003,
21000, 21001, 21002, 21003, 30000, 30001, 30002, 30003, 40000, 40001,
50000, 50001, 60000, 60001, 65000, 65001
]
DEFAULT_CREDENTIALS = {
"admin": ["admin", "1234", "12345", "123456", "1234567", "12345678",
"123456789", "admin123", "admin1234", "password", "888888",
"666666", "8888", "pass", "123", "1111", "0000"],
"root": ["root", "toor", "1234", "12345", "123456", "pass", "password"],
"user": ["user", "user123", "password", "1234", "12345", "123456"],
"guest": ["guest", "guest123", "1234", "12345", "123456"],
"operator": ["operator", "operator123", "1234", "12345"],
"administrator": ["administrator", "admin", "1234", "12345", "123456"],
"supervisor": ["supervisor", "1234", "12345", "123456"],
"support": ["support", "support123", "1234"],
"system": ["system", "system123", "1234", "12345"],
"viewer": ["viewer", "viewer123", "1234", "12345"],
}
PORT_SERVICE_MAP = {
80: ("HTTP", "Web Interface"),
81: ("HTTP-Alt", "Web Interface"),
443: ("HTTPS", "Secure Web"),
554: ("RTSP", "Streaming Protocol"),
8080: ("HTTP-Alt", "Web Interface"),
8443: ("HTTPS-Alt", "Secure Web"),
8000: ("HTTP-Alt", "Web/Hikvision"),
8554: ("RTSP-Alt", "Streaming"),
1935: ("RTMP", "Streaming"),
3702: ("ONVIF", "Device Discovery"),
37777: ("Dahua", "DVR/NVR"),
37778: ("Dahua", "DVR/NVR"),
8008: ("Hikvision", "Web/API"),
1755: ("MMS", "Media Server"),
}
CVE_DATABASE = {
"hikvision": [
"CVE-2021-36260", "CVE-2017-7921", "CVE-2021-31955", "CVE-2021-31956",
"CVE-2021-31957", "CVE-2021-31958", "CVE-2021-31959", "CVE-2021-31960",
],
"dahua": [
"CVE-2021-33044", "CVE-2022-30563", "CVE-2021-33045", "CVE-2021-33046",
"CVE-2021-33047", "CVE-2021-33048", "CVE-2021-33049", "CVE-2021-33050",
],
"axis": [
"CVE-2018-10660", "CVE-2020-29550", "CVE-2020-29551", "CVE-2020-29552",
],
}
============================================================================
CYBERPUNK THEME
============================================================================
class CyberpunkTheme:
"""Complete cyberpunk theme configuration"""
BG_DARK = "#0a0a0a"
BG_DARKER = "#050505"
BG_CARD = "#1a1a1a"
BG_INPUT = "#151515"
NEON_CYAN = "#00d9ff"
NEON_MAGENTA = "#ff006e"
NEON_GREEN = "#39ff14"
NEON_YELLOW = "#ffff00"
NEON_PURPLE = "#b300ff"
NEON_BLUE = "#0099ff"
TEXT_PRIMARY = "#ffffff"
TEXT_SECONDARY = "#b0b0b0"
TEXT_MUTED = "#707070"
SUCCESS = "#00ff41"
WARNING = "#ff9500"
ERROR = "#ff0055"
INFO = "#00d9ff"
@staticmethod
def get_stylesheet():
"""Get complete stylesheet"""
return f"""
* {{
background-color: {CyberpunkTheme.BG_DARK};
color: {CyberpunkTheme.TEXT_PRIMARY};
font-family: 'Courier New', monospace;
border: none;
}}
QMainWindow {{
background-color: {CyberpunkTheme.BG_DARK};
}}
QWidget {{
background-color: {CyberpunkTheme.BG_DARK};
color: {CyberpunkTheme.TEXT_PRIMARY};
}}
QLineEdit, QSpinBox, QDoubleSpinBox, QComboBox {{
background-color: {CyberpunkTheme.BG_INPUT};
color: {CyberpunkTheme.TEXT_PRIMARY};
border: 2px solid {CyberpunkTheme.NEON_CYAN};
border-radius: 5px;
padding: 8px;
font-size: 11px;
selection-background-color: {CyberpunkTheme.NEON_CYAN};
selection-color: {CyberpunkTheme.BG_DARK};
}}
QLineEdit:focus, QSpinBox:focus, QComboBox:focus {{
border: 2px solid {CyberpunkTheme.NEON_MAGENTA};
background-color: {CyberpunkTheme.BG_INPUT};
box-shadow: 0 0 10px {CyberpunkTheme.NEON_MAGENTA};
}}
QPushButton {{
background-color: {CyberpunkTheme.NEON_CYAN};
color: {CyberpunkTheme.BG_DARK};
border: 2px solid {CyberpunkTheme.NEON_CYAN};
border-radius: 5px;
padding: 10px 20px;
font-weight: bold;
font-size: 12px;
}}
QPushButton:hover {{
background-color: {CyberpunkTheme.NEON_MAGENTA};
border: 2px solid {CyberpunkTheme.NEON_MAGENTA};
box-shadow: 0 0 15px {CyberpunkTheme.NEON_MAGENTA};
}}
QPushButton:pressed {{
background-color: {CyberpunkTheme.NEON_GREEN};
border: 2px solid {CyberpunkTheme.NEON_GREEN};
}}
QPushButton:disabled {{
background-color: {CyberpunkTheme.TEXT_MUTED};
color: {CyberpunkTheme.BG_DARK};
border: 2px solid {CyberpunkTheme.TEXT_MUTED};
}}
QTextEdit {{
background-color: {CyberpunkTheme.BG_CARD};
color: {CyberpunkTheme.TEXT_PRIMARY};
border: 2px solid {CyberpunkTheme.NEON_CYAN};
border-radius: 5px;
padding: 8px;
font-size: 10px;
font-family: 'Courier New', monospace;
}}
QTabWidget::pane {{
border: 2px solid {CyberpunkTheme.NEON_CYAN};
border-radius: 5px;
}}
QTabBar::tab {{
background-color: {CyberpunkTheme.BG_CARD};
color: {CyberpunkTheme.TEXT_SECONDARY};
padding: 8px 20px;
border: 2px solid {CyberpunkTheme.BG_CARD};
border-bottom: 2px solid transparent;
}}
QTabBar::tab:selected {{
background-color: {CyberpunkTheme.BG_DARK};
color: {CyberpunkTheme.NEON_CYAN};
border-bottom: 3px solid {CyberpunkTheme.NEON_CYAN};
}}
QTabBar::tab:hover {{
color: {CyberpunkTheme.NEON_MAGENTA};
}}
QTableWidget {{
background-color: {CyberpunkTheme.BG_CARD};
color: {CyberpunkTheme.TEXT_PRIMARY};
border: 2px solid {CyberpunkTheme.NEON_CYAN};
border-radius: 5px;
gridline-color: {CyberpunkTheme.BG_DARKER};
}}
QTableWidget::item {{
padding: 5px;
border: none;
}}
QTableWidget::item:selected {{
background-color: {CyberpunkTheme.NEON_CYAN};
color: {CyberpunkTheme.BG_DARK};
}}
QHeaderView::section {{
background-color: {CyberpunkTheme.BG_DARKER};
color: {CyberpunkTheme.NEON_CYAN};
padding: 5px;
border: none;
border-right: 1px solid {CyberpunkTheme.NEON_CYAN};
font-weight: bold;
}}
QProgressBar {{
background-color: {CyberpunkTheme.BG_INPUT};
border: 2px solid {CyberpunkTheme.NEON_CYAN};
border-radius: 5px;
text-align: center;
color: {CyberpunkTheme.NEON_CYAN};
height: 25px;
}}
QProgressBar::chunk {{
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
stop:0 {CyberpunkTheme.NEON_CYAN},
stop:0.5 {CyberpunkTheme.NEON_PURPLE},
stop:1 {CyberpunkTheme.NEON_MAGENTA});
border-radius: 3px;
}}
QLabel {{
color: {CyberpunkTheme.TEXT_PRIMARY};
background-color: transparent;
}}
QCheckBox {{
color: {CyberpunkTheme.TEXT_PRIMARY};
background-color: transparent;
spacing: 5px;
}}
QCheckBox::indicator {{
width: 18px;
height: 18px;
border: 2px solid {CyberpunkTheme.NEON_CYAN};
border-radius: 3px;
background-color: {CyberpunkTheme.BG_INPUT};
}}
QCheckBox::indicator:checked {{
background-color: {CyberpunkTheme.NEON_CYAN};
}}
QScrollBar:vertical {{
background-color: {CyberpunkTheme.BG_CARD};
width: 12px;
border: none;
}}
QScrollBar::handle:vertical {{
background-color: {CyberpunkTheme.NEON_CYAN};
border-radius: 6px;
min-height: 20px;
}}
QScrollBar::handle:vertical:hover {{
background-color: {CyberpunkTheme.NEON_MAGENTA};
}}
QScrollBar:horizontal {{
background-color: {CyberpunkTheme.BG_CARD};
height: 12px;
border: none;
}}
QScrollBar::handle:horizontal {{
background-color: {CyberpunkTheme.NEON_CYAN};
border-radius: 6px;
min-width: 20px;
}}
QScrollBar::handle:horizontal:hover {{
background-color: {CyberpunkTheme.NEON_MAGENTA};
}}
QListWidget {{
background-color: {CyberpunkTheme.BG_CARD};
color: {CyberpunkTheme.TEXT_PRIMARY};
border: 2px solid {CyberpunkTheme.NEON_CYAN};
border-radius: 5px;
}}
QListWidget::item {{
padding: 5px;
border: none;
}}
QListWidget::item:selected {{
background-color: {CyberpunkTheme.NEON_CYAN};
color: {CyberpunkTheme.BG_DARK};
}}
QGroupBox {{
border: 2px solid {CyberpunkTheme.NEON_CYAN};
border-radius: 5px;
margin-top: 10px;
padding-top: 10px;
color: {CyberpunkTheme.NEON_CYAN};
}}
QGroupBox::title {{
subcontrol-origin: margin;
left: 10px;
padding: 0 3px 0 3px;
}}
QMenuBar {{
background-color: {CyberpunkTheme.BG_CARD};
color: {CyberpunkTheme.TEXT_PRIMARY};
border-bottom: 2px solid {CyberpunkTheme.NEON_CYAN};
}}
QMenuBar::item:selected {{
background-color: {CyberpunkTheme.NEON_CYAN};
color: {CyberpunkTheme.BG_DARK};
}}
QMenu {{
background-color: {CyberpunkTheme.BG_CARD};
color: {CyberpunkTheme.TEXT_PRIMARY};
border: 2px solid {CyberpunkTheme.NEON_CYAN};
}}
QMenu::item:selected {{
background-color: {CyberpunkTheme.NEON_CYAN};
color: {CyberpunkTheme.BG_DARK};
}}
QStatusBar {{
background-color: {CyberpunkTheme.BG_CARD};
color: {CyberpunkTheme.TEXT_PRIMARY};
border-top: 2px solid {CyberpunkTheme.NEON_CYAN};
}}
"""
============================================================================
CUSTOM WIDGETS
============================================================================
class CyberpunkLabel(QLabel):
"""Cyberpunk styled label"""
def init(self, text, color=CyberpunkTheme.TEXT_PRIMARY, size=12, bold=False):
super().init(text)
font = QFont("Courier New", size)
font.setBold(bold)
self.setFont(font)
self.setStyleSheet(f"color: {color}; background-color: transparent;")
class GlowingButton(QPushButton):
"""Glowing cyberpunk button"""
def init(self, text, color=CyberpunkTheme.NEON_CYAN):
super().init(text)
self.base_color = color
self.update_style(color)
def update_style(self, color):
self.setStyleSheet(f"""
QPushButton {{
background-color: {color};
color: {CyberpunkTheme.BG_DARK};
border: 2px solid {color};
border-radius: 5px;
padding: 10px 20px;
font-weight: bold;
font-size: 12px;
font-family: 'Courier New', monospace;
}}
QPushButton:hover {{
background-color: {CyberpunkTheme.NEON_MAGENTA};
border: 2px solid {CyberpunkTheme.NEON_MAGENTA};
}}
QPushButton:pressed {{
background-color: {CyberpunkTheme.NEON_GREEN};
}}
""")
class StatusIndicator(QLabel):
"""Status indicator with colors"""
def init(self, status="offline"):
super().init()
self.status = status
self.set_status(status)
def set_status(self, status):
colors = {
"offline": CyberpunkTheme.ERROR,
"scanning": CyberpunkTheme.NEON_YELLOW,
"online": CyberpunkTheme.SUCCESS,
"vulnerable": CyberpunkTheme.NEON_MAGENTA,
"credentials_found": CyberpunkTheme.NEON_GREEN,
}
color = colors.get(status, CyberpunkTheme.TEXT_MUTED)
self.setText(f"● {status.upper()}")
self.setStyleSheet(f"color: {color}; font-weight: bold; background-color: transparent;")
self.status = status
============================================================================
SCANNER THREADS
============================================================================
class ScannerThread(QThread):
"""Thread for port scanning"""
progress = pyqtSignal(str)
port_found = pyqtSignal(int, str, str)
finished = pyqtSignal(int)
def __init__(self, ip, ports_to_scan, timeout=1.5):
super().__init__()
self.ip = ip
self.ports_to_scan = ports_to_scan
self.timeout = timeout
self.is_running = True
self.open_ports = []
def run(self):
"""Execute port scan"""
try:
for idx, port in enumerate(self.ports_to_scan):
if not self.is_running:
break
progress_pct = int((idx / len(self.ports_to_scan)) * 100)
self.progress.emit(f"Escaneando puerto {port}... ({progress_pct}%)")
if self.is_port_open(port):
self.open_ports.append(port)
service = self.get_service_name(port)
self.port_found.emit(port, service, "TCP")
self.progress.emit(f"Escaneo completado: {len(self.open_ports)} puertos abiertos")
self.finished.emit(len(self.open_ports))
except Exception as e:
self.progress.emit(f"Error: {str(e)}")
self.finished.emit(0)
def is_port_open(self, port):
"""Check if port is open"""
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.settimeout(self.timeout)
result = sock.connect_ex((self.ip, port))
return result == 0
except Exception:
return False
def stop(self):
"""Stop scanning"""
self.is_running = False
@staticmethod
def get_service_name(port):
"""Get service name from port"""
return PORT_SERVICE_MAP.get(port, ("Desconocido", ""))[0]
class CredentialTestThread(QThread):
"""Thread for credential testing"""
progress = pyqtSignal(str)
found_creds = pyqtSignal(str, str, str, str, str)
finished = pyqtSignal()
def __init__(self, ip, ports, timeout=2):
super().__init__()
self.ip = ip
self.ports = ports
self.timeout = timeout
self.is_running = True
def run(self):
"""Test credentials"""
try:
tested = 0
for port in self.ports[:10]:
if not self.is_running:
break
protocol = "https" if port in [443, 8443] else "http"
base_url = f"{protocol}://{self.ip}:{port}"
for username, passwords in DEFAULT_CREDENTIALS.items():
if not self.is_running:
break
for password in passwords:
tested += 1
if tested % 10 == 0:
self.progress.emit(f"Probadas {tested} credenciales...")
if self.test_http_auth(base_url, username, password):
self.found_creds.emit(
username, password, str(port),
f"{protocol.upper()}", base_url
)
self.progress.emit(f"Test de credenciales completado ({tested} intentos)")
self.finished.emit()
except Exception as e:
self.progress.emit(f"Error: {str(e)}")
self.finished.emit()
def test_http_auth(self, url, username, password):
"""Test HTTP authentication"""
try:
response = requests.get(
url,
auth=(username, password),
timeout=self.timeout,
verify=False
)
return response.status_code == 200
except Exception:
return False
def stop(self):
"""Stop testing"""
self.is_running = False
class RTSPDetectionThread(QThread):
"""Thread for RTSP detection"""
progress = pyqtSignal(str)
stream_found = pyqtSignal(str)
finished = pyqtSignal()
def __init__(self, ip, rtsp_ports):
super().__init__()
self.ip = ip
self.rtsp_ports = rtsp_ports
self.is_running = True
def run(self):
"""Detect RTSP streams"""
try:
common_paths = [
'/', '/live.sdp', '/h264.sdp', '/stream1', '/Streaming/Channels/1',
'/axis-media/media.amp', '/axis-media/media.amp?camera=1',
'/onvif/streaming/channels/1', '/cgi-bin/mjpg/video.cgi'
]
for port in self.rtsp_ports:
if not self.is_running:
break
for path in common_paths:
if not self.is_running:
break
url = f"rtsp://{self.ip}:{port}{path}"
self.progress.emit(f"Detectando RTSP: {url}")
if self.probe_rtsp(self.ip, port):
self.stream_found.emit(url)
self.progress.emit("Detección de RTSP completada")
self.finished.emit()
except Exception as e:
self.progress.emit(f"Error: {str(e)}")
self.finished.emit()
def probe_rtsp(self, ip, port):
"""Probe for RTSP service"""
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(1.5)
if s.connect_ex((ip, port)) != 0:
return False
request = (
f"OPTIONS rtsp://{ip}:{port}/ RTSP/1.0\r\n"
"CSeq: 1\r\n"
"\r\n"
).encode("ascii", errors="ignore")
s.sendall(request)
try:
data = s.recv(2048)
except socket.timeout:
return False
if not data:
return False
text = data.decode(errors="ignore")
return "RTSP/1.0" in text
except Exception:
return False
def stop(self):
"""Stop detection"""
self.is_running = False
class FingerprintThread(QThread):
"""Thread for device fingerprinting"""
progress = pyqtSignal(str)
device_info = pyqtSignal(str, str, str, str)
finished = pyqtSignal()
def __init__(self, ip, ports):
super().__init__()
self.ip = ip
self.ports = ports
self.is_running = True
def run(self):
"""Fingerprint devices"""
try:
for port in self.ports[:5]:
if not self.is_running:
break
protocol = "https" if port in [443, 8443] else "http"
url = f"{protocol}://{self.ip}:{port}/"
self.progress.emit(f"Fingerprinting puerto {port}...")
try:
response = requests.get(
url,
timeout=3,
verify=False,
headers={'User-Agent': 'CamXploit/2.0'}
)
if response.status_code == 200:
server = response.headers.get('Server', '')
content = response.text.lower()
brand = self.detect_brand(server, content)
model = self.detect_model(content)
firmware = self.detect_firmware(content)
if brand != "UNKNOWN":
self.device_info.emit(brand, model, firmware, str(port))
except Exception as e:
self.progress.emit(f"Puerto {port}: {str(e)}")
self.progress.emit("Fingerprinting completado")
self.finished.emit()
except Exception as e:
self.progress.emit(f"Error: {str(e)}")
self.finished.emit()
@staticmethod
def detect_brand(server, content):
"""Detect device brand"""
brands = {
'hikvision': ['hikvision', 'ds-'],
'dahua': ['dahua', 'nvr', 'dvr'],
'axis': ['axis', 'axis communications'],
'sony': ['sony', 'ipela'],
'panasonic': ['panasonic'],
'bosch': ['bosch'],
'samsung': ['samsung', 'techwin'],
}
search_text = (server + content).lower()
for brand, keywords in brands.items():
if any(kw in search_text for kw in keywords):
return brand.upper()
return "UNKNOWN"
@staticmethod
def detect_model(content):
"""Detect device model"""
patterns = [
r'Model["\']?\s*:\s*([^"\'<>\n]+)',
r'model["\']?\s*:\s*([^"\'<>\n]+)',
r'Device["\']?\s*:\s*([^"\'<>\n]+)',
r'device["\']?\s*:\s*([^"\'<>\n]+)',
]
for pattern in patterns:
match = re.search(pattern, content, re.IGNORECASE)
if match:
return match.group(1).strip()[:50]
return "N/A"
@staticmethod
def detect_firmware(content):
"""Detect firmware version"""
patterns = [
r'Firmware["\']?\s*:\s*([^"\'<>\n]+)',
r'firmware["\']?\s*:\s*([^"\'<>\n]+)',
r'Version["\']?\s*:\s*([^"\'<>\n]+)',
r'version["\']?\s*:\s*([^"\'<>\n]+)',
]
for pattern in patterns:
match = re.search(pattern, content, re.IGNORECASE)
if match:
return match.group(1).strip()[:50]
return "N/A"
def stop(self):
"""Stop fingerprinting"""
self.is_running = False
============================================================================
MAIN APPLICATION
============================================================================
class CamXploitGUI(QMainWindow):
"""Main application window"""
def __init__(self):
super().__init__()
self.settings = QSettings("CamXploit", "GUI")
self.init_ui()
self.apply_theme()
self.restore_settings()
# Thread management
self.scanner_thread = None
self.credential_thread = None
self.rtsp_thread = None
self.fingerprint_thread = None
def init_ui(self):
"""Initialize user interface"""
self.setWindowTitle("🔥 CamXploit - Camera Exploitation Scanner v2.0")
self.setGeometry(100, 100, 1400, 900)
self.setMinimumSize(1200, 700)
# Create menu bar
self.create_menu_bar()
# Create main layout
main_widget = QWidget()
self.setCentralWidget(main_widget)
main_layout = QHBoxLayout()
# Create panels
left_panel = self.create_left_panel()
right_panel = self.create_right_panel()
# Add splitter
splitter = QSplitter(Qt.Orientation.Horizontal)
splitter.addWidget(left_panel)
splitter.addWidget(right_panel)
splitter.setStretchFactor(0, 2)
splitter.setStretchFactor(1, 3)
main_layout.addWidget(splitter)
main_widget.setLayout(main_layout)
# Create status bar
self.statusBar().showMessage("Listo")
self.statusBar().setStyleSheet(f"""
QStatusBar {{
background-color: {CyberpunkTheme.BG_CARD};
color: {CyberpunkTheme.TEXT_PRIMARY};
border-top: 2px solid {CyberpunkTheme.NEON_CYAN};
}}
""")
def create_menu_bar(self):
"""Create application menu bar"""
menubar = self.menuBar()
# File menu
file_menu = menubar.addMenu("📁 Archivo")
save_action = file_menu.addAction("💾 Guardar Reporte")
save_action.triggered.connect(self.save_report)
file_menu.addSeparator()
exit_action = file_menu.addAction("❌ Salir")
exit_action.triggered.connect(self.close)
# Tools menu
tools_menu = menubar.addMenu("🛠️ Herramientas")
clear_action = tools_menu.addAction("🗑️ Limpiar Datos")
clear_action.triggered.connect(self.clear_all_data)
# Help menu
help_menu = menubar.addMenu("❓ Ayuda")
about_action = help_menu.addAction("ℹ️ Acerca de")
about_action.triggered.connect(self.show_about)
def create_left_panel(self):
"""Create left control panel"""
frame = QFrame()
frame.setStyleSheet(f"""
QFrame {{
border: 2px solid {CyberpunkTheme.NEON_CYAN};
border-radius: 5px;
background-color: {CyberpunkTheme.BG_CARD};
}}
""")
layout = QVBoxLayout()
layout.setContentsMargins(15, 15, 15, 15)
layout.setSpacing(10)
# Title
title = CyberpunkLabel("⚔️ OBJETIVO", CyberpunkTheme.NEON_MAGENTA, 14, True)
layout.addWidget(title)
# IP Input
layout.addWidget(CyberpunkLabel("Dirección IP:"))
self.ip_input = QLineEdit()
self.ip_input.setPlaceholderText("ej: 192.168.1.100 o 10.0.0.50")
layout.addWidget(self.ip_input)
# Port Range
layout.addWidget(CyberpunkLabel("Rango de Puertos:"))
port_layout = QGridLayout()
port_layout.addWidget(CyberpunkLabel("De:", size=10), 0, 0)
self.port_start = QSpinBox()
self.port_start.setMinimum(1)
self.port_start.setMaximum(65535)
self.port_start.setValue(80)
port_layout.addWidget(self.port_start, 0, 1)
port_layout.addWidget(CyberpunkLabel("A:", size=10), 0, 2)
self.port_end = QSpinBox()
self.port_end.setMinimum(1)
self.port_end.setMaximum(65535)
self.port_end.setValue(9000)
port_layout.addWidget(self.port_end, 0, 3)
layout.addLayout(port_layout)
# Timeout
layout.addWidget(CyberpunkLabel("Timeout (segundos):"))
self.timeout_spin = QDoubleSpinBox()
self.timeout_spin.setMinimum(0.5)
self.timeout_spin.setMaximum(10.0)
self.timeout_spin.setValue(1.5)
self.timeout_spin.setSingleStep(0.5)
layout.addWidget(self.timeout_spin)
# Advanced options
layout.addSpacing(15)
layout.addWidget(CyberpunkLabel("⚙️ OPCIONES", CyberpunkTheme.NEON_PURPLE, 12, True))
self.rtsp_check = QCheckBox("Detectar RTSP")
self.rtsp_check.setChecked(True)
layout.addWidget(self.rtsp_check)
self.fingerprint_check = QCheckBox("Fingerprinting")
self.fingerprint_check.setChecked(True)
layout.addWidget(self.fingerprint_check)
self.credentials_check = QCheckBox("Probar Credenciales")
self.credentials_check.setChecked(True)
layout.addWidget(self.credentials_check)
# Action buttons
layout.addSpacing(20)
layout.addWidget(CyberpunkLabel("⚡ CONTROLES", CyberpunkTheme.NEON_GREEN, 12, True))
button_layout = QGridLayout()
self.scan_button = GlowingButton("🔍 ESCANEAR", CyberpunkTheme.NEON_CYAN)
self.scan_button.clicked.connect(self.start_scan)
button_layout.addWidget(self.scan_button, 0, 0, 1, 2)
self.stop_button = GlowingButton("⏹ DETENER", CyberpunkTheme.NEON_MAGENTA)
self.stop_button.clicked.connect(self.stop_scan)
self.stop_button.setEnabled(False)
button_layout.addWidget(self.stop_button, 1, 0, 1, 2)
layout.addLayout(button_layout)
# Status
layout.addSpacing(20)
layout.addWidget(CyberpunkLabel("📊 ESTADO", CyberpunkTheme.NEON_CYAN, 12, True))
self.status_indicator = StatusIndicator("offline")
layout.addWidget(self.status_indicator)
self.status_text = CyberpunkLabel("Esperando entrada...", CyberpunkTheme.TEXT_SECONDARY, 10)
self.status_text.setWordWrap(True)
self.status_text.setMinimumHeight(40)
layout.addWidget(self.status_text)
self.progress_bar = QProgressBar()
self.progress_bar.setValue(0)
layout.addWidget(self.progress_bar)
# Statistics
layout.addSpacing(20)
layout.addWidget(CyberpunkLabel("📈 ESTADÍSTICAS", CyberpunkTheme.NEON_BLUE, 12, True))
self.stats_label = CyberpunkLabel("", CyberpunkTheme.TEXT_SECONDARY, 10)
self.stats_label.setWordWrap(True)
layout.addWidget(self.stats_label)
layout.addStretch()
frame.setLayout(layout)
return frame
def create_right_panel(self):
"""Create right results panel"""
self.tabs = QTabWidget()
# Tab 1: Open Ports
self.ports_table = QTableWidget()
self.ports_table.setColumnCount(4)
self.ports_table.setHorizontalHeaderLabels(["Puerto", "Servicio", "Estado", "Detalles"])
self.ports_table.horizontalHeader().setStretchLastSection(True)
self.ports_table.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows)
self.ports_table.setSelectionMode(QTableWidget.SelectionMode.SingleSelection)
self.tabs.addTab(self.ports_table, "🔌 Puertos")
# Tab 2: Log
self.log_text = QTextEdit()
self.log_text.setReadOnly(True)
self.tabs.addTab(self.log_text, "📋 Log")
# Tab 3: Credentials
self.creds_table = QTableWidget()
self.creds_table.setColumnCount(5)
self.creds_table.setHorizontalHeaderLabels(["Usuario", "Contraseña", "Puerto", "Protocolo", "URL"])
self.creds_table.horizontalHeader().setStretchLastSection(True)
self.tabs.addTab(self.creds_table, "🔐 Credenciales")
# Tab 4: Devices
self.devices_table = QTableWidget()
self.devices_table.setColumnCount(4)
self.devices_table.setHorizontalHeaderLabels(["Marca", "Modelo", "Firmware", "Puerto"])
self.devices_table.horizontalHeader().setStretchLastSection(True)
self.tabs.addTab(self.devices_table, "🔬 Dispositivos")
# Tab 5: RTSP Streams
self.streams_list = QListWidget()
self.tabs.addTab(self.streams_list, "🎥 Streams")
# Tab 6: OSINT
self.osint_text = QTextEdit()
self.osint_text.setReadOnly(True)
self.tabs.addTab(self.osint_text, "🌐 OSINT")
return self.tabs
def apply_theme(self):
"""Apply cyberpunk theme"""
self.setStyleSheet(CyberpunkTheme.get_stylesheet())
palette = QPalette()
palette.setColor(QPalette.ColorRole.Window, QColor(CyberpunkTheme.BG_DARK))
palette.setColor(QPalette.ColorRole.WindowText, QColor(CyberpunkTheme.TEXT_PRIMARY))
self.setPalette(palette)
def start_scan(self):
"""Start port scanning"""
ip = self.ip_input.text().strip()
if not ip:
QMessageBox.warning(self, "Error", "Por favor ingresa una dirección IP")
return
try:
ipaddress.ip_address(ip)
except ValueError:
QMessageBox.warning(self, "Error", "Dirección IP inválida")
return
# Generate port list
port_start = self.port_start.value()
port_end = self.port_end.value()
if port_start > port_end:
QMessageBox.warning(self, "Error", "Puerto inicial debe ser menor que final")
return
ports = list(range(port_start, port_end + 1))
timeout = self.timeout_spin.value()
# Clear previous results
self.ports_table.setRowCount(0)
self.creds_table.setRowCount(0)
self.devices_table.setRowCount(0)
self.streams_list.clear()
self.log_text.clear()
self.osint_text.clear()
# Start scanner thread
self.scanner_thread = ScannerThread(ip, ports, timeout)
self.scanner_thread.progress.connect(self.update_status)
self.scanner_thread.port_found.connect(self.add_port_to_table)
self.scanner_thread.finished.connect(self.on_scan_finished)
# Update UI
self.scan_button.setEnabled(False)
self.stop_button.setEnabled(True)
self.status_indicator.set_status("scanning")
self.progress_bar.setValue(0)
self.log_text.append(f"╔════════════════════════════════════════════════════════╗")
self.log_text.append(f"║ CamXploit v2.0 - Scan Report ║")
self.log_text.append(f"╚════════════════════════════════════════════════════════╝\n")
self.log_text.append(f"[*] Target IP: {ip}")
self.log_text.append(f"[*] Port Range: {port_start}-{port_end}")
self.log_text.append(f"[*] Timeout: {timeout}s")
self.log_text.append(f"[*] Total Ports: {len(ports)}")
self.log_text.append("-" * 60)
self.scanner_thread.start()
def stop_scan(self):
"""Stop scanning"""
if self.scanner_thread and self.scanner_thread.is_running:
self.scanner_thread.stop()
self.scanner_thread.wait()
if self.credential_thread and self.credential_thread.is_running:
self.credential_thread.stop()
self.credential_thread.wait()
if self.rtsp_thread and self.rtsp_thread.is_running:
self.rtsp_thread.stop()
self.rtsp_thread.wait()
if self.fingerprint_thread and self.fingerprint_thread.is_running:
self.fingerprint_thread.stop()
self.fingerprint_thread.wait()
self.scan_button.setEnabled(True)
self.stop_button.setEnabled(False)
self.status_indicator.set_status("offline")
self.log_text.append("[!] Escaneo detenido por el usuario")
def update_status(self, message):
"""Update status message"""
self.status_text.setText(message)
self.log_text.append(f"[*] {message}")
cursor = self.log_text.textCursor()
cursor.movePosition(QTextCursor.MoveOperation.End)
self.log_text.setTextCursor(cursor)
def add_port_to_table(self, port, service, protocol):
"""Add found port to table"""
row = self.ports_table.rowCount()
self.ports_table.insertRow(row)
port_item = QTableWidgetItem(str(port))
port_item.setForeground(QColor(CyberpunkTheme.NEON_GREEN))
port_item.setFont(QFont("Courier New", 11, QFont.Weight.Bold))
service_item = QTableWidgetItem(service)
service_item.setForeground(QColor(CyberpunkTheme.NEON_CYAN))
status_item = QTableWidgetItem("✅ ABIERTO")
status_item.setForeground(QColor(CyberpunkTheme.SUCCESS))
details_item = QTableWidgetItem(PORT_SERVICE_MAP.get(port, ("", "Desconocido"))[1])
details_item.setForeground(QColor(CyberpunkTheme.TEXT_SECONDARY))
self.ports_table.setItem(row, 0, port_item)
self.ports_table.setItem(row, 1, service_item)
self.ports_table.setItem(row, 2, status_item)
self.ports_table.setItem(row, 3, details_item)
self.log_text.append(f"[+] PUERTO ABIERTO: {port} ({service})")
def on_scan_finished(self, port_count):
"""Callback when scan finishes"""
self.scan_button.setEnabled(True)
self.stop_button.setEnabled(False)
if port_count > 0:
self.status_indicator.set_status("online")
self.log_text.append(f"\n[✓] Escaneo completado: {port_count} puertos abiertos")
# Update statistics
self.update_statistics(port_count)
# Optionally run additional scans
if self.fingerprint_check.isChecked():
self.start_fingerprinting()
elif self.credentials_check.isChecked():
self.start_credential_testing()
elif self.rtsp_check.isChecked():
self.start_rtsp_detection()
else:
self.status_indicator.set_status("offline")
self.log_text.append("[!] No se encontraron puertos abiertos")
self.progress_bar.setValue(100)
def start_credential_testing(self):
"""Start credential testing"""
if not self.ports_table.rowCount():
self.log_text.append("[!] No hay puertos para probar credenciales")
return
ip = self.ip_input.text().strip()
ports = []
for row in range(self.ports_table.rowCount()):
port_text = self.ports_table.item(row, 0).text()
ports.append(int(port_text))
self.credential_thread = CredentialTestThread(ip, ports)
self.credential_thread.progress.connect(self.update_status)
self.credential_thread.found_creds.connect(self.add_credentials_to_table)
self.credential_thread.finished.connect(self.on_credentials_finished)
self.log_text.append("\n[*] Iniciando prueba de credenciales...")
self.credential_thread.start()
def add_credentials_to_table(self, user, passwd, port, protocol, url):
"""Add found credentials"""
row = self.creds_table.rowCount()
self.creds_table.insertRow(row)
user_item = QTableWidgetItem(user)
user_item.setForeground(QColor(CyberpunkTheme.NEON_MAGENTA))
passwd_item = QTableWidgetItem(passwd)
passwd_item.setForeground(QColor(CyberpunkTheme.NEON_GREEN))
port_item = QTableWidgetItem(port)
port_item.setForeground(QColor(CyberpunkTheme.NEON_CYAN))
protocol_item = QTableWidgetItem(protocol)
protocol_item.setForeground(QColor(CyberpunkTheme.NEON_YELLOW))
url_item = QTableWidgetItem(url)
url_item.setForeground(QColor(CyberpunkTheme.TEXT_SECONDARY))
self.creds_table.setItem(row, 0, user_item)
self.creds_table.setItem(row, 1, passwd_item)
self.creds_table.setItem(row, 2, port_item)
self.creds_table.setItem(row, 3, protocol_item)
self.creds_table.setItem(row, 4, url_item)
self.log_text.append(f"[🔥] CREDENCIALES VÁLIDAS: {user}:{passwd} @ {url}")
def on_credentials_finished(self):
"""Callback when credentials finished"""
self.log_text.append("[✓] Test de credenciales completado")
if self.rtsp_check.isChecked():
self.start_rtsp_detection()
def start_fingerprinting(self):
"""Start device fingerprinting"""
if not self.ports_table.rowCount():
return
ip = self.ip_input.text().strip()
ports = []
for row in range(self.ports_table.rowCount()):
port_text = self.ports_table.item(row, 0).text()
ports.append(int(port_text))
self.fingerprint_thread = FingerprintThread(ip, ports)
self.fingerprint_thread.progress.connect(self.update_status)
self.fingerprint_thread.device_info.connect(self.add_device_info)
self.fingerprint_thread.finished.connect(self.on_fingerprint_finished)
self.log_text.append("\n[*] Iniciando fingerprinting...")
self.fingerprint_thread.start()
def add_device_info(self, brand, model, firmware, port):
"""Add device information"""
row = self.devices_table.rowCount()
self.devices_table.insertRow(row)
brand_item = QTableWidgetItem(brand)
brand_item.setForeground(QColor(CyberpunkTheme.NEON_MAGENTA))
brand_item.setFont(QFont("Courier New", 10, QFont.Weight.Bold))
model_item = QTableWidgetItem(model)
model_item.setForeground(QColor(CyberpunkTheme.NEON_CYAN))
firmware_item = QTableWidgetItem(firmware)
firmware_item.setForeground(QColor(CyberpunkTheme.NEON_GREEN))
port_item = QTableWidgetItem(port)
port_item.setForeground(QColor(CyberpunkTheme.NEON_YELLOW))
self.devices_table.setItem(row, 0, brand_item)
self.devices_table.setItem(row, 1, model_item)
self.devices_table.setItem(row, 2, firmware_item)
self.devices_table.setItem(row, 3, port_item)
self.log_text.append(f"[📡] Dispositivo: {brand} {model} (FW: {firmware}) en puerto {port}")
# Check for CVEs
self.check_cves(brand)
def on_fingerprint_finished(self):
"""Callback when fingerprinting finished"""
self.log_text.append("[✓] Fingerprinting completado")
if self.credentials_check.isChecked():
self.start_credential_testing()
elif self.rtsp_check.isChecked():
self.start_rtsp_detection()
def start_rtsp_detection(self):
"""Start RTSP stream detection"""
if not self.ports_table.rowCount():
return
ip = self.ip_input.text().strip()
rtsp_ports = []
for row in range(self.ports_table.rowCount()):
port_text = self.ports_table.item(row, 0).text()
port = int(port_text)
if port in [554, 8554, 10554, 5554, 7070]:
rtsp_ports.append(port)
if not rtsp_ports:
# Add default RTSP ports
rtsp_ports = [554, 8554]
self.rtsp_thread = RTSPDetectionThread(ip, rtsp_ports)
self.rtsp_thread.progress.connect(self.update_status)
self.rtsp_thread.stream_found.connect(self.add_stream_to_list)
self.rtsp_thread.finished.connect(self.on_rtsp_finished)
self.log_text.append("\n[*] Detectando streams RTSP...")
self.rtsp_thread.start()
def add_stream_to_list(self, url):
"""Add stream URL to list"""
item = QListWidgetItem(url)
item.setForeground(QColor(CyberpunkTheme.NEON_GREEN))
self.streams_list.addItem(item)
self.log_text.append(f"[🎥] RTSP Stream encontrado: {url}")
def on_rtsp_finished(self):
"""Callback when RTSP detection finished"""
self.log_text.append("[✓] Detección de RTSP completada")
def check_cves(self, brand):
"""Check for known CVEs"""
brand_lower = brand.lower()
if brand_lower in CVE_DATABASE:
cves = CVE_DATABASE[brand_lower]
self.log_text.append(f"\n[⚠️] CVEs conocidos para {brand}:")
for cve in cves[:3]:
self.log_text.append(f" • {cve}")
def update_statistics(self, open_ports):
"""Update statistics display"""
stats_text = f"Puertos abiertos: {open_ports}\n"
stats_text += f"Credenciales encontradas: {self.creds_table.rowCount()}\n"
stats_text += f"Dispositivos detectados: {self.devices_table.rowCount()}"
self.stats_label.setText(stats_text)
def save_report(self):
"""Save scan report"""
if self.ports_table.rowCount() == 0:
QMessageBox.warning(self, "Error", "No hay datos para guardar")
return
filename, _ = QFileDialog.getSaveFileName(
self, "Guardar Reporte", "", "JSON Files (*.json);;Text Files (*.txt)"
)
if not filename:
return
try:
report = {
"timestamp": datetime.now().isoformat(),
"target_ip": self.ip_input.text(),
"open_ports": [],
"credentials": [],
"devices": [],
"streams": []
}
# Collect ports
for row in range(self.ports_table.rowCount()):
port = self.ports_table.item(row, 0).text()
service = self.ports_table.item(row, 1).text()
report["open_ports"].append({
"port": int(port),
"service": service
})
# Collect credentials
for row in range(self.creds_table.rowCount()):
user = self.creds_table.item(row, 0).text()
passwd = self.creds_table.item(row, 1).text()
port = self.creds_table.item(row, 2).text()
report["credentials"].append({
"username": user,
"password": passwd,
"port": port
})
# Collect devices
for row in range(self.devices_table.rowCount()):
brand = self.devices_table.item(row, 0).text()
model = self.devices_table.item(row, 1).text()
firmware = self.devices_table.item(row, 2).text()
port = self.devices_table.item(row, 3).text()
report["devices"].append({
"brand": brand,
"model": model,
"firmware": firmware,
"port": port
})
# Collect streams
for i in range(self.streams_list.count()):
report["streams"].append(self.streams_list.item(i).text())
# Save to file
with open(filename, 'w') as f:
json.dump(report, f, indent=2)
QMessageBox.information(self, "Éxito", f"Reporte guardado en {filename}")
except Exception as e:
QMessageBox.critical(self, "Error", f"Error al guardar: {str(e)}")
def clear_all_data(self):
"""Clear all data"""
self.ports_table.setRowCount(0)
self.creds_table.setRowCount(0)
self.devices_table.setRowCount(0)
self.streams_list.clear()
self.log_text.clear()
self.osint_text.clear()
self.status_text.setText("Datos limpiados")
def show_about(self):
"""Show about dialog"""
about_text = """
<h2>CamXploit v2.0</h2>
<p><b>Camera Exploitation & CCTV Scanner</b></p>
<p>Advanced tool for security research and camera exploitation testing.</p>
<p><b>Features:</b></p>
<ul>
<li>🔍 Port scanning</li>
<li>🔐 Credential testing</li>
<li>🔬 Device fingerprinting</li>
<li>🎥 RTSP stream detection</li>
<li>📊 Real-time reporting</li>
</ul>
<p><b>Disclaimer:</b><br>
This tool is for authorized security testing only. Unauthorized access is illegal.</p>
<p><b>Original:</b> Spyboy Productions<br>
<b>GUI Version:</b> Security Community</p>
"""
QMessageBox.about(self, "Acerca de CamXploit", about_text)
def restore_settings(self):
"""Restore application settings"""
geometry = self.settings.value("geometry")
if geometry:
self.restoreGeometry(geometry)
def closeEvent(self, event):
"""Handle application close"""
# Stop all threads
self.stop_scan()
# Save settings
self.settings.setValue("geometry", self.saveGeometry())
event.accept()
============================================================================
APPLICATION ENTRY POINT
============================================================================
def main():
"""Main application entry point"""
app = QApplication(sys.argv)
app.setApplicationName("CamXploit GUI")
app.setApplicationVersion("2.0")
window = CamXploitGUI()
window.show()
sys.exit(app.exec())
if name == "main":
main()
#!/usr/bin/env python3
-- coding: utf-8 --
#!/usr/bin/env python3
-- coding: utf-8 --
"""
╔══════════════════════════════════════════════════════════════════════════════╗
║ CamXploit GUI - Cyberpunk Edition v2.0 ║
║ Camera Exploitation & CCTV Scanner with PyQt6 Interface ║
║ ║
║ 🔥 Advanced CCTV/DVR/NVR Scanner with Beautiful Cyberpunk GUI ║
║ 🎨 Modern dark theme with neon accents ║
║ ⚡ High-performance threading for responsive UI ║
║ 🔍 Comprehensive port scanning and device detection ║
║ 🔐 Automatic credential testing ║
║ 🎥 RTSP stream detection ║
║ 📊 Real-time progress and logging ║
║ ║
║ Original CamXploit by Spyboy: https://github.com/spyboy-productions ║
║ GUI Version by: Security Researcher Community ║
║ License: Educational Use Only ║
╚══════════════════════════════════════════════════════════════════════════════╝
"""
import sys
import requests
import socket
import threading
import warnings
import base64
import time
import ipaddress
import json
from xml.etree import ElementTree as ET
from datetime import datetime
from urllib.parse import quote
import re
from PyQt6.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLineEdit, QPushButton, QTextEdit, QTabWidget, QTableWidget,
QTableWidgetItem, QLabel, QComboBox, QSpinBox, QProgressBar,
QDialog, QMessageBox, QScrollArea, QFrame, QListWidget, QListWidgetItem,
QHeaderView, QSplitter, QStatusBar, QMenuBar, QMenu, QFileDialog,
QCheckBox, QGroupBox, QGridLayout, QDoubleSpinBox
)
from PyQt6.QtCore import Qt, QThread, pyqtSignal, QTimer, QSize, QRect, QSettings
from PyQt6.QtGui import (
QFont, QColor, QIcon, QPixmap, QTextCursor, QLinearGradient, QPalette,
QTextCharFormat, QBrush, QPen
)
from PyQt6.QtWidgets import QSizePolicy, QApplication
from PyQt6.QtCore import QPropertyAnimation
warnings.filterwarnings("ignore")
requests.packages.urllib3.disable_warnings()
============================================================================
CONSTANTS & CONFIGURATION
============================================================================
COMMON_PORTS = [
# Standard ports
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 443, 8080, 8443, 8000, 8001, 8008,
8081, 8082, 8083, 8084, 8085, 8086, 8087, 8088, 8089, 8090, 8091, 8092,
# RTSP
554, 8554, 10554, 1554, 2554, 3554, 4554, 5554, 6554, 7554, 9554,
# RTMP
1935, 1936, 1937, 1938, 1939,
# Custom camera ports
37777, 37778, 37779, 37780, 37781, 37782, 37783, 37784, 37785,
# ONVIF
3702, 3703, 3704, 3705, 3706, 3707, 3708, 3709, 3710,
# Common ports
21, 22, 23, 25, 53, 110, 143, 993, 995, 1024, 1025, 1026, 1027, 1028,
2000, 2001, 2002, 2003, 2004, 2005, 3000, 3001, 3002, 3003, 3004, 3005,
4000, 4001, 4002, 4003, 4004, 4005, 5000, 5001, 5002, 5003, 5004, 5005,
6000, 6001, 6002, 6003, 6004, 6005, 7000, 7001, 7002, 7003, 7004, 7005,
9000, 9001, 9002, 9003, 9004, 9005, 8888, 8889, 8890, 8891, 8892,
9999, 9998, 9997, 9996, 9995, 1755, 1756, 1757, 1758, 1759,
10000, 10001, 10002, 10003, 10004, 10005, 10006, 10007, 10008, 10009,
11000, 11001, 11002, 11003, 11004, 11005, 20000, 20001, 20002, 20003,
21000, 21001, 21002, 21003, 30000, 30001, 30002, 30003, 40000, 40001,
50000, 50001, 60000, 60001, 65000, 65001
]
DEFAULT_CREDENTIALS = {
"admin": ["admin", "1234", "12345", "123456", "1234567", "12345678",
"123456789", "admin123", "admin1234", "password", "888888",
"666666", "8888", "pass", "123", "1111", "0000"],
"root": ["root", "toor", "1234", "12345", "123456", "pass", "password"],
"user": ["user", "user123", "password", "1234", "12345", "123456"],
"guest": ["guest", "guest123", "1234", "12345", "123456"],
"operator": ["operator", "operator123", "1234", "12345"],
"administrator": ["administrator", "admin", "1234", "12345", "123456"],
"supervisor": ["supervisor", "1234", "12345", "123456"],
"support": ["support", "support123", "1234"],
"system": ["system", "system123", "1234", "12345"],
"viewer": ["viewer", "viewer123", "1234", "12345"],
}
PORT_SERVICE_MAP = {
80: ("HTTP", "Web Interface"),
81: ("HTTP-Alt", "Web Interface"),
443: ("HTTPS", "Secure Web"),
554: ("RTSP", "Streaming Protocol"),
8080: ("HTTP-Alt", "Web Interface"),
8443: ("HTTPS-Alt", "Secure Web"),
8000: ("HTTP-Alt", "Web/Hikvision"),
8554: ("RTSP-Alt", "Streaming"),
1935: ("RTMP", "Streaming"),
3702: ("ONVIF", "Device Discovery"),
37777: ("Dahua", "DVR/NVR"),
37778: ("Dahua", "DVR/NVR"),
8008: ("Hikvision", "Web/API"),
1755: ("MMS", "Media Server"),
}
CVE_DATABASE = {
"hikvision": [
"CVE-2021-36260", "CVE-2017-7921", "CVE-2021-31955", "CVE-2021-31956",
"CVE-2021-31957", "CVE-2021-31958", "CVE-2021-31959", "CVE-2021-31960",
],
"dahua": [
"CVE-2021-33044", "CVE-2022-30563", "CVE-2021-33045", "CVE-2021-33046",
"CVE-2021-33047", "CVE-2021-33048", "CVE-2021-33049", "CVE-2021-33050",
],
"axis": [
"CVE-2018-10660", "CVE-2020-29550", "CVE-2020-29551", "CVE-2020-29552",
],
}
============================================================================
CYBERPUNK THEME
============================================================================
class CyberpunkTheme:
"""Complete cyberpunk theme configuration"""
============================================================================
CUSTOM WIDGETS
============================================================================
class CyberpunkLabel(QLabel):
"""Cyberpunk styled label"""
def init(self, text, color=CyberpunkTheme.TEXT_PRIMARY, size=12, bold=False):
super().init(text)
font = QFont("Courier New", size)
font.setBold(bold)
self.setFont(font)
self.setStyleSheet(f"color: {color}; background-color: transparent;")
class GlowingButton(QPushButton):
"""Glowing cyberpunk button"""
def init(self, text, color=CyberpunkTheme.NEON_CYAN):
super().init(text)
self.base_color = color
self.update_style(color)
class StatusIndicator(QLabel):
"""Status indicator with colors"""
def init(self, status="offline"):
super().init()
self.status = status
self.set_status(status)
============================================================================
SCANNER THREADS
============================================================================
class ScannerThread(QThread):
"""Thread for port scanning"""
class CredentialTestThread(QThread):
"""Thread for credential testing"""
class RTSPDetectionThread(QThread):
"""Thread for RTSP detection"""
class FingerprintThread(QThread):
"""Thread for device fingerprinting"""
============================================================================
MAIN APPLICATION
============================================================================
class CamXploitGUI(QMainWindow):
"""Main application window"""
============================================================================
APPLICATION ENTRY POINT
============================================================================
def main():
"""Main application entry point"""
app = QApplication(sys.argv)
app.setApplicationName("CamXploit GUI")
app.setApplicationVersion("2.0")
if name == "main":
main()