
CVE-2026-31431 के लिए प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट, जो splice() और क्राफ्टेड सॉकेट विकल्पों के माध्यम से Linux कर्नेल में स्थानीय विशेषाधिकार वृद्धि है, जो setuid बाइनरीज़ को ओवरराइट करने के लिए मनमाना कर्नेल मेमोरी राइट सक्षम करता है।
copyFail.py एक प्रूफ-ऑफ-कॉन्सेप्ट (PoC) शोषण है जो Linux कर्नेल में स्थानीय विशेषाधिकार वृद्धि (local privilege escalation) भेद्यता को प्रदर्शित करता है। splice() सिस्टम कॉल का दुरुपयोग करके, क्राफ्ट किए गए सॉकेट विकल्पों के साथ संयोजन में, शोषण मनमाने कर्नेल मेमोरी को भ्रष्ट करने की क्षमता प्राप्त करता है। यह इस क्षमता का उपयोग डिस्क पर किसी भी setuid बाइनरी को कस्टम ELF निष्पादन योग्य के साथ अधिलेखित करने के लिए करता है, फिर उन्नत विशेषाधिकार प्राप्त करने के लिए छेड़छाड़ की गई बाइनरी को चलाता है।
हमले का प्रकार: स्थानीय विशेषाधिकार वृद्धि (LPE) प्रभाव: पूर्ण रूट शेल पहुंच (setuid-root बाइनरी को लक्षित करते समय) जटिलता: कम (एकल स्क्रिप्ट, कोई बाहरी निर्भरता नहीं)
उपयोग:
./copyFail_cleaned.py [target_binary] # डिफ़ॉल्ट: /usr/bin/su
मूल PoC में /usr/bin/su हार्डकोड किया गया था, लेकिन अंतर्निहित कर्नेल भेद्यता किसी भी फ़ाइल पर लागू होती है — हमलावर अपनी पसंद के किसी भी setuid बाइनरी को अधिलेखित कर सकता है। साफ़ किया गया संस्करण लक्ष्य निर्दिष्ट करने के लिए एक वैकल्पिक कमांड-लाइन तर्क स्वीकार करता है, जिससे यह व्यवहार स्पष्ट हो जाता है।
Linux कर्नेल एक splice() सिस्टम कॉल प्रदान करता है जो दो फ़ाइल डिस्क्रिप्टर के बीच डेटा को पूरी तरह से कर्नेल के भीतर कॉपी करता है — पहले डेटा को userspace में कॉपी किए बिना। इसे "ज़ीरो-कॉपी I/O" कहा जाता है और इसका उपयोग उच्च-थ्रूपुट अनुप्रयोगों जैसे वेब सर्वर और रिवर्स प्रॉक्सी में प्रदर्शन के लिए किया जाता है।
भेद्यता इसलिए उत्पन्न होती है क्योंकि कर्नेल PACKET सॉकेट पर splice() का उपयोग करते समय कुछ सॉकेट संरचनाओं की आंतरिक स्थिति को ठीक से मान्य नहीं करता है, जिन्हें असमर्थित प्रोटोकॉल-स्तरीय सॉकेट विकल्पों के साथ कॉन्फ़िगर किया गया है। इन विकल्पों को सावधानीपूर्वक तैयार करके, एक हमलावर कर्नेल पॉइंटर्स को भ्रष्ट कर सकता है, और फिर कर्नेल मेमोरी राइट्स को मनमाने स्थानों पर पुनर्निर्देशित करने के लिए splice() का उपयोग कर सकता है।
सरल शब्दों में: कर्नेल के पास डेटा को आंतरिक रूप से स्थानांतरित करने के लिए एक शॉर्टकट है, और यह शोषण उस शॉर्टकट को गलत जगह पर डेटा लिखने के लिए धोखा देता है — विशेष रूप से, सिस्टम बाइनरी की इन-मेमोरी कॉपी में।
शोषण चरणों के एक स्पष्ट अनुक्रम का पालन करता है:
शोषण एक रॉ PACKET सॉकेट (AF_PACKET / SOCK_RAW) बनाता है और इसे जानबूझकर दोषपूर्ण पतों से बांधता है। फिर यह SOL_PNIO (प्रोटोकॉल स्तर 279) का उपयोग करके setsockopt() को कॉल करता है, जो एक Solaris-स्तरीय स्थिरांक है जिसे Linux पहचानता नहीं है।
यह क्यों मायने रखता है: जब कर्नेल setsockopt() में एक असमर्थित प्रोटोकॉल स्तर का सामना करता है, तो यह एक सामान्य हैंडलर पर पहुंच जाता है जो डेटा को ठीक से मान्य नहीं करता है। यह कर्नेल मेमोरी को एक असंगत, शोषण योग्य स्थिति में छोड़ देता है।
accept() के माध्यम से सॉकेट कनेक्शन स्थापित करने के बाद, शोषण sendmsg() का उपयोग करके क्राफ्ट किए गए सहायक (नियंत्रण) संदेश भेजता है। इन संदेशों में जानबूझकर बेमेल लंबाई हेडर होते हैं — कुछ दावा करते हैं कि वे जितने हैं उससे छोटे हैं, अन्य दावा करते हैं कि वे जितने हैं उससे लंबे हैं।
यह क्यों मायने रखता है: कर्नेल का नियंत्रण संदेश पार्सर पॉइंटर अंकगणित के लिए इन लंबाईयों का उपयोग करता है। बेमेल लंबाई पार्सर को इच्छित सीमाओं से परे पढ़ने या लिखने का कारण बनती है, आसन्न कर्नेल संरचनाओं को भ्रष्ट करती है — विशेष रूप से, पॉइंटर्स जिन्हें splice() बाद में अनुसरण करेगा।
शोषण एक पाइप बनाता है और splice() को दो बार कॉल करता है:
/usr/bin/su से पाइप में डेटा स्प्लाइस करता है।यह क्यों मायने रखता है: splice() कॉल चरण 2 में लगाए गए भ्रष्ट कर्नेल पॉइंटर्स का अनुसरण करता है, जिससे यह सॉकेट बफर के बजाय हमलावर-चुने गए कर्नेल मेमोरी पते पर डेटा लिखता है। यह शोषण को एक मनमाना कर्नेल मेमोरी राइट प्रिमिटिव देता है।
शोषण का पेलोड एक 160-बाइट ELF निष्पादन योग्य है (नीचे देखें)। शोषण फ़ंक्शन की प्रत्येक कॉल ठीक 4 बाइट्स लिखती है। इसलिए मुख्य लूप 40 बार चलता है (160 / 4 = 40), हर बार:
सभी 40 पुनरावृत्तियों के बाद, /usr/bin/su के पहले 160 बाइट्स अधिलेखित हो चुके होते हैं।
अंत में, शोषण os.system("su") चलाता है। कर्नेल संशोधित /usr/bin/su को उसके पेज कैश से लोड करता है (जिसमें अब वास्तविक su बाइनरी के बजाय हमलावर का शेलकोड होता है), और शेलकोड निष्पादित होता है।
एम्बेडेड पेलोड एक 160-बाइट x86-64 ELF निष्पादन योग्य में डीकंप्रेस होता है जिसमें यह शेलकोड होता है:
; syscall 105 (execveat) का प्रयास करें — पुराने कर्नेल पर उपलब्ध नहीं हो सकता है
xor eax, eax
xor edi, edi
mov al, 0x69 ; syscall 105
syscall
; फ़ॉलबैक: syscall 59 (execve) — विश्वसनीय पथ
lea rdi, [rip+0xf] ; RDI = "/bin/sh" का पॉइंटर
xor esi, esi ; RSI = NULL (envp)
push 0x3b ; syscall 59 नंबर
pop eax
cdq ; RDX = NULL (argv)
syscall
; साफ़ तरीके से बाहर निकलें
xor edi, edi
push 0x3c ; syscall 60 (exit)
pop eax
syscall
; डेटा अनुभाग: "/bin/sh\0\0\0"
यह क्या करता है: बिना किसी तर्क के /bin/sh स्पॉन करता है, उस प्रक्रिया के विशेषाधिकारों को विरासत में प्राप्त करता है जिसने su चलाया था। यदि शोषण रूट के रूप में चलता है (या उन क्षमताओं के साथ जो su को रूट एक्सेस देती हैं), तो परिणामी शेल एक रूट शेल होता है।
यह क्या नहीं करता है:
यह एक सीधा एक-शॉट विशेषाधिकार वृद्धि है, जो एक शोध PoC के अनुरूप है।
copyFail.py
├── hex_to_bytes() — हेक्स स्ट्रिंग डिकोडर
├── exploit_splice() — मुख्य शोषण (सॉकेट सेटअप + भ्रष्टाचार + splice)
│ ├── चरण 1: PACKET सॉकेट बनाएं, बांधें, setsockopt (SOL_PNIO)
│ ├── चरण 2: accept() कनेक्शन
│ ├── चरण 3: क्राफ्ट किए गए सहायक संदेशों के साथ sendmsg()
│ ├── चरण 4: कर्नेल मेमोरी को भ्रष्ट करने के लिए pipe() + splice()
│ └── चरण 5: recv() प्रयास (भ्रष्टाचार को मजबूत करता है)
└── मुख्य लूप:
├── /usr/bin/su खोलें (केवल-पढ़ने के लिए)
├── एम्बेडेड पेलोड डीकंप्रेस करें (zlib → 160-बाइट ELF)
├── लूप: प्रति पुनरावृत्ति 4 बाइट्स इंजेक्ट करें (कुल 40 पुनरावृत्तियां)
└── छेड़छाड़ की गई su निष्पादित करें → रूट शेल
शोषण /usr/bin/su को O_RDONLY (केवल-पढ़ने के लिए) के साथ खोलता है। इसे लिखने की पहुंच की आवश्यकता नहीं है क्योंकि भ्रष्टाचार कर्नेल पेज कैश के माध्यम से होता है — फ़ाइल की इन-मेमोरी कॉपी जिसे कर्नेल डिस्क में परिवर्तन फ्लश करने से पहले उपयोग करता है। splice()-आधारित राइट सामान्य फ़ाइल अनुमतियों को पूरी तरह से बायपास करता है, सीधे कर्नेल मेमोरी में जाता है।
/usr/bin/su बाइनरी (पैकेज मैनेजर के विरुद्ध हैश की तुलना करें)setsockopt() कॉलsplice() syscallsAF_PACKET सॉकेट निर्माण को प्रतिबंधित करने के लिए sysctl का उपयोग करेंcopyFail.py (जैसा वितरित किया गया)copyFail_cleaned.py (समान निर्देशिका)net/packet/, fs/splice.c, net/core/sock.cयह रिपोर्ट केवल सुरक्षा अनुसंधान और रक्षात्मक विश्लेषण उद्देश्यों के लिए है।
| स्थिरांक | मान | शोषण में उद्देश्य |
|---|
AF_PACKET | 17 | रॉ पैकेट सॉकेट परिवार |
SOCK_RAW | 3 | रॉ सॉकेट प्रकार |
SOL_PNIO | 279 | असमर्थित प्रोटोकॉल स्तर (Solaris) |
MSG_DONTWAIT | 0x400 | नॉन-ब्लॉकिंग sendmsg फ़्लैग |