
Copy Fail Linux LPE (CVE-2026-31431) का क्रॉस-प्लेटफ़ॉर्म C पोर्ट। Theori / Xint द्वारा 2026-04-29 को खुलासा किया गया।
English (en) ∙ 日本語 (ja) ∙ 简体中文 (zh-cn) ∙ 한국어 (ko) ∙ Русский (ru)
Copy Fail Linux LPE (CVE-2026-31431) का एक क्रॉस-प्लेटफॉर्म C पुनःकार्यान्वयन, जिसे 2026-04-29 को Theori / Xint द्वारा प्रकट किया गया। पूर्ण भेद्यता विवरण, समयरेखा और Theori की खोज प्रक्रिया के लिए copy.fail पर विहित लेख देखें।
सार्वजनिक रूप से जारी प्रूफ-ऑफ-कॉन्सेप्ट एक 732-बाइट Python स्क्रिप्ट है। यह C पोर्ट दर्शाता है कि उसी शोषण को पोर्टेबल C के रूप में व्यक्त किया जा सकता है जो nolibc द्वारा समर्थित किसी भी आर्किटेक्चर पर संकलित हो, परियोजना के अपने स्रोत में कोई प्रति-आर्क हेक्स ब्लॉब या इनलाइन असेंबली के बिना।
इस पोर्ट के लेखक: Tony Gies [email protected]। खोज और मूल प्रकटीकरण: Theori / Xint।
copy-fail-c/
├── exploit.c the dropper (binary-mutation variant)
├── exploit-passwd.c the dropper (/etc/passwd UID-flip variant)
├── vulnerable.c non-destructive vulnerability checker
├── payload.c the body that gets dropped (setgid+setuid+execve sh)
├── utils.c, utils.h shared AF_ALG/splice page-cache mutation primitive
├── Makefile build orchestration
├── nolibc/ vendored from torvalds/linux tools/include/nolibc
└── README.md this file
make के बाद:
├── payload tiny static ELF, embedded into the dropper as bytes
├── payload.o payload wrapped as a relocatable .o by `ld -r -b binary`
├── exploit dropper, binary-mutation variant
├── exploit-passwd dropper, /etc/passwd UID-flip variant
└── vulnerable non-destructive vulnerability checker
exploit.c लक्ष्य बाइनरी को केवल-पढ़ने के लिए खोलता है, फिर एम्बेडेड पेलोड की प्रत्येक 4-बाइट विंडो के लिए AF_ALG के माध्यम से एक नकली AEAD-डिक्रिप्ट चलाता है जिसका सिफरटेक्स्ट इनपुट splice() के माध्यम से लक्ष्य के पेज-कैश पृष्ठों से आपूर्ति किया जाता है। authencesn टेम्पलेट का इन-प्लेस ऑप्टिमाइजेशन splice किए गए स्रोत पृष्ठों को सिफरटेक्स्ट इनपुट और प्लेनटेक्स्ट गंतव्य दोनों के रूप में मानता है, इसलिए (असफल) डिक्रिप्ट ने पृष्ठ-कैश पृष्ठ को तब तक अधिलेखित कर दिया है जब तक प्रमाणीकरण सत्यापन अनुरोध को अस्वीकार करता है। 4 * N पुनरावृत्तियों के बाद लक्ष्य की कैश्ड छवि को पेलोड के साथ बाइट-दर-बाइट बदल दिया गया है। लक्ष्य को execve() करने से उत्परिवर्तित पृष्ठ लोड होते हैं; डिस्क पर inode अभी भी setuid रूट है, इसलिए कर्नेल रूट क्रेडेंशियल प्रदान करता है और पेलोड चलाता है।
payload.c सादा पोर्टेबल C है: setgid(0); setuid(0); execve("/bin/sh", ...)। nolibc _start, syscall मशीनरी, और प्रति-आर्च रजिस्टर-जगलिंग प्रदान करता है।
एक दूसरा वेरिएंट, exploit-passwd.c, setuid बाइनरी की छवि के बजाय /etc/passwd के पेज कैश के चार बाइट्स को उत्परिवर्तित करता है। इसे किसी एम्बेडेड पेलोड की आवश्यकता नहीं है और उन सिस्टमों पर काम करता है जहां बाइनरी-म्यूटेशन मार्ग अवरुद्ध है, लेकिन इसकी कैशआउट सतह बहुत संकरी है।
vulnerable.c कोई शोषण नहीं है। यह एक स्थानीय testfile बनाता है जिसमें स्ट्रिंग init होती है, फिर उस फ़ाइल के अपने पेज कैश के विरुद्ध उन बाइट्स को vulnerable से अधिलेखित करने के लिए वही patch_chunk() प्रिमिटिव चलाता है। यदि पुनः-पढ़ी गई सामग्री मेल खाती है, तो चल रहा कर्नेल CVE-2026-31431 के लिए विंडो में है। डिस्क पर inode कभी संशोधित नहीं होता; testfile बाहर निकलने पर हटा दिया जाता है; पेज-कैश उत्परिवर्तन इसके साथ वाष्पित हो जाता है। अनप्रिविलेज्ड चलता है। यदि असुरक्षित है तो 100 बाहर निकलता है, यदि प्रिमिटिव चला लेकिन उत्परिवर्तन नहीं हुआ तो 0, यदि AF_ALG सॉकेट परिवार या authencesn टेम्पलेट अनुपलब्ध है तो पैच स्थिति निर्धारित नहीं की जा सकती तो 2, और अन्य रनटाइम त्रुटियों के लिए 1 बाहर निकलता है।
डिफ़ॉल्ट (होस्ट-आर्क नेटिव):
make
aarch64 (या किसी अन्य Linux आर्क जिसके लिए क्रॉस-टूलचेन स्थापित है) पर क्रॉस-संकलन:
make CC=aarch64-linux-gnu-gcc LD=aarch64-linux-gnu-ld
वेंडर्ड nolibc द्वारा समर्थित आर्किटेक्चर (प्रति अपस्ट्रीम): x86_64, i386, arm, aarch64, riscv32/64, mips, ppc, s390x, loongarch, m68k, sh, sparc। nolibc कंपाइलर के आर्क मैक्रोज़ पर डिस्पैच करता है, इसलिए सही CC/LD चुनना पर्याप्त है।
निर्माण के लिए आवश्यक:
cc, gcc, या कोई क्रॉस वेरिएंट)ld -r -b binary का समर्थन करता है (binutils ld और lld दोनों करते हैं)linux/if_alg.h और <asm/unistd.h> प्रदान करते हैं (Debian/Ubuntu: linux-libc-dev; क्रॉस वेरिएंट: आमतौर पर क्रॉस-टूलचेन पैकेज द्वारा शामिल)Linux 5.6 से पुराने हेडर सेट __kernel_old_time_t और struct __kernel_old_timespec से पहले के हैं, जिनका उपयोग वेंडर्ड nolibc करता है। compat.h (पेलोड बिल्ड में फोर्स-इन्क्लूडेड) उन्हें अनुपस्थित होने पर प्रदान करता है, इसलिए एक पुराना linux-libc-dev अभी भी बनता है। यह 5.6+ हेडर पर कोई-ऑप नहीं है।
कोई बाहरी लाइब्रेरी निर्भरता नहीं है। पेलोड nolibc के विरुद्ध फ्रीस्टैंडिंग बनाया गया है; ड्रॉपर केवल fprintf और perror के लिए होस्ट libc से लिंक होता है।
कुछ छोटी टूलचेन सुविधाएं स्रोत को पोर्टेबल और पेलोड को छोटा रखने में अधिकांश भार वहन करती हैं।
nolibc/ कर्नेल का छोटा हेडर-ओनली libc प्रतिस्थापन है, जो torvalds/linux tools/include/nolibc/ से वेंडर्ड है। यह _start, एक पोर्टेबल syscall() मैक्रो, और इनलाइन syscall रैपर प्रदान करता है, जिसमें प्रति-आर्क रजिस्टर परंपराएं nolibc/arch-*.h में एन्कोडेड हैं। पेलोड को -nostdlib -static -ffreestanding -Inolibc के साथ बनाने से एक छोटा स्टैटिक ELF उत्पन्न होता है जो glibc स्टार्टअप, TLS इनिट, या स्टैक-कैनरी प्लंबिंग को खींचे बिना सीधे कर्नेल में कॉल करता है। एक बार पैक और सेक्शन-स्ट्रिप्ड (दोनों नीचे) होने पर परिणाम: x86_64 पर ~720 बाइट्स, aarch64 पर ~1.2 KB, बनाम उसी payload.c को musl-static के विरुद्ध लिंक करने पर ~17 KB या glibc-static के विरुद्ध ~700 KB।
ld -r -b binaryMakefile निर्मित payload ELF को ld -r -b binary -o payload.o payload के माध्यम से payload.o में बदल देता है। लिंकर इनपुट बाइट्स को एक रीलोकेटेबल ऑब्जेक्ट फ़ाइल के डेटा सेक्शन के रूप में शब्दशः उत्सर्जित करता है और इनपुट फ़ाइल नाम से तीन प्रतीकों को संश्लेषित करता है:
_binary_payload_start पहले पेलोड बाइट का पता
_binary_payload_end अंतिम पेलोड बाइट से एक पता आगे
_binary_payload_size निरपेक्ष प्रतीक जिसका मान बाइट्स में आकार है
exploit.c पहले दो को extern const unsigned char[] के रूप में घोषित करता है और आकार की गणना _binary_payload_end - _binary_payload_start के रूप में करता है।
-Wl,-N प्लस टाइट max-page-sizeपेलोड को -Wl,-N -Wl,-z,max-page-size=0x10 के साथ स्टैटिक रूप से लिंक किया गया है, जो .text/.rodata/.data को कर्नेल-पेज-एलाइंड 4 KB-प्रति-सेगमेंट डिफ़ॉल्ट के बजाय 16-बाइट फ़ाइल-एलाइनमेंट के साथ एक एकल LOAD सेगमेंट में समेट देता है। यह ld से "RWX permissions" चेतावनी उत्पन्न करता है, जो केवल सूचनात्मक है - पेलोड का रनटाइम मेमोरी सुरक्षा इसके एकल-उद्देश्य प्रोग्राम के लिए मायने नहीं रखता। इस ध्वज के बिना, वही कोड x86_64 पर ~13 KB से लिंक होता है (अधिकतर अंतर-सेगमेंट शून्य पैडिंग); इसके साथ, नीचे सेक्शन-हेडर स्ट्रिप से पहले ~1.3 KB।
लिंकिंग के बाद, objcopy --strip-section-headers पेलोड के सेक्शन हेडर टेबल और .shstrtab को हटा देता है। कर्नेल ELF लोडर एक प्रोग्राम को केवल इसके प्रोग्राम हेडर से मैप करता है, इसलिए वे बाइट्स रनटाइम पर कभी लोड नहीं होते, और क्योंकि payload शब्दशः एम्बेडेड है, वे ड्रॉप और patch_chunk पुनरावृत्ति गणना को भी बढ़ाते हैं। उन्हें स्ट्रिप करने से x86_64 पेलोड ~1.3 KB से 720 बाइट्स (322 चार-बाइट पुनरावृत्तियों से घटकर 180) हो जाता है। दो लिंक-टाइम ध्वज बाकी को कम करते हैं: -Wl,--build-id=none बिल्ड-आईडी नोट को हटाता है, और -fcf-protection=none x86 CET नोट को हटाता है जहां कंपाइलर इसका समर्थन करता है।