
शैक्षिक PoC और CVE-2021-4034 (PwnKit) का विश्लेषण जो polkit के pkexec में स्थानीय विशेषाधिकार वृद्धि भेद्यता है, और हाथों-हाथ शोषण और रक्षा अभ्यास के लिए Docker-आधारित लैब शामिल है।
🔗 मूल परियोजना: berdav/CVE-2021-4034
यह परियोजना मूल के आधार पर शैक्षिक उद्देश्यों के लिए विश्लेषण और संशोधित संस्करण है।
MIT लाइसेंस का अनुपालन | व्हाइट हैट स्कूल शैक्षिक असाइनमेंट
CVE-2021-4034 Linux policykit-1 (PolicyKit) में एक स्थानीय विशेषाधिकार वृद्धि भेद्यता है। एक सामान्य उपयोगकर्ता pkexec को बिना किसी तर्क के चलाकर प्रक्रिया मेमोरी संरचना में खामी का लाभ उठा सकता है, और इसके माध्यम से glib को उन पर्यावरण चर स्ट्रिंग्स को फिर से संदर्भित करने देता है जिन्हें मूल रूप से फ़िल्टर किया जाना चाहिए था, जिससे एक दुर्भावनापूर्ण .so फ़ाइल लोड होती है और root विशेषाधिकार प्राप्त होता है।
⚠️ केवल शैक्षिक उद्देश्य: इस कोड का उपयोग केवल संशोधित सिस्टम पर ही करें।
वास्तविक सिस्टम पर हमले के लिए उपयोग करने पर कानूनी जिम्मेदारी हो सकती है।
| आइटम | विवरण |
|---|---|
| CVE ID | CVE-2021-4034 |
| भेद्यता नाम | PwnKit |
| प्रभावित संस्करण | polkit 0.105 से पहले पैच न लागू किए गए सभी संस्करण (परीक्षण वातावरण के अनुसार: Ubuntu 20.04 पर policykit-1 0.105-26ubuntu1) |
| भेद्यता प्रकार | Local Privilege Escalation (LPE) |
| गंभीरता | Critical (CVSS 7.8) |
| पैच संस्करण | policykit-1 >= 0.105-26ubuntu1.1 |
| खोज तिथि | जून 2021 (सार्वजनिक जनवरी 2022) |
यह समझना आसान है कि यह केवल Ubuntu की समस्या है, लेकिन चूंकि pkexec में ही तर्क दोष है, इसलिए polkit का उपयोग करने वाले अधिकांश वितरण प्रभावित होते हैं। Docker परीक्षण वातावरण Ubuntu 20.04 था, इसलिए उपरोक्त तालिका में वह संस्करण भी शामिल किया गया है।
शुरू में विश्लेषण करते समय मुझे लगा कि यह "पर्यावरण चर के सत्यापन की कमी" के कारण हुई समस्या है, लेकिन स्रोत कोड और पैच कमिट को एक साथ देखने पर पता चला कि क्रम थोड़ा अलग है। वास्तविक कारण अलग है, और पर्यावरण चर की समस्या उस कारण का परिणाम है। नीचे कारण क्रम में प्रवाह दिया गया है।
pkexec PolicyKit के माध्यम से विशेषाधिकार वृद्धि का अनुरोध करने वाला SUID-root प्रोग्राम है।
# उदाहरण: root विशेषाधिकार के साथ कमांड चलाना
pkexec /bin/id
pkexec systemctl restart service
सामान्य उपयोगकर्ता इसका उपयोग प्रशासनिक विशेषाधिकारों के साथ विशिष्ट कार्य करने के लिए करता है।
argc == 0 के मामले को संभाल नहीं पाताpkexec के main() फ़ंक्शन में कमांड-लाइन तर्कों को संसाधित करने वाले भाग में, जब बिना किसी तर्क के चलाया जाता है (argc == 0) तो इसकी जाँच नहीं की जाती। यही इस भेद्यता का वास्तविक प्रारंभ बिंदु है।
argv = {"pkexec", "कमांड", NULL} → argc >= 1execve("/usr/bin/pkexec", {NULL}, env) → argc == 0जब argc 0 होता है, तो argv सूची में केवल समाप्ति के लिए NULL रह जाता है। लेकिन pkexec का आंतरिक तर्क इस स्थिति में भी मौजूद नहीं argv[1] को पढ़ने और लिखने का प्रयास करता है। समस्या यह है कि Linux जब प्रक्रिया चलाता है, तो argv ऐरे और envp (पर्यावरण चर) ऐरे को मेमोरी में एक-दूसरे के ठीक बगल में रखता है। इसलिए सीमा से बाहर argv[1] वास्तव में envp[0], यानी पहले पर्यावरण चर को इंगित करता है।
सामान्य स्थिति: argv = [ "pkexec" | NULL ]
हमले की स्थिति: argv = [ NULL ] ← argc = 0
↑
मौजूद नहीं argv[1] तक पहुँच
↓
मेमोरी में ठीक पीछे स्थित envp[0] को पढ़ा और लिखा जाता है (आउट-ऑफ-बाउंड)
यह खतरनाक क्यों है:
GCONV_PATH, LD_PRELOAD जैसे खतरनाक पर्यावरण चर को असुरक्षित मानकर हटा देता है।argc < 1 होने पर तुरंत बाहर निकलने के लिए सत्यापन तर्क जोड़कर इस भाग को ठीक करते हैं। (CWE-125 आउट-ऑफ-बाउंड रीड, CWE-787 आउट-ऑफ-बाउंड राइट)📌 संक्षेप में: पर्यावरण चर का सत्यापन न होना "हमले के काम करने की शर्त" है, और वास्तविक भेद्यता (root cause) यह है कि pkexec argc == 0 के मामले को संभाल नहीं पाता। नीचे दिया गया बिंदु 3 इस कारण का परिणाम है।
बिंदु 2 में बताए गए OOB व्यवहार के कारण, pkexec के glib आरंभीकरण प्रक्रिया के दौरान यह स्ट्रिंग बिना सत्यापन के फिर से उपयोग में आ जाती है।
// CVE-2021-4034_exploit.c
char * const env[] = {
"GCONV_PATH=.", // मूल रूप से ld.so द्वारा फ़िल्टर किया जाना चाहिए था
"CHARSET=PWNKIT", // मौजूद नहीं एन्कोडिंग
};
execve("/usr/bin/pkexec", args, env); // argv खाली है, जिससे argc=0 बनता है
समस्या:
यहाँ महत्वपूर्ण बात यह है कि glib स्वयं गलत नहीं है। जब GCONV_PATH सेट होता है, तो glib का उस पथ से कनवर्टर खोजना सामान्य व्यवहार है। समस्या यह है कि pkexec ने पहले ही सुरक्षित निष्पादन स्थिति (खतरनाक पर्यावरण चर हटा दिए गए) को तोड़ दिया है — glib बस सामान्य रूप से काम कर रहा है, लेकिन उस सामान्य व्यवहार का दुरुपयोग किया जाता है।
CHARSET पर्यावरण चर की जाँच
CHARSET=PWNKIT
gconv-modules फ़ाइल में कनवर्टर परिभाषा खोजें
module UTF-8// PWNKIT// pwnkit 1
GCONV_PATH से .so फ़ाइल लोड करें
GCONV_PATH=. → वर्तमान निर्देशिका में pwnkit.so खोजें
.so फ़ाइल का आरंभीकरण फ़ंक्शन स्वचालित रूप से चलता है
// pwnkit.c - .so फ़ाइल लोड होने पर स्वचालित रूप से चलता है
void gconv_init(void *step)
{
setuid(0); // root विशेषाधिकार प्राप्त करें
setgid(0);
execve("/bin/sh"); // root शेल चलाएँ!
}
gconv_init को "कंस्ट्रक्टर फ़ंक्शन" कहना आसान है, लेकिन सख्ती से यह C के __attribute__((constructor)) से अलग है। सटीक रूप से यह gconv मॉड्यूल इंटरफ़ेस में परिभाषित आरंभीकरण फ़ंक्शन है, और glib dlopen के साथ .so लोड करने के बाद इस फ़ंक्शन को स्पष्ट रूप से कॉल करता है।
┌─────────────────────────────────────┐
│ सामान्य उपयोगकर्ता (uid=1000) │
└─────────────────────────────────────┘
│
│ 1. argv खाली करके pkexec चलाएँ (argc=0)
│ + दुर्भावनापूर्ण पर्यावरण चर सेट करें
│ GCONV_PATH=. / CHARSET=PWNKIT
↓
┌─────────────────────────────────────┐
│ pkexec निष्पादित │
│ argc सत्यापन नहीं → OOB → स्ट्रिंग पुनर्संदर्भित │
└─────────────────────────────────────┘
│
│ 2. glib सामान्य व्यवहार के अनुसार संसाधित करता है
│ CHARSET=PWNKIT एन्कोडिंग खोजें
│ GCONV_PATH=. से कनवर्टर खोजें
↓
┌─────────────────────────────────────┐
│ pwnkit.so लोड करें │
│ (वर्तमान निर्देशिका में दुर्भावनापूर्ण .so फ़ाइल) │
└─────────────────────────────────────┘
│
│ 3. gconv आरंभीकरण फ़ंक्शन स्वचालित रूप से चलता है (root विशेषाधिकार!)
↓
┌─────────────────────────────────────┐
│ root शेल प्राप्त करें ✅ │
│ uid=0(root) gid=0(root) │
└─────────────────────────────────────┘
# 1. परियोजना प्राप्त करें
git clone https://github.com/krleejihyeong/WHS4_CVE-2021-4034.git
cd WHS4_CVE-2021-4034
# 2. नवीनतम संस्करण जाँचें
git pull origin main
# 3. बिल्ड (कैश के बिना)
docker compose build --no-cache
# 4. चलाएँ
docker compose up