
CVE-2026-40176 के लिए विभेदक प्रूफ-ऑफ-कॉन्सेप्ट, जो एक दुर्भावनापूर्ण रिपॉजिटरी URL के माध्यम से Composer के Perforce ड्राइवर में OS कमांड इंजेक्शन का प्रदर्शन करता है, जिसमें प्रभावित और फिक्स किए गए संस्करणों के विरुद्ध स्वचालित A/B परीक्षण शामिल है।
एक स्व-निहित, OOP-शैली PHP प्रूफ़ ऑफ़ कॉन्सेप्ट जो कंपोज़र के पर्फ़ोर्स रिपॉजिटरी ड्राइवर में एक कमांड-इंजेक्शन भेद्यता को प्रदर्शित और अंतर सत्यापित करता है।
PoC एक ही दुर्भावनापूर्ण composer.json को दो कंपोज़र बाइनरी — एक प्रभावित रिलीज़ (2.9.5) और एक ठीक की गई रिलीज़ (2.9.6) — पर चलाता है, और एक साइड इफ़ेक्ट (एक इंजेक्टेड शेल कमांड द्वारा लिखी गई मार्कर फ़ाइल) का अवलोकन करके बग को साबित करता है जो प्रभावित संस्करण पर ट्रिगर होता है लेकिन ठीक किए गए संस्करण पर नहीं।
⚠️ केवल अधिकृत सुरक्षा अनुसंधान और रक्षात्मक परीक्षण के लिए। जिम्मेदार उपयोग देखें।
| सीवीई | CVE-2026-40176 |
| घटक | कंपोज़र — पर्फ़ोर्स (perforce) रिपॉजिटरी/VCS ड्राइवर |
| वर्ग | हमलावर-नियंत्रित रिपॉजिटरी URL के माध्यम से OS कमांड इंजेक्शन |
| हमला सतह | एक composer.json जिसमें type: perforce की एक क्राफ्टेड repositories प्रविष्टि है |
| प्रभावित | कंपोज़र 2.9.5 |
| ठीक किया गया | कंपोज़र 2.9.6 |
| ट्रिगर | दुर्भावनापूर्ण मेनिफेस्ट के विरुद्ध निर्भरताओं को हल/अपडेट करना (composer update) |
| प्रभाव | कंपोज़र चलाने वाली मशीन पर मनमाना कमांड निष्पादन |
| PoC भाषा | PHP (एकल फ़ाइल, कोई बाहरी निर्भरता नहीं) |
कंपोज़र कई संस्करण-नियंत्रण प्रणालियों से पैकेज हल कर सकता है। पर्फ़ोर्स के लिए, रिपॉजिटरी एक p4:// URL द्वारा पहचाना जाता है जो होस्ट, पोर्ट और उपयोगकर्ता/स्ट्रीम को एन्कोड करता है। जब कंपोज़र का पर्फ़ोर्स ड्राइवर अंतर्निहित p4 कमांड लाइन बनाता है, तो हमलावर-नियंत्रित URL से लिए गए फ़ील्ड शेल को सौंपे जाने से पहले पर्याप्त रूप से स्वच्छ नहीं किए जाते हैं।
चूंकि मेनिफेस्ट लेखक रिपॉजिटरी URL को पूरी तरह से नियंत्रित करता है, एक हमलावर जो किसी पीड़ित को दुर्भावनापूर्ण composer.json के विरुद्ध composer update/composer install चलाने के लिए प्रेरित कर सकता है (उदाहरण के लिए, एक जहरीली निर्भरता, एक शत्रुतापूर्ण रिपॉजिटरी, या अविश्वसनीय प्रोजेक्ट फ़ाइलों को संसाधित करने वाला CI कार्य) इच्छित p4 आह्वान से बाहर निकल सकता है और कंपोज़र प्रक्रिया के विशेषाधिकारों के साथ मनमाना OS कमांड निष्पादित कर सकता है।
यह ऐतिहासिक कंपोज़र VCS-ड्राइवर आर्गुमेंट-इंजेक्शन समस्याओं के समान परिवार से संबंधित है, जहां URL/ब्रांच/स्ट्रीम मान बिना एस्केपिंग के शेल कमांड में प्रवाहित होते हैं। कंपोज़र 2.9.6 पर्फ़ोर्स ड्राइवर को मजबूत करता है ताकि इंजेक्टेड पेलोड अब निष्पादित न हो।
यहां प्रदर्शित व्यवहार का आधिकारिक विवरण स्वयं PoC स्रोत (
CVE202640176Test.php) है; अपस्ट्रीम फिक्स विवरण के लिए आधिकारिक सलाहकार और कंपोज़र चेंजलॉग देखें।
PoC एक एकल वर्ग है, CVE202640176Test, जो एक नियंत्रित A/B (अंतर) प्रयोग करता है:
2.9.5 और ठीक की गई 2.9.6) पर --version क्वेरी करता है और यदि उनमें से किसी को भी आमंत्रित नहीं किया जा सकता है तो जल्दी बाहर निकल जाता है।composer.json लिखता है जिसके repositories अनुभाग में एक perforce प्रविष्टि है जिसमें एक इंजेक्टेड शेल पेलोड वाला दुर्भावनापूर्ण p4:// URL है।composer update चलाता है।finally ब्लॉक हमेशा प्रोजेक्ट निर्देशिका में मूल composer.json को पुनर्स्थापित करता है।PASS प्रिंट करता है जब प्रभावित रन साइड इफ़ेक्ट दिखाता है और ठीक किया गया रन नहीं दिखाता।प्रत्येक रन के लिए, validateRun() तीन चीज़ों की जाँच करता है:
| जांच | यह क्या साबित करता है |
|---|---|
| मार्कर फ़ाइल मौजूद है और उसमें रन ID है | इंजेक्टेड touch/echo पेलोड वास्तव में निष्पादित हुआ — अर्थात कमांड इंजेक्शन सफल हुआ। |
कंपोज़र आउटपुट में p4 का उल्लेख है | पर्फ़ोर्स ड्राइवर कोड पथ तक पहुंच गया था (पेलोड सही घटक द्वारा संसाधित किया गया था, किसी असंबंधित चरण द्वारा नहीं)। |
| पार्स किया गया कंपोज़र संस्करण == अपेक्षित | सही बाइनरी (2.9.5 बनाम 2.9.6) वह थी जो चली। |
एक रन केवल तभी "OK" होता है जब तीनों पास हों। समग्र परीक्षण पास होता है जब प्रभावित रन OK होता है और ठीक किया गया रन नहीं होता — एक वास्तविक भेद्यता का सटीक हस्ताक्षर जिसे बाद में पैच किया गया।
दुर्भावनापूर्ण रिपॉजिटरी URL writeComposerJson() में बनाया गया है:
p4://127.0.0.1:1666:attacker_user;touch <marker> && echo '<runId>' > <marker>:client_test
इसे तोड़ते हुए:
p4://127.0.0.1:1666:attacker_user — एक अच्छी दिखने वाली पर्फ़ोर्स URL (होस्ट, पोर्ट 1666, उपयोगकर्ता)।;touch <marker> && echo '<runId>' > <marker> — इंजेक्टेड शेल कमांड। अग्रणी ; इच्छित p4 कमांड को समाप्त करता है; touch मार्कर फ़ाइल बनाता है, और echo '<runId>' > <marker> उसमें अद्वितीय रन ID लिखता है ताकि PoC पुष्टि कर सके कि पेलोड (और कोई असंबंधित प्रक्रिया नहीं) ने फ़ाइल उत्पन्न की।:client_test — बाकी URL पार्सिंग को प्रशंसनीय बनाए रखने के लिए अनुगामी टेक्स्ट।प्रभावित ड्राइवर पर शेल मेटाकैरेक्टर का सम्मान किया जाता है और मार्कर फ़ाइल बनाई जाती है। ठीक किए गए ड्राइवर पर मान को ठीक से एस्केप/कोट किया जाता है, इसलिए वही स्ट्रिंग निष्क्रिय डेटा के रूप में मानी जाती है और कोई मार्कर प्रकट नहीं होता।
नोट: PoC एक अद्वितीय, टाइमस्टैम्प्ड रन ID का उपयोग करता है और अपने मार्कर को एक पृथक अस्थायी निर्देशिका के अंदर लिखता है, इसलिए पेलोड हानिरहित और स्व-सफाई है न कि विनाशकारी।
2.9.5 (प्रभावित)2.9.6 (ठीक किया गया)exec() cd … && php … चलाता है)। Linux/macOS के लिए डिज़ाइन किया गया।composer.json (यह स्टार्टअप पर पढ़ा जाता है, प्रत्येक अस्थायी रन में कॉपी किया जाता है, और बाद में पुनर्स्थापित किया जाता है)।आपको आम तौर पर एक लाइव पर्फ़ोर्स सर्वर की आवश्यकता नहीं है: भेद्यता इस बात में है कि कंपोज़र
p4कमांड लाइन कैसे बनाता है, और इंजेक्टेड पेलोड किसी वास्तविकp4कनेक्शन से पहले/आसपास चलता है। कंपोज़र एक पर्फ़ोर्स कनेक्शन त्रुटि लॉग कर सकता है — यह अपेक्षित है और मार्कर-फ़ाइल प्रमाण को प्रभावित नहीं करता।
PoC को क्लोन करें / रखें एक कार्यशील निर्देशिका में।
एक composer.json प्रदान करें PoC के समान निर्देशिका में। एक न्यूनतम पर्याप्त है:
{
"name": "research/cve-2026-40176-poc",
"description": "Base manifest for the CVE-2026-40176 differential PoC",
"require": {}
}
दो कंपोज़र बाइनरी प्राप्त करें और उन्हें वहां रखें जहां PoC उनकी अपेक्षा करता है (डिफ़ॉल्ट दिखाए गए हैं):
/usr/local/bin/composer-2.9.5.phar # प्रभावित
/usr/local/bin/composer-2.9.6.phar # ठीक किया गया
आप आधिकारिक संग्रह से विशिष्ट कंपोज़र रिलीज़ डाउनलोड कर सकते हैं, उदा.:
curl -Lo /usr/local/bin/composer-2.9.5.phar https://getcomposer.org/download/2.9.5/composer.phar
curl -Lo /usr/local/bin/composer-2.9.6.phar https://getcomposer.org/download/2.9.6/composer.phar
यदि आपके पथ भिन्न हैं, तो
CVE202640176Test.phpके नीचे दो कंस्ट्रक्टर तर्क संपादित करें।
php CVE202640176Test.php
हार्नेस दोनों कंपोज़र संस्करणों को बारी-बारी से चलाता है और एक अंतिम निर्णय प्रिंट करता है। मूल composer.json स्वचालित रूप से पुनर्स्थापित हो जाता है भले ही कोई रन विफल हो (कार्य डिस्पोजेबल अस्थायी निर्देशिकाओं में होता है)।
रिपो ऐसा कंटेनरीकृत लैब भेजता है जो वातावरण को बिल्कुल दोहराता है: एक PHP CLI रनटाइम और उन पथों पर दो पिन किए गए कंपोज़र रिलीज़ जिनकी PoC अपेक्षा करता है, रनटाइम पर पूरी तरह से नेटवर्क-पृथक।
docker compose run --rm poc
यह cve-2026-40176-lab:latest बनाता है (बिल्ड के दौरान कंपोज़र 2.9.5 और 2.9.6 डाउनलोड करता है और प्रत्येक का --version सत्यापित करता है) और एक अनप्रिविलेज्ड, एग्रेस-मुक्त कंटेनर के अंदर अंतर परीक्षण चलाता है।
लैब क्या गारंटी देता है:
poc सेवा एक internal ब्रिज नेटवर्क (कोई होस्ट/इंटरनेट एग्रेस नहीं) पर चलती है, cap_drop: ALL और no-new-privileges के साथ। इंजेक्शन पेलोड समाहित रहता है।बिल्ड आर्ग के माध्यम से संस्करणों को रिपिन करें (PoC में दो कंस्ट्रक्टर पथों के साथ सिंक में रहना चाहिए):
docker compose build --build-arg COMPOSER_AFFECTED_VERSION=2.9.5 --build-arg COMPOSER_FIXED_VERSION=2.9.6
वैकल्पिक — लाइव पर्फ़ोर्स सर्वर। full-lab प्रोफ़ाइल के तहत एक p4d सेवा उपलब्ध है (docker compose --profile full-lab up). मार्कर-आधारित प्रमाण को इसकी आवश्यकता नहीं है; यह उन शोधकर्ताओं के लिए मौजूद है जो लाइव p4:// एंडपॉइंट चाहते हैं। ध्यान दें कि PoC पेलोड 127.0.0.1:1666 को लक्षित करता है, इसलिए एक अलग p4d कंटेनर के माध्यम से रूटिंग के लिए PoC URL को होस्ट p4d पर इंगित करने की आवश्यकता होती है।
ईमानदार परिणाम: वास्तविक, प्रकाशित कंपोज़र
2.9.5और2.9.6के विरुद्ध, PoC वर्तमान में फायर नहीं करता, और लैबINCONCLUSIVE / FAILरिपोर्ट करता है।
प्रभावित कंपोज़र (2.9.5) को PoC के दुर्भावनापूर्ण मेनिफेस्ट के विरुद्ध चलाने पर, कंपोज़र के अंदर, किसी p4/शेल कमांड के बनने से पहले, यह फेंकता है:
In PerforceDriver.php line 40:
[ErrorException]
Undefined array key "depot"
PerforceDriver::initialize() सबसे पहले $this->repoConfig['depot'] पढ़ता है, लेकिन PoC की रिपॉजिटरी प्रविष्टि केवल type और url (कोई depot कुंजी नहीं) प्रदान करती है। ड्राइवर उस बिंदु पर रुक जाता है, इसलिए URL में इंजेक्टेड ;touch <marker> पेलोड तक कभी नहीं पहुंचा जाता और कोई मार्कर नहीं बनता। नेटवर्क अलगाव कारण नहीं है — पूर्ण एग्रेस के साथ भी वही त्रुटि होती है।
इसका क्या मतलब है:
INCONCLUSIVE परिणाम PoC पेलोड का गुण है, वातावरण का नहीं।depot कुंजी (और वास्तविक रूप से full-lab प्रोफ़ाइल के तहत एक लाइव p4d एंडपॉइंट) की आवश्यकता होगी। पेलोड को उस बिंदु तक परिष्कृत करना "लैब खड़ा करने" से परे एक शोषण विकास है और जानबूझकर यहां दायरे से बाहर रखा गया है।नीचे "अपेक्षित आउटपुट" PoC का अभिप्रेत/आदर्शीकृत परिणाम है, जो संदर्भ के लिए रखा गया है; यह वर्तमान पेलोड वास्तविक ड्राइवर के विरुद्ध जो उत्पन्न करता है वह नहीं है।
एक सफल प्रदर्शन मोटे तौर पर इस तरह दिखता है (पथ और ID भिन्न होंगे):
=== CVE-2026-40176 PoC started ===
- Composer 2.9.5 version: 2.9.5
- Composer 2.9.6 version: 2.9.6
Prepared temp dir: /tmp/cve20264176_5_20260610_142233
Written malicious composer.json to /tmp/cve20264176_5_20260610_142233
Running Composer in /tmp/cve20264176_5_20260610_142233…
- Parsed Composer version: 2.9.5
- Marker /tmp/cve20264176_5_.../poc_marker_5.txt created with expected ID.
- Output shows Perforce driver activity.
- Affected run exit code: 1
Prepared temp dir: /tmp/cve20264176_6_20260610_142233
Written malicious composer.json to /tmp/cve20264176_6_20260610_142233
Running Composer in /tmp/cve20264176_6_20260610_142233…
- Parsed Composer version: 2.9.6
✘ Marker file /tmp/cve20264176_6_.../poc_marker_6.txt not found.
- Output shows Perforce driver activity.
- Fixed run exit code: 1
=== CVE-2026-40176 PoC finished ===
=== TEST RESULT: PASS (affected succeeded, fixed failed) ===
एक गैर-शून्य कंपोज़र एग्ज़िट कोड सामान्य है — composer update अंततः (नकली) पैकेज लाने में विफल रहता है। प्रमाण मार्कर फ़ाइल है, कंपोज़र की एग्ज़िट स्थिति नहीं।
| परिणाम | अर्थ |
|---|---|
| PASS (affected succeeded, fixed failed) | पुष्टि: 2.9.5 ने इंजेक्टेड कमांड निष्पादित किया, 2.9.6 ने नहीं किया। भेद्यता और इसका फिक्स दोनों पुनरुत्पादित हैं। |
| INCONCLUSIVE / FAIL | एक या अधिक जाँचें मेल नहीं खाईं। प्रति-रन ✓/✗ पंक्तियों का निरीक्षण करें: गलत बाइनरी पथ, संस्करण बेमेल, प्रभावित मार्कर गायब (वातावरण/एस्केपिंग अंतर), या ठीक किए गए रन द्वारा अप्रत्याशित रूप से मार्कर बनाना। |
अनिर्णायक परिणाम के सामान्य कारण:
PerforceDriver.php:40 पर Undefined array key "depot" के साथ रुकता है — रिपॉजिटरी कॉन्फ़िग में depot कुंजी का अभाव है, इसलिए कंपोज़र कभी p4 कमांड-निर्माण पथ तक नहीं पहुंचता। वास्तविक 2.9.5/2.9.6 के विरुद्ध PoC के वर्तमान पेलोड के साथ ऐसा ही होता है (देखें प्रजनन स्थिति).2.9.5 / 2.9.6 नहीं हैं।exec() सैंडबॉक्स्ड/अक्षम है।p4 शामिल नहीं है (ड्राइवर पथ तक नहीं पहुंचा)।CVE2026-40176/
├── CVE202640176Test.php # PoC: CVE202640176Test वर्ग + प्रवेश बिंदु
├── composer.json # आधार मेनिफेस्ट जिसे PoC रनटाइम पर पढ़ता/पुनर्स्थापित करता है
├── Dockerfile # लैब इमेज: PHP CLI + पिन किया गया कंपोज़र 2.9.5 और 2.9.6
├── docker-compose.yml # `poc` रनर (+ `full-lab` प्रोफ़ाइल के तहत वैकल्पिक `p4d`)
├── .dockerignore # बिल्ड कॉन्टेक्स्ट को ट्रिम करता है
├── README.md # यह फ़ाइल
└── .gitignore # स्थानीय एजेंट/टूलिंग स्थिति को बाहर करता है
पूरा PoC एक फ़ाइल है:
__construct() — दो बाइनरी पथ संग्रहीत करता है, एक टाइमस्टैम्प्ड रन ID मिंट करता है, मूल composer.json का स्नैपशॉट लेता है।run() — प्रीफ़्लाइट, प्रभावित रन, ठीक किया गया रन, पुनर्स्थापना और निर्णय का आयोजन करता है।prepareTempDir() — प्रति रन एक पृथक कार्यशील निर्देशिका बनाता है।writeComposerJson() — इंजेक्टेड p4:// URL के साथ दुर्भावनापूर्ण मेनिफेस्ट बनाता है।runComposer() — composer update निष्पादित करता है (आर्गुमेंट escapeshellarg() से एस्केप किए गए) और आउटपुट + एग्ज़िट कोड कैप्चर करता है।validateRun() — संस्करण, मार्कर फ़ाइल और पर्फ़ोर्स-ड्राइवर गतिविधि की जाँच करता है।preflightVersion() — दिए गए बाइनरी से --version पढ़ता है।composer.json परिणाम की परवाह किए बिना एक finally ब्लॉक में पुनर्स्थापित किया जाता है।escapeshellarg() से एस्केप करता है (ताकि PoC गलती से अपने स्वयं के exec() कॉल में इंजेक्ट न हो)। भेद्यता एक स्तर गहरी रहती है — इस बात में कि कंपोज़र स्वयं p4 कमांड कैसे बनाता है — जो बिल्कुल वही है जो पेलोड लक्षित करता है।touch/echo करते हैं, जिससे PoC को होस्ट पर साइड इफ़ेक्ट के बिना बार-बार चलाना सुरक्षित हो जाता है।exec("cd … && php …") पैटर्न और ;/&& पेलोड एक Unix-जैसे शेल को मानते हैं; Windows जैसा-है वैसा समर्थित नहीं है।mkdir रेस / अनुमतियाँ। अस्थायी निर्देशिकाएं मोड 0777 के साथ बनाई जाती हैं; यदि साझा वातावरण में चल रहे हैं तो कस लें।Composer X.Y.Z पार्स करता है; असामान्य कंपोज़र बैनर मिलान को विफल कर सकते हैं।यह रिपॉजिटरी CVE-2026-40176 को समझने और बचाव करने के लिए मौजूद है।
composer.json फ़ाइलों (जैसे, CI पाइपलाइनों में जो तृतीय-पक्ष प्रोजेक्ट स्रोत संसाधित करती हैं) पर अलगाव के बिना कभी composer install/update न चलाएं।2.9.5 / 2.9.6 PHAR लाने के लिए)2.9.6 चेंजलॉग (आधिकारिक फिक्स विवरण के लिए अपने वितरण के सुरक्षा ट्रैकर / GitHub Advisory Database देखें)लेखक: Ikarolaborda · PoC दिनांक 2026-06-10.