
CVE-2023-0386 के लिए स्थानीय विशेषाधिकार वृद्धि शोषण जो Linux कर्नेल overlayfs को लक्षित करता है। इसमें विस्तृत भेद्यता विश्लेषण, PoC कोड, और FUSE तथा user namespaces का उपयोग करके चरण-दर-चरण शोषण मार्गदर्शिका शामिल है।
gcc -Wall exp.c `pkg-config fuse --cflags --libs` -o exp
./exp /tmp

इस लेख का सैद्धांतिक ज्ञान (नेमस्पेस, ओवरले फ़ाइल सिस्टम, FUSE फ़ाइल सिस्टम, आदि) chatGPT से लिया गया है।
भेद्यता संख्या: CVE-2023-0386
प्रभावित उत्पाद: linux kernel - ओवरले फ़ाइल सिस्टम
प्रभावित संस्करण: 5.11 ~ 5.19
शोषण की शर्तें: unshar कर सकते हैं या ओवरले फ़ाइल सिस्टम बना सकते हैं
शोषण का प्रभाव: स्थानीय विशेषाधिकार वृद्धि (local privilege escalation)
स्वयं कर्नेल संकलित करें:
भेद्यता संस्करण सीमा के अंतर्गत, 5.15 को छोड़कर (5.15 में संभवतः समस्या है), overlay और FUSE दोनों फ़ाइल सिस्टम सक्षम करें:
CONFIG_SLUB_DEBUGOVERLAY_FS
CONFIG_FUSE_FS
Ubuntu 21.10 (कर्नेल संस्करण 5.13.0-16-generic) पर व्यावहारिक परीक्षण सफल रहा:

भेद्यता विश्लेषण से पहले, आइए chatGPT को Linux कर्नेल विशेषज्ञ की भूमिका दें:
(chatGPT से पूछें: अब आप एक Linux कर्नेल विशेषज्ञ की भूमिका निभाएं और मेरे कुछ प्रश्नों को हल करने में मदद करें)
इस भेद्यता के बारे में सार्वजनिक जानकारी कम है; सबसे सीधी जानकारी इसका पैच है। पैच लिंक निम्नलिखित है:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4f11ada10d0a

देखा जा सकता है कि ovl_copy_up_one फ़ंक्शन में एक जाँच जोड़ी गई है। पहले chatGPT से पूछते हैं कि यह फ़ंक्शन क्या करता है:

तो यह फ़ंक्शन ओवरले फ़ाइल सिस्टम में निचली परत की फ़ाइल को ऊपरी परत में कॉपी करने की क्रिया के दौरान काम करता है। अब संदर्भ के साथ इस पैच द्वारा जोड़ी गई जाँच को देखते हैं:
static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
int flags)
{
int err;
DEFINE_DELAYED_CALL(done);
struct path parentpath;
struct ovl_copy_up_ctx ctx = {
.parent = parent,
.dentry = dentry,
.workdir = ovl_workdir(dentry),
};
if (WARN_ON(!ctx.workdir))
return -EROFS;
ovl_path_lower(dentry, &ctx.lowerpath);
err = vfs_getattr(&ctx.lowerpath, &ctx.stat,//[1] 获取底层文件系统的stat
STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT);
if (err)
return err;
//[2]补丁新加判断文件的stat属性中的用户id和用户组id是否在当前命名空间有映射
if (!kuid_has_mapping(current_user_ns(), ctx.stat.uid) ||
!kgid_has_mapping(current_user_ns(), ctx.stat.gid))
return -EOVERFLOW;
[1] पहले, vfs_getattr फ़ंक्शन के माध्यम से निचले फ़ाइल सिस्टम में लक्ष्य फ़ाइल की विशेषताएँ प्राप्त की जाती हैं। vfs_getattr फ़ंक्शन किसी फ़ाइल का struct path संरचना पास करके उस फ़ाइल के अनुरूप struct stat संरचना प्राप्त करता है।
[1.1] ctx.lowerpath ओवरले फ़ाइल सिस्टम में निचले फ़ाइल सिस्टम के किसी फ़ाइल का पथ है। ओवरले फ़ाइल सिस्टम का परिचय आगे दिया जाएगा।
[1.2] struct stat संरचना फ़ाइल की मेटाडेटा जानकारी संग्रहीत करती है, जिसमें फ़ाइल का स्वामी और समूह शामिल होते हैं। प्राप्त स्वामी जानकारी की जाँच नीचे पैच में जोड़ी गई शर्त में की जाती है।
[2] फिर kuid_has_mapping फ़ंक्शन को कॉल करके ऊपर प्राप्त फ़ाइल के स्वामी और समूह की जानकारी की जाँच की जाती है। यह जाँचा जाता है कि लक्ष्य फ़ाइल का स्वामी और समूह वर्तमान यूज़र नेमस्पेस में मैप है या नहीं।
[2.1] kuid_has_mapping फ़ंक्शन में दो पैरामीटर होते हैं: एक struct user_namespace यूज़र नेमस्पेस संरचना और एक struct kuid कर्नेल यूज़र संरचना। यह फ़ंक्शन जाँचता है कि दिया गया उपयोगकर्ता दिए गए यूज़र नेमस्पेस में मैप है या नहीं। नेमस्पेस में उपयोगकर्ता मैपिंग की विस्तृत जानकारी आगे दी जाएगी।
इसलिए हम जानते हैं कि जब इस भेद्यता-युक्त फ़ंक्शन (ovl_copy_up_one) पर कार्रवाई होती है, यदि लक्ष्य निचली परत की फ़ाइल का स्वामी उपयोगकर्ता या समूह वर्तमान नेमस्पेस में मैप नहीं है, तो यह विफल हो जाएगा।
अब पैच का सिद्धांत स्पष्ट हो गया है, लेकिन फिर भी इस भेद्यता को रिप्रोड्यूस करने के लिए हमें निम्नलिखित प्रश्नों को हल करना होगा:
ovl_copy_up_one वाली लॉजिक को कैसे ट्रिगर किया जाए, यानी ओवरले फ़ाइल सिस्टम में निचली परत की फ़ाइल को ऊपरी परत में कॉपी करना?lowerpath उपर्युक्त लॉजिक श्रृंखला में वास्तव में क्या भूमिका निभाता है?इन दो प्रश्नों को हल करने से पहले, हमें कुछ बुनियादी अवधारणाओं को समझना होगा:
(chatGPT से पूछें: कृपया Linux कर्नेल में नेमस्पेस के बारे में बताएं)
Linux में, नेमस्पेस (namespaces) एक कर्नेल सुविधा है जिसका उपयोग संसाधन अलगाव (resource isolation) के लिए किया जाता है। नेमस्पेस के माध्यम से प्रक्रियाओं का एक समूह ऐसा प्रतीत होता है जैसे वे स्वतंत्र सिस्टम वातावरण में चल रही हों, जिससे सिस्टम की सुरक्षा और प्रबंधनीयता बढ़ती है। नेमस्पेस कंटेनर तकनीक (जैसे Docker) में महत्वपूर्ण भूमिका निभाते हैं, जिससे कंटेनर अलग-थलग वातावरण में चल सकते हैं और अन्य कंटेनर या मुख्य सिस्टम को प्रभावित नहीं करते।
Linux कर्नेल 7 प्रकार के नेमस्पेस का समर्थन करता है (mount, pid, net, ipc, user, time, cgroup); प्रत्येक नेमस्पेस एक विशेष प्रकार के सिस्टम संसाधन को अलग करता है। नेमस्पेस को सिस्टम कॉल (जैसे clone, unshare और setns) के माध्यम से बनाया, संशोधित और प्रबंधित किया जाता है। कंटेनर रनटाइम (जैसे Docker) और अन्य वर्चुअलाइज़ेशन उपकरण इन नेमस्पेस सुविधाओं का उपयोग करके कंटेनरों के लिए स्वतंत्र, अलग-थलग निष्पादन वातावरण प्रदान करते हैं।
इनमें से, भेद्यता पैच द्वारा जोड़ा गया जाँच फ़ंक्शन kuid_has_mapping उपर्युक्त 7 नेमस्पेस में से यूज़र नेमस्पेस (user namespace) से संबंधित है।
(chatGPT से पूछें: कृपया इनमें से यूज़र नेमस्पेस के बारे में बताएं)
यूज़र नेमस्पेस (User Namespace) का उपयोग उपयोगकर्ता ID (UID) और समूह ID (GID) को अलग करने के लिए किया जाता है। इसके माध्यम से विभिन्न नेमस्पेस में उपयोगकर्ता और समूह ID के स्वतंत्र सेट उपयोग किए जा सकते हैं। इसका मतलब है कि एक यूज़र नेमस्पेस में उपयोगकर्ता और समूह का किसी अन्य नेमस्पेस में अलग ID या अनुमतियाँ हो सकती हैं। यूज़र नेमस्पेस सिस्टम की सुरक्षा और प्रबंधनीयता बढ़ा सकता है, विशेष रूप से कंटेनरीकृत वातावरण में।
यूज़र नेमस्पेस की प्रमुख विशेषता ID मैपिंग है: यूज़र नेमस्पेस एक नेमस्पेस के UID और GID को दूसरे नेमस्पेस के UID और GID में मैप करने की अनुमति देता है। इसका अर्थ है कि विभिन्न यूज़र नेमस्पेस में समान UID और GID अलग-अलग उपयोगकर्ताओं और समूहों का प्रतिनिधित्व कर सकते हैं। उदाहरण के लिए, कंटेनर में root उपयोगकर्ता (UID 0) को मुख्य सिस्टम में एक गैर-विशेषाधिकार प्राप्त उपयोगकर्ता के रूप में मैप किया जा सकता है।
हमें बस निम्नलिखित बिंदुओं को याद रखने की आवश्यकता है:
/proc/[pid]/uid_map; /proc/[pid]/gid_map संशोधित करके)। इस कार्रवाई के लिए आमतौर पर प्रारंभिक नेमस्पेस में root विशेषाधिकार की आवश्यकता होती है।उदाहरण के लिए, मैं breeze उपयोगकर्ता के साथ एक नया यूज़र नेमस्पेस बनाता हूँ, फिर उस नेमस्पेस में root स्वामित्व वाली फ़ाइल देखने पर समूह nobody दिखाई देता है:

ऐसा इसलिए है क्योंकि नए नेमस्पेस में, root उपयोगकर्ता वही breeze उपयोगकर्ता है जिसने नेमस्पेस बनाया है, जबकि प्रारंभिक नेमस्पेस के root को मैंने नए नेमस्पेस में मैन्युअल रूप से मैप नहीं किया है, इसलिए इसे नए नेमस्पेस में nobody के रूप में पहचाना जाता है।