Skip to content
KitploitKITPLOIT
उपकरणब्लॉग
जमा करें
उपकरणब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
StackRot — CVE-2023-3269: लिनक्स कर्नेल विशेषाधिकार वृद्धि भेद्यता | Kitploit
उपकरण/GitHubGitHub/lrh2000/stackrot
विशेषाधिकार वृद्धिभेद्यता विश्लेषणशोषणCTFबाइनरी शोषण
GitHublrh2000/stackrot

StackRot

CVE-2023-3269: लिनक्स कर्नेल विशेषाधिकार वृद्धि भेद्यता

रिपॉजिटरी देखें
499375 महीने पहलेKitploit द्वारा समीक्षित

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें

StackRot (CVE-2023-3269): Linux कर्नेल विशेषाधिकार वृद्धि भेद्यता

GitHub CI (GitHub-CI-सत्यापित शोषण)

डेमो

Linux कर्नेल 6.1 में स्टैक विस्तार के प्रबंधन में एक दोष पाया गया से 6.4 तक, जिसे "Stack Rot" कहा जाता है। वर्चुअल मेमोरी क्षेत्रों के प्रबंधन के लिए जिम्मेदार maple tree, MM राइट लॉक को ठीक से प्राप्त किए बिना नोड प्रतिस्थापन से गुजर सकती है, जिससे use-after-free समस्याएँ उत्पन्न होती हैं। एक अविशेषाधिकार प्राप्त स्थानीय उपयोगकर्ता इस दोष का उपयोग करके कर्नेल से समझौता कर सकता है और अपने विशेषाधिकार बढ़ा सकता है।

चूंकि StackRot मेमोरी प्रबंधन सबसिस्टम में पाई जाने वाली Linux कर्नेल भेद्यता है, यह लगभग सभी कर्नेल कॉन्फ़िगरेशन को प्रभावित करती है और न्यूनतम क्षमताओं की आवश्यकता होती है। हालाँकि, यह ध्यान दिया जाना चाहिए कि maple नोड्स RCU कॉलबैक का उपयोग करके मुक्त किए जाते हैं, जिससे वास्तविक मेमोरी डीलोकेशन RCU ग्रेस अवधि के बाद तक विलंबित होती है। परिणामस्वरूप, इस भेद्यता का शोषण करना चुनौतीपूर्ण माना जाता है।

मेरी जानकारी के अनुसार, वर्तमान में कोई सार्वजनिक रूप से उपलब्ध शोषण नहीं हैं जो use-after-free-by-RCU (UAFBR) बग्स को लक्षित करते हैं। यह पहला उदाहरण है जहाँ UAFBR बग्स शोषण योग्य साबित हुए हैं, यहाँ तक कि CONFIG_PREEMPT या CONFIG_SLAB_MERGE_DEFAULT सेटिंग्स की उपस्थिति के बिना भी। विशेष रूप से, यह शोषण Google kCTF VRP द्वारा प्रदान किए गए वातावरण में सफलतापूर्वक प्रदर्शित किया गया है (bzImage_upstream_6.1.25, config).

StackRot भेद्यता Linux कर्नेल में संस्करण 6.1 से मौजूद है, जब VMA ट्री संरचना बदल दी गई red-black trees से maple trees में।

पृष्ठभूमि

जब भी किसी मेमोरी मैपिंग को स्थापित करने के लिए mmap() सिस्टम कॉल का उपयोग किया जाता है, कर्नेल उस वर्चुअल मेमोरी क्षेत्र (VMA) को दर्शाने के लिए vm_area_struct नामक एक संरचना उत्पन्न करता है। यह संरचना विभिन्न जानकारी संग्रहीत करती है, जिसमें फ़्लैग, गुण और अन्य प्रासंगिक विवरण शामिल हैं, जो मैपिंग से संबंधित हैं।```c struct vm_area_struct { long unsigned int vm_start; /* 0 8 / long unsigned int vm_end; / 8 8 / struct mm_struct * vm_mm; / 16 8 / pgprot_t vm_page_prot; / 24 8 / long unsigned int vm_flags; / 32 8 / union { struct { struct rb_node rb attribute((aligned(8))); / 40 24 / / --- cacheline 1 boundary (64 bytes) --- / long unsigned int rb_subtree_last; / 64 8 / } attribute((aligned(8))) shared attribute((aligned(8))); / 40 32 / struct anon_vma_name * anon_name; / 40 8 / } attribute((aligned(8))); / 40 32 / / --- cacheline 1 boundary (64 bytes) was 8 bytes ago --- / struct list_head anon_vma_chain; / 72 16 / struct anon_vma * anon_vma; / 88 8 / const struct vm_operations_struct * vm_ops; / 96 8 / long unsigned int vm_pgoff; / 104 8 / struct file * vm_file; / 112 8 / void * vm_private_data; / 120 8 / / --- cacheline 2 boundary (128 bytes) --- / atomic_long_t swap_readahead_info; / 128 8 / struct vm_userfaultfd_ctx vm_userfaultfd_ctx; / 136 0 */

root@kitploit:~
    /* size: 136, cachelines: 3, members: 14 */
    /* forced alignments: 1 */
    /* last cacheline: 8 bytes */

} attribute((aligned(8)));

root@kitploit:~
इसके बाद, जब कर्नेल को पेज फॉल्ट या अन्य मेमोरी-संबंधित सिस्टम कॉल का सामना करना पड़ता है, तो उसे केवल एड्रेस के आधार पर VMA की त्वरित खोज की आवश्यकता होती है। पहले, VMAs को red-black trees का उपयोग करके प्रबंधित किया जाता था। हालाँकि, Linux kernel संस्करण 6.1 से, maple trees में स्थानांतरण हुआ। [Maple trees][mt] RCU-safe B-tree डेटा संरचनाएँ हैं जो गैर-अतिव्यापी रेंजों को संग्रहीत करने के लिए अनुकूलित हैं। फिर भी, उनकी जटिल प्रकृति कोडबेस में जटिलता जोड़ती है और StackRot भेद्यता को प्रस्तुत करती है।

 [mt]: https://docs.kernel.org/6.4/core-api/maple_tree.html

मूल रूप से, एक maple tree maple nodes से बनी होती है। हालाँकि पेड़ की संरचना जटिल हो सकती है, यह ध्यान रखना महत्वपूर्ण है कि यह जटिलता StackRot बग से कोई संबंध नहीं रखती है। इसलिए, इस लेख में यह मान लिया गया है कि maple tree केवल एक node, यानी root node, से बनी है।

यह root node 16 तक intervals धारण कर सकता है। ये intervals या तो एक gap का प्रतिनिधित्व कर सकते हैं या किसी VMA की ओर इंगित कर सकते हैं। चूँकि gaps भी intervals के रूप में गिने जाते हैं, सभी intervals क्रमिक रूप से जुड़े होते हैं, जिसके परिणामस्वरूप node की संरचना में केवल 15 endpoints, जिन्हें pivots भी कहा जाता है, की आवश्यकता होती है। ध्यान दें कि सबसे बाएँ endpoint और सबसे दाएँ endpoint को छोड़ दिया गया है, क्योंकि उन्हें parent node से प्राप्त किया जा सकता है।```c
struct maple_range_64 {
        struct maple_pnode *       parent;               /*     0     8 */
        long unsigned int          pivot[15];            /*     8   120 */
        /* --- cacheline 2 boundary (128 bytes) --- */
        union {
                void *             slot[16];             /*   128   128 */
                struct {
                        void *     pad[15];              /*   128   120 */
                        /* --- cacheline 3 boundary (192 bytes) was 56 bytes ago --- */
                        struct maple_metadata meta;      /*   248     2 */
                };                                       /*   128   128 */
        };                                               /*   128   128 */

        /* size: 256, cachelines: 4, members: 3 */
};

maple_range_64 संरचना, जैसा कि ऊपर दिखाया गया है, एक maple नोड का प्रतिनिधित्व करती है। pivots के अलावा, slots का उपयोग VMA संरचना को संदर्भित करने के लिए किया जाता है जब नोड leaf नोड के रूप में कार्य करता है, या अन्य maple नोड्स को संदर्भित करने के लिए जब नोड interior नोड के रूप में कार्य करता है। यदि कोई अंतराल एक gap के अनुरूप है, तो slot में केवल NULL मान होगा। pivot बिंदुओं और slots की व्यवस्था को नीचे चित्रित अनुसार देखा जा सकता है:``` Slots -> | 0 | 1 | 2 | ... | 12 | 13 | 14 | 15 | ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ │ │ │ │ │ │ │ │ └─ Implied maximum │ │ │ │ │ │ │ └─ Pivot 14 │ │ │ │ │ │ └─ Pivot 13 │ │ │ │ │ └─ Pivot 12 │ │ │ │ └─ Pivot 11 │ │ │ └─ Pivot 2 │ │ └─ Pivot 1 │ └─ Pivot 0 └─ Implied minimum

root@kitploit:~
समवर्ती संशोधन के संबंध में, maple tree एक विशेष प्रतिबंध लागू करता है
अर्थात् लेखकों को एक अनन्य लॉक धारण करना चाहिए (*Rule W*)। VMA tree के
मामले में, अनन्य लॉक MM write lock के अनुरूप होता है। पाठकों के लिए,
दो विकल्प उपलब्ध हैं। पहला विकल्प MM read lock धारण करना है
(*Rule A1*), जिसके परिणामस्वरूप लेखक MM read-write lock द्वारा अवरुद्ध
हो जाता है। वैकल्पिक रूप से, दूसरा विकल्प RCU क्रांतिक खंड में प्रवेश
करना है (*Rule A2*)। ऐसा करने से, लेखक अवरुद्ध नहीं होता, और पाठक
अपने कार्य जारी रख सकते हैं क्योंकि maple tree RCU-safe है। जबकि
अधिकांश मौजूदा VMA एक्सेस पहले विकल्प (अर्थात, Rule A1) को चुनते हैं,
Rule A2 कुछ प्रदर्शन-महत्वपूर्ण परिदृश्यों में उपयोग किया जाता है, जैसे lockless page faults.

हालाँकि, एक अतिरिक्त पहलू है जिस पर विशेष ध्यान देने की आवश्यकता है,
जो स्टैक विस्तार से संबंधित है। स्टैक एक मेमोरी क्षेत्र को दर्शाता है जो
MAP_GROWSDOWN फ्लैग के साथ मैप किया जाता है, जो क्षेत्र के नीचे के पते तक
पहुँचने पर स्वचालित विस्तार का संकेत देता है। ऐसे मामलों में, संबंधित VMA का
प्रारंभिक पता समायोजित किया जाता है, साथ ही maple tree के भीतर संबद्ध अंतराल
भी। उल्लेखनीय रूप से, ये समायोजन MM write lock धारण किए
बिना किए जाते हैं।```c
static inline
void do_user_addr_fault(struct pt_regs *regs,
                        unsigned long error_code,
                        unsigned long address)
{
	// ...

	if (unlikely(!mmap_read_trylock(mm))) {
		// ...
	}
	// ...
	if (unlikely(expand_stack(vma, address))) {
		// ...
	}

	// ...
}

आम तौर पर, स्टैक VMA और उसके पड़ोसी VMA के बीच एक अंतर होता है, क्योंकि कर्नेल एक स्टैक गार्ड लागू करता है। इस परिदृश्य में, स्टैक का विस्तार करते समय, केवल मेपल नोड (maple node) में पिवट मान को अद्यतन करने की आवश्यकता होती है, यह प्रक्रिया परमाणु रूप से (atomically) की जा सकती है। हालाँकि, यदि पड़ोसी VMA में भी MAP_GROWSDOWN फ्लैग हो, तो कोई स्टैक गार्ड लागू नहीं किया जाता है।```c int expand_downwards(struct vm_area_struct *vma, unsigned long address) { // ...

root@kitploit:~
if (prev) {
	if (!(prev->vm_flags & VM_GROWSDOWN) &&
	    vma_is_accessible(prev) &&
	    (address - prev->vm_end < stack_guard_gap))
		return -ENOMEM;
}

// ...

}

root@kitploit:~
परिणामस्वरूप, स्टैक विस्तार गैप को समाप्त कर सकता है। ऐसी स्थितियों में,
मेपल नोड के भीतर गैप अंतराल को हटाया जाना चाहिए। चूंकि मेपल ट्री
RCU-सुरक्षित है, नोड को इन-प्लेस ओवरराइट करना संभव नहीं है। इसके बजाय, एक नया नोड
बनाया जाता है, जो नोड प्रतिस्थापन को ट्रिगर करता है, और पुराने नोड को बाद में
RCU कॉलबैक का उपयोग करके नष्ट कर दिया जाता है।```c
static inline void mas_wr_modify(struct ma_wr_state *wr_mas)
{
	// ...

	if ((wr_mas->offset_end - mas->offset <= 1) &&
	    mas_wr_slot_store(wr_mas))           // <-- in-place update
		return;
	else if (mas_wr_node_store(wr_mas))      // <-- node replacement
		return;

	// ...
}

RCU कॉलबैक केवल सभी पूर्व-मौजूद RCU क्रिटिकल सेक्शन समाप्त होने के बाद ही लागू किया जाता है। हालाँकि, समस्या VMA को एक्सेस करते समय उत्पन्न होती है, क्योंकि केवल MM रीड लॉक धारण किया जाता है, और यह RCU क्रिटिकल सेक्शन में प्रवेश नहीं करता (नियम A1 के अनुसार)। परिणामस्वरूप, सैद्धांतिक रूप से, कॉलबैक किसी भी समय लागू किया जा सकता है, जिसके परिणामस्वरूप पुराना maple node मुक्त हो जाता है। हालाँकि, पुराने नोड के पॉइंटर्स पहले ही प्राप्त किए जा चुके हो सकते हैं, जिससे उस तक बाद में पहुँचने का प्रयास करने पर use-after-free बग उत्पन्न होता है।

जिस बैकट्रेस में use-after-free (UAF) होता है वह नीचे दिखाया गया है:```

  • CPU 0 - - CPU 1 -

mm_read_lock() mm_read_lock() expand_stack() find_vma_prev() expand_downwards() mas_walk() mas_store_prealloc() mas_state_walk() mas_wr_story_entry() mas_start() mas_wr_modify() mas_root() mas_wr_node_store() node = rcu_dereference_check() mas_replace() [ The node pointer is recorded ] mas_free() ma_free_rcu() call_rcu(&mt_free_rcu) [ The node is dead ] mm_read_unlock()

[ Wait for the next RCU grace period.. ] rcu_do_batch() mas_prev() mt_free_rcu() mas_prev_entry() kmem_cache_free() mas_prev_nentry() [ The node is freed ] mas_slot() mt_slot() rcu_dereference_check(node->..) [ UAF occurs here ] mm_read_unlock()

root@kitploit:~
## फिक्स

मैंने 15 जून को लिनक्स कर्नेल सुरक्षा टीम को इस कमजोरी की सूचना दी।
इसके बाद, इस बग को संबोधित करने की प्रक्रिया का नेतृत्व लिनस टोरवाल्ड्स ने किया।
इसकी जटिलता को देखते हुए, पैचों का एक सेट विकसित करने में लगभग दो सप्ताह लगे जिस पर
आम सहमति बनी।

28 जून को, लिनक्स कर्नेल 6.5 की मर्ज विंडो के दौरान, फिक्स को
लिनस के ट्री में मर्ज किया गया। लिनस ने तकनीकी दृष्टिकोण से
पैच श्रृंखला को स्पष्ट करने के लिए एक [व्यापक मर्ज संदेश][fix] प्रदान किया।

 [fix]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9471f1f2f50282b9e8f59198ec6bb738b4ccc009

इन पैचों को बाद में स्थिर कर्नेल ([6.1.37][6.1],
[6.3.11][6.3], और [6.4.1][6.4]) में बैकपोर्ट किया गया, जिससे 1 जुलाई को
"स्टैक रॉट" बग प्रभावी रूप से हल हो गया।

 [6.1]: https://lore.kernel.org/stable/2023070133-create-stainless-9a8c@gregkh/T/
 [6.3]: https://lore.kernel.org/stable/2023070146-endearing-bounding-d21a@gregkh/T/
 [6.4]: https://lore.kernel.org/stable/2023070140-eldercare-landlord-133c@gregkh/T/

## एक्सप्लॉइट

एक्सप्लॉइट मुख्य रूप से Google kCTF चैलेंज पर केंद्रित है, विशेष रूप से जब
न तो CONFIG_PREEMPT और न ही CONFIG_SLAB_MERGE_DEFAULT सेट हो। StackRot
का शोषण करने के लिए, सबसे महत्वपूर्ण कार्य एक VMA इटरेशन खोजना है जो निम्नलिखित
मानदंडों को पूरा करता है:
 1. इटरेशन के समय को नियंत्रित किया जा सकता है। यह नियंत्रण हमें यह सुनिश्चित करने
    की अनुमति देता है कि RCU ग्रेस पीरियड VMA इटरेशन के दौरान समाप्त हो जाए।
 2. इटरेशन VMA संरचना से विशिष्ट जानकारी प्राप्त करता है, और
    उस जानकारी को यूज़रस्पेस में लौटाता है। यह सुविधा हमें मेपल नोड की
    UAF कमजोरी का शोषण करके कुछ कर्नेल पते लीक करने में सक्षम बनाती है।
 3. इटरेशन VMA संरचना में कुछ फ़ंक्शन पॉइंटर्स को लागू करता है। यह
    विशेष क्षमता हमें मेपल नोड के UAF का शोषण करके
    कर्नेल-मोड प्रोग्राम काउंटर (PC) को नियंत्रित करने की अनुमति देती है।

चुना गया VMA इटरेशन वह इटरेशन है जो `/proc/[pid]/maps` की
सामग्री उत्पन्न करने के लिए जिम्मेदार है। निम्नलिखित अनुभाग दिखाएंगे कि यह
इटरेशन उपरोक्त मानदंडों को कैसे संतुष्ट करता है।

### चरण 0: UAFBR से UAF तक

किसी भी VMA इटरेशन के दौरान, VMA ट्री के रूट नोड का संदर्भ
प्राप्त किया जाता है, और इटरेशन इसके स्लॉट्स के माध्यम से आगे बढ़ता है। इस प्रकार, VMA इटरेशन के दौरान किसी अन्य थ्रेड में एक अलग CPU पर स्टैक विस्तार को ट्रिगर करके,
नोड प्रतिस्थापन को समवर्ती रूप से शुरू किया जा सकता है। इस बिंदु पर, पुराने
नोड तक पहुँचना use-after-free-by-RCU (UAFBR) स्थिति माना जाता है। हालाँकि,
वास्तविक समस्याएँ तभी उत्पन्न होती हैं जब पुराना नोड वास्तव में मुक्त हो जाता है, जो
RCU कॉलबैक में होता है।

यह दो चुनौतियाँ प्रस्तुत करता है: (i) यह निर्धारित करना कि पुराना नोड कब मुक्त होता है और
(ii) यह सुनिश्चित करना कि पुराना नोड मुक्त होने से पहले VMA इटरेशन पूरा न हो।

पहला प्रश्न अपेक्षाकृत सीधा है। कर्नेल में,
`synchronize_rcu()` फ़ंक्शन का उपयोग RCU ग्रेस पीरियड समाप्त होने तक प्रतीक्षा करने के लिए किया जा सकता है, यह सुनिश्चित करते हुए कि सभी पहले से मौजूद RCU कॉलबैक लागू किए गए हैं। में
यूज़रस्पेस, सिस्टम कॉल जो अंततः `synchronize_rcu()` को कॉल करते हैं, उसी उद्देश्य के लिए उपयोग किए जा सकते हैं। इस प्रकार, जब ऐसे सिस्टम कॉल समाप्त होते हैं, तो यह
ज्ञात होता है कि पुराना नोड मुक्त हो गया है। उल्लेखनीय रूप से, एक सिस्टम कॉल है,
`membarrier(MEMBARRIER_CMD_GLOBAL, 0, -1)`, जो केवल
`synchronize_rcu()` को लागू करता है।```c
SYSCALL_DEFINE3(membarrier, int, cmd, unsigned int, flags, int, cpu_id)
{
	// ...

	switch (cmd) {
	// ...
	case MEMBARRIER_CMD_GLOBAL:
		/* MEMBARRIER_CMD_GLOBAL is not compatible with nohz_full. */
		if (tick_nohz_full_enabled())
			return -EINVAL;
		if (num_online_cpus() > 1)
			synchronize_rcu();
		return 0;
	// ...
	}
}

दूसरे प्रश्न पर और विचार करने की आवश्यकता है। कुछ संभावित समाधान निम्नलिखित हैं:

  1. इटरेशन कार्य प्रीएम्प्ट हो जाता है, RCU ग्रेस पीरियड समाप्त हो जाता है, और इटरेशन निष्पादन फिर से शुरू हो जाता है। हालाँकि, यह दृष्टिकोण अप्रभावी है यदि CONFIG_PREEMPT सेट नहीं है।
  2. इटरेशन कार्य स्लीप अवस्था में प्रवेश करता है (जैसे, I/O की प्रतीक्षा), RCU ग्रेस पीरियड समाप्त हो जाता है, और इटरेशन जारी रहता है। वर्तमान में, मैं किसी भी VMA इटरेशन से अवगत नहीं हूँ जो इस आवश्यकता को पूरा करता हो और कर्नेल एड्रेस लीक करने तथा प्रोग्राम काउंटर (PC) को नियंत्रित करने के लिए शोषण किया जा सके। यह मौजूद हो सकता है, लेकिन गहन जाँच की आवश्यकता है।
  3. इटरेशन कार्य एक व्यवधान (जैसे, टाइमर इंटरप्ट) का अनुभव करता है, जिसके दौरान RCU ग्रेस पीरियड समाप्त हो जाता है। timerfd का उपयोग करके कई हार्डवेयर टाइमर बनाना संभव है, जो VMA इटरेशन के दौरान टाइमआउट होने पर एक लंबा इंटरप्ट ट्रिगर कर सकते हैं। हालाँकि, यह दृष्टिकोण व्यवहार्य नहीं है क्योंकि इंटरप्ट हैंडलर इंटरप्ट अक्षम करके संचालित होता है, और यदि कोई CPU इंटर-प्रोसेसर इंटरप्ट (IPI) को संभाल नहीं सकता है, तो RCU ग्रेस पीरियड समाप्त नहीं होगा।
  4. इटरेशन कार्य को जानबूझकर लंबा किया जाता है, जिससे RCU ग्रेस पीरियड समाप्त हो जाता है। यह चुना गया समाधान है। यदि वर्तमान RCU ग्रेस पीरियड jiffies_till_first_fqs (डिफ़ॉल्ट रूप से कुछ जिफ़ीज़) से अधिक हो जाता है, तो पीड़ित CPU पर एक इंटर-प्रोसेसर इंटरप्ट (IPI) भेजा जाएगा और स्वैच्छिक प्रीएम्प्शन ट्रिगर होगा। VMA इटरेशन के मामले में, स्वैच्छिक प्रीएम्प्शन RCU ग्रेस पीरियड को समाप्त कर सकता है और मेपल नोड को मुक्त कर सकता है, जिससे UAFBR प्रभावी रूप से एक वास्तविक use-after-free (UAF) परिदृश्य में परिवर्तित हो जाता है।

एक महत्वपूर्ण अवलोकन यह है कि /proc/[pid]/maps के लिए VMA इटरेशन के दौरान, यह फ़ाइल-मैप्ड मेमोरी क्षेत्रों के लिए संपूर्ण फ़ाइल पथ उत्पन्न करता है। हालाँकि निर्देशिका का नाम आमतौर पर अधिकतम 255 वर्णों तक सीमित होता है, निर्देशिका गहराई पर कोई सीमा नहीं है। इसका अर्थ है कि अत्यधिक बड़ी निर्देशिका गहराई वाली फ़ाइल बनाकर और इस फ़ाइल के लिए एक मेमोरी मैपिंग स्थापित करके, /proc/[pid]/maps तक पहुँचने में VMA इटरेशन के दौरान काफी समय लग सकता है। परिणामस्वरूप, यह विस्तारित अवधि RCU ग्रेस पीरियड को समाप्त करने और UAF प्रिमिटिव प्राप्त करने की संभावना को सक्षम बनाती है।```c static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) { // ...

root@kitploit:~
/*
 * Print the dentry name for named mappings, and a
 * special [heap] marker for the heap:
 */
if (file) {
	seq_pad(m, ' ');
	/*
	 * If user named this anon shared memory via
	 * prctl(PR_SET_VMA ..., use the provided name.
	 */
	if (anon_name)
		seq_printf(m, "[anon_shmem:%s]", anon_name->name);
	else
		seq_file_path(m, file, "\n");
	goto done;
}

// ...

}

root@kitploit:~
यह चरण निम्नलिखित चित्र में दर्शाया गया है:

![चरण 0: UAFBR से UAF तक](https://assets.kitploit.com/production/public/readmes/28620/6791d2c105f1fc504247b668317c7d23c3141c92456dab2fb2e54f7f70e16e15.png)

### चरण 1: slab UAF से page UAF तक

अब जब UAF एक slab के भीतर कार्य कर रहा है। यदि CONFIG_SLAB_MERGE_DEFAULT
सक्षम है और maple nodes का slab kmalloc-256 के साथ विलय हो जाता है, तो
पुराने node के भीतर की सामग्री को kmalloc-256 से एक नई संरचना आवंटित करके
और उसे userspace डेटा से भरकर नियंत्रित किया जा सकता है। हालाँकि, यदि
CONFIG_SLAB_MERGE_DEFAULT सेट नहीं है, तो एक वैकल्पिक दृष्टिकोण की आवश्यकता होती
है। इस स्थिति में, मुक्त किए गए node के page को page allocator को वापस करना
होता है, जिससे पुराने node को एक नया page आवंटित करके और उसे तदनुसार भरकर
नियंत्रित किया जा सके।

याद रखें कि VMA tree में केवल एक node होगा। इसलिए, `fork()`/`clone()` का
उपयोग करके, कई VMA trees और उतनी ही संख्या में maple nodes उत्पन्न होते हैं।
यह मानते हुए कि एक slab में M maple nodes समाहित हैं, और प्रति M nodes में एक
node बनाए रखा जाता है जबकि अन्य सभी nodes को `exit()` के माध्यम से मुक्त कर
दिया जाता है, शेष nodes अपने संबंधित slabs के भीतर एकमात्र nodes बन जाते हैं।
प्रारंभ में, ये slabs CPU की partial list में रहते हैं। जब partial list अपनी
क्षमता तक पहुँच जाती है, तो slabs को वापस संबंधित NUMA node की partial list
में फ्लश कर दिया जाता है।

यदि किसी slab के भीतर अंतिम maple node को मुक्त कर दिया जाता है, तो slab खाली
हो जाता है। यदि यह slab किसी NUMA node की partial list में रहता है, और उस
विशेष NUMA node की partial list पहले से ही अधिकतम क्षमता पर है, तो page को
तुरंत page allocator को वापस कर दिया जाता है। परिणामस्वरूप, slab UAF एक page
UAF परिदृश्य में बदल जाता है। मुक्त किए गए page के भीतर की सामग्री को
`msgsnd()` के माध्यम से कुछ डेटा भेजकर हेरफेर किया जा सकता है, जो elastic
objects आवंटित करता है और उन्हें सीधे प्रदान किए गए user डेटा से भर देता है।```c
static void __slab_free(struct kmem_cache *s, struct slab *slab,
			void *head, void *tail, int cnt,
			unsigned long addr)

{
	// ...

	if (unlikely(!new.inuse && n->nr_partial >= s->min_partial))
		goto slab_empty;

	// ...
	return;

slab_empty:
	// ...
	discard_slab(s, slab);
}

प्रति स्लैब मेपल नोड्स की संख्या, M, CPU की संख्या पर निर्भर करती है। एक्सप्लॉइट कार्यान्वयन दो CPU वाली स्थिति पर विचार करता है और इसलिए M का मान 16 मानता है, जैसा कि निम्नलिखित आकृति में दर्शाया गया है:

चरण 1: स्लैब UAF से पेज UAF तक

चरण 2: UAF से एड्रेस लीकिंग तक

मेपल नोड पर नियंत्रण पाने के बाद, बाद में पुनरावृत्त किए जाने वाले आगामी VMAs के एड्रेसों को हेरफेर करना संभव हो जाता है। चूँकि लक्षित पुनरावृत्ति /proc/self/maps उत्पन्न करने के उद्देश्य से होती है, कुछ VMA जानकारी, जैसे प्रारंभ और समाप्ति एड्रेस, जो VMA संरचना के भीतर स्थित होते हैं, उपयोगकर्ता स्पेस में लौटा दी जाती हैं।

हालाँकि, एक चुनौती उत्पन्न होती है: मेपल नोड में VMA संरचना का पता केवल तभी उचित रूप से सेट किया जा सकता है जब कुछ पते पहले से ज्ञात हों। सौभाग्य से, CVE-2023-0597 सीधे इस उद्देश्य की पूर्ति करता है। CVE-2023-0597 के अनुसार, cpu_entry_area का पता रैंडमाइज़ नहीं होता है। हालाँकि इस कमजोरी को Linux 6.2 में पैच कर दिया गया है, लेकिन लेखन के समय तक इसे पहले के स्थिर कर्नेल में बैकपोर्ट नहीं किया गया है। परिणामस्वरूप, VMA संरचना के पते को अंतिम IDT प्रविष्टि के पते से अधिलेखित करके, वह प्रविष्टि जिसमें asm_sysvec_spurious_apic_interrupt का पता होता है, सीधे लीक हो जाती है, जिससे कर्नेल कोड और कर्नेल डेटा के आधार पते प्रकट हो जाते हैं।

चरण 2: UAF से एड्रेस लीकिंग तक (1)

पहले चर्चित विधि का उपयोग पुनरावर्ती रूप से कर्नेल डेटा अनुभाग से अधिक पतों को क्रमिक रूप से उजागर करने के लिए किया जा सकता है। उदाहरण के लिए, डेटा अनुभाग में init_task.tasks.prev पॉइंटर नवीनतम निर्मित कार्य के task_struct संरचना की ओर इंगित करता है, जो निस्संदेह हीप पर आवंटित होता है।

चरण 2: UAF से एड्रेस लीकिंग तक (2)

जब सभी नव स्थापित कार्य समाप्त कर दिए जाते हैं, तो उनकी task_struct संरचनाएँ बाद में डीलोकेट कर दी जाएँगी। यदि इन कार्यों की मात्रा पर्याप्त रूप से बड़ी है, तो संबंधित पेज पेज आवंटक को वापस सौंपे जा सकते हैं। यह इन पेजों को पुनः आवंटित करने और उन्हें उपयोगकर्ता डेटा से भरने की संभावना प्रदान करता है। हालाँकि, ध्यान रखें कि जारी किए गए पेज सामान्यतः per-cpu पेज (PCP) सूची से संबंधित होते हैं। PCP सूची में मौजूद पेजों के लिए, उन्हें केवल उसी पेज क्रम में पुनः आवंटित किया जा सकता है। परिणामस्वरूप, केवल नए पेजों को उपयोगकर्ता स्पेस में मैप करना, जिसके लिए पेज आवंटक से केवल order-0 पेजों की आवश्यकता होती है, उद्देश्यों को पूरा नहीं करेगा।

फिर भी, msgsnd सिस्टम कॉल kmalloc के माध्यम से मेमोरी चंक्स का अनुरोध करेगा और इन चंक्स को उपयोगकर्ता-परिभाषित डेटा से भर देगा। जब kmalloc कैश समाप्त हो जाता है, तो यह एक विशिष्ट क्रम में पेज आवंटक से पेजों की मांग करेगा। यदि संदेश का आकार सटीक रूप से समायोजित किया जाता है, तो वांछित सटीक क्रम प्राप्त होगा। इस प्रकार, जिस पेज का पता पहले लीक किया गया था, वह पुनः आवंटित किया जाएगा। परिणामस्वरूप, एक ज्ञात पते और उपयोगकर्ता-हेरफेर किए गए डेटा वाला पेज प्राप्त करना संभव हो जाता है।

चरण 3: UAF से रूट विशेषाधिकार तक

अब ज्ञात-पते वाले पेज में VMA संरचना को गढ़ना और vma->vm_ops->name फ़ंक्शन पॉइंटर को नियंत्रित करना संभव है। अगले चरण में कंटेनरों से बचने और रूट विशेषाधिकार प्राप्त करने के लिए उपयुक्त गैजेट्स खोजना शामिल है।```c static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) { // ...

root@kitploit:~
if (vma->vm_ops && vma->vm_ops->name) {
	name = vma->vm_ops->name(vma);
	if (name)
		goto done;
}

// ...

}

root@kitploit:~
![चरण 3: UAF से रूट विशेषाधिकार तक](https://assets.kitploit.com/production/public/readmes/28620/d9c03475803bb799f2b594935d118d73f2547ea4dcf5b40c54e1454324575a0f.png)

गैजेट निर्माण इस प्रकार हैं:
 1. स्टैक पिवट: `movq %rbx, %rsi; movq %rbp, %rdi; call
    __x86_indirect_thunk_r13` -> `pushq %rsi; jmp 46(%rsi)` -> `popq %rsp; ret`
    -> `popq %rsp; ret`, जहाँ %rdi, %rbx, और %r13 _प्रारंभ में_ इंगित करते हैं
    उपयोगकर्ता-नियंत्रित डेटा की ओर।
 2. रूट विशेषाधिकार प्राप्त करें: `popq %rdi; ret` -> `prepare_kernel_cred` -> `popq
    %rdi; ret` -> `movq %rax, (%rdi); ret`, जहाँ %rdi _अब_ इंगित करता है
    स्टैक के शीर्ष की ओर; `popq %rdi; ret` -> `commit_creds`, प्रभावी रूप से
    `commit_creds(prepare_kernel_cred(&init_task))` निष्पादित करता है।
 3. कंटेनरों से बचना: `popq %rdi; ret` -> `find_task_by_vpid` -> `popq %rdi;
    ret` -> `movq %rax, (%rdi); ret`, जहाँ %rdi _अब_ स्टैक के शीर्ष की ओर इंगित करता है;
    `popq %rdi; ret` -> `popq %rsi; ret` -> `switch_task_namespaces`,
    प्रभावी रूप से `switch_task_namespaces(find_task_by_vpid(1),
    &init_nsproxy)` निष्पादित करता है।
 4. mm अनलॉक करें: `popq %rax; ret` -> `movq %rbp, %rdi; call
    __x86_indirect_thunk_rax`, जहाँ %rbp मूल seq_file की ओर इंगित करता है;
    `popq %rax; ret` -> `m_stop`, प्रभावी रूप से `m_stop(seq_file, ..)` निष्पादित करता है।
 5. यूज़रस्पेस पर लौटें: `swapgs_restore_regs_and_return_to_usermode` का उपयोग करें, और
    शेल पाने के लिए `execve()` को कॉल करें।

अंत में, माउंट नेमस्पेस को पुनर्स्थापित करने के लिए `nsenter --mount=/proc/1/ns/mnt` का उपयोग करें
और `cat /flag/flag` के माध्यम से फ्लैग प्राप्त करें।

### स्रोत कोड

पूर्ण एक्सप्लॉइट स्रोत [यहाँ](https://github.com/lrh2000/stackrot/blob/HEAD/exp) उपलब्ध है। अधिक विवरण के लिए,
इसकी README फ़ाइल देखें।
टूल डाउनलोड करें