
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 नोट को हटाता है जहां कंपाइलर इसका समर्थन करता है।
स्ट्रिप को binutils >= 2.40 की आवश्यकता है। क्रॉस बिल्ड लक्ष्य के objcopy को OBJCOPY= के माध्यम से पास करते हैं (जैसे OBJCOPY=aarch64-linux-gnu-objcopy); जब objcopy ऐसा नहीं कर सकता, तो बिल्ड एक नोट प्रिंट करता है और एक मान्य, बड़ा पेलोड रखता है।
यह रिपॉजिटरी दो शोषण वेरिएंट शिप करती है जो AF_ALG/splice पेज-कैश उत्परिवर्तन प्रिमिटिव साझा करते हैं लेकिन रूट निष्पादन में अलग-अलग तरीके से कैशआउट होते हैं। उनकी विश्वसनीयता प्रोफाइल समतुल्य नहीं हैं, और वास्तविक दुनिया के खतरे के मॉडल के बारे में तर्क करते समय अंतर महत्वपूर्ण है।
exploit)एक लक्ष्य setuid बाइनरी के पेज कैश को एम्बेडेड पेलोड बाइट्स के साथ उत्परिवर्तित करता है, फिर बाइनरी को exec करता है। कर्नेल बाइनरी के अछूते ऑन-डिस्क setuid बिट से रूट क्रेडेंशियल प्रदान करता है, दूषित इन-मेमोरी छवि लोड करता है, और पेलोड चलाता है।
जहां भी हमलावर किसी रूट-सेटुइड बाइनरी के लिए open(target, O_RDONLY) कर सकता है, वहां काम करता है। उन वातावरणों द्वारा कमोबेश पराजित होता है जो setuid बाइनरी को प्रतिबंधित-पढ़ने वाली निर्देशिकाओं के पीछे रखते हैं और setuid-मुक्त सिस्टम डिज़ाइन द्वारा।
exploit-passwd)/etc/passwd के पेज कैश के चार बाइट्स को उत्परिवर्तित करता है ताकि चल रहे उपयोगकर्ता के UID फ़ील्ड को "0000" पर सेट किया जा सके। /etc/passwd प्रत्येक मानक Linux सिस्टम पर विश्व-पठनीय है, इसलिए उत्परिवर्तन सार्वभौमिक है। इसे रूट निष्पादन में अनुवाद करना किसी रूट-साइड प्रक्रिया पर निर्भर करता है जो getpwnam/getpwuid के माध्यम से उपयोगकर्ता को हल करती है और बिना क्रॉस-सत्यापन के हल किए गए uid पर कार्य करती है। ऐसे कई उपभोक्ता मौजूद हैं; उनमें से कई कॉलिंग uid के कर्नेल दृश्य या ऑन-डिस्क फ़ाइल स्वामित्व के विरुद्ध रक्षात्मक रूप से क्रॉस-चेक करते हैं, जिससे कैशआउट टूट जाता है।
su के विफल होने पर पिवटिंगexploit-passwd उत्परिवर्तन के बाद su <user> को exec करता है, सबसे सरल संभव कैशआउट के रूप में। यह util-linux su के विरुद्ध काम करता है लेकिन shadow-utils su के विरुद्ध "Cannot determine your user name." के साथ विफल होता है। उस बिंदु पर पेज कैश उत्परिवर्तन अभी भी जगह पर है, और किसी अन्य कैशआउट (जैसे कि बिना क्रॉस-चेकिंग के getpwnam के माध्यम से उपयोगकर्ताओं को हल करने वाले डेमॉन का उपयोग) पर पिवट करना उस बिंदु पर संभव है। परीक्षण समाप्त होने पर दूषित पेज कैश को साफ़ करने के लिए रूट के रूप में echo 3 > /proc/sys/vm/drop_caches चलाएं।
फ़्लोर: torvalds/linux 72548b093ee3 अगस्त 2017, v4.14
(AF_ALG iov_iter पुनर्कार्य जिसने
AEAD स्कैटरलिस्ट में splice के माध्यम से
फ़ाइल-पेज लेखन प्रिमिटिव पेश किया)
सीलिंग: torvalds/linux a664bf3d603d अप्रैल 2026, मेनलाइन
(2017 के algif_aead इन-प्लेस
ऑप्टिमाइजेशन को वापस लेता है; स्रोत और
गंतव्य स्कैटरलिस्ट को अलग करता है ताकि
पेज-कैश पृष्ठ अब लिखने योग्य क्रिप्टो
गंतव्य नहीं हो सकें)
इनके बीच: प्रत्येक प्रमुख डिस्ट्रो कर्नेल जिसने फिक्स को बैकपोर्ट नहीं किया। Ubuntu, RHEL, SUSE, Amazon Linux, और Debian सभी को प्रकटीकरण के समय उनके स्टॉक क्लाउड-इमेज कर्नेल में असुरक्षित पुष्टि की गई थी। डिस्ट्रो-स्तरीय बैकपोर्ट 2026-04-29 के आसपास सार्वजनिक प्रकटीकरण के साथ शुरू हुए। यह सत्यापित करने के लिए कि लक्ष्य कर्नेल विंडो में है या नहीं, जांचें कि a664bf3d603d (या इसका डिस्ट्रो-विशिष्ट बैकपोर्ट) कर्नेल के git लॉग या डिस्ट्रो के चेंजलॉग में मौजूद है या नहीं।
भुगतान सुरक्षा समीक्षा, कस्टम पोर्टिंग कार्य, या निजी सुरक्षा सलाह के लिए, लेखक से उनकी परामर्श कंपनी, Crash United, LLC के माध्यम से संपर्क करें।
संपर्क: [email protected] · https://crashunited.com
GitHub: @tgies · X/Twitter: @me_irl
CVE-2026-31431 की खोज और मूल प्रकटीकरण: Theori / Xint. सार्वजनिक लेख: https://copy.fail/।
यह C पोर्ट: Tony Gies [email protected]
nolibc/: Linux कर्नेल ट्री से वेंडर्ड, दोहरी-लाइसेंस LGPL-2.1-or-later या MIT (nolibc/nolibc.h और व्यक्तिगत फ़ाइल SPDX हेडर देखें)।
इस रिपॉजिटरी में ड्रॉपर और पेलोड स्रोत उसी दोहरी LGPL-2.1-or-later या MIT शर्तों के तहत जारी किए गए हैं जैसे उन पर निर्भर nolibc ट्री, ताकि जो कोई भी इस पूरी निर्देशिका को अपने काम में वेंडर कर रहा है, उसके लिए लाइसेंसिंग तुच्छ रूप से संगत रहे।
शोषण और पेलोड सुरक्षा-अनुसंधान और रक्षात्मक-पहचान उद्देश्यों के लिए प्रकाशित किए गए हैं। उन सिस्टमों के विरुद्ध उपयोग जिनके आप मालिक नहीं हैं या जिनके परीक्षण करने के लिए आपके पास स्पष्ट प्राधिकरण नहीं है, आपकी समस्या है, लेखक की नहीं।
| कैशआउट | प्री-रूट सेटअप आवश्यक | टिप्पणियाँ |
|---|
| WSL2 सत्र स्पॉन | नहीं | WSL का प्रति-सत्र setuid(getpwnam(default_user)->pw_uid) कोई सत्यापन नहीं करता। साफ काम करता है। |
util-linux su | नहीं | अनुज्ञेय कॉलर-पहचान हैंडलिंग। |
shadow-utils su | हाँ | getpwuid(getuid()) कॉलर-पहचान जांच विफल होती है क्योंकि उत्परिवर्तन वास्तविक uid को अनमैप कर देता है। |
sshd (डिफ़ॉल्ट StrictModes yes) | हाँ (StrictModes अक्षम करें) | StrictModes के लिए होम निर्देशिका को रूट या pw->pw_uid के स्वामित्व में होना आवश्यक है। उत्परिवर्तन pw_uid=0 बनाता है; ऑन-डिस्क स्वामी मूल uid पर रहता है; बेमेल प्रमाणीकरण को अस्वीकार करता है। |
| MTA स्थानीय वितरण (postfix, exim, आदि) | परिवर्तनशील | MDA की होम-पर्म सत्यापन पर निर्भर करता है। प्रति MTA परीक्षण करें। |