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

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

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

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

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

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
CVE-2012-0056 — Linux विशेषाधिकार वृद्धि | Kitploit
उपकरण/GitHubGitHub/pythonone/cve-2012-0056
विशेषाधिकार वृद्धिभेद्यता विश्लेषणशोषणशेलकोडलर्निंग और शिक्षाबाइनरी शोषण
GitHubpythonone/cve-2012-0056

CVE-2012-0056

Linux विशेषाधिकार वृद्धि

रिपॉजिटरी देखें
1610 साल पहलेअभी तक समीक्षित नहीं

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

सभी देखें →

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

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

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

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

SUID /proc/pid/mem राइट के माध्यम से Linux स्थानीय विशेषाधिकार वृद्धि

मेमपॉडिपर

मेमपॉडिपर का परिचय, CVE-2012-0056 के लिए एक शोषण। /proc/pid/mem एक इंटरफ़ेस है जो प्रक्रिया मेमोरी को सीधे पढ़ने और लिखने के लिए है, जिसमें प्रक्रिया के वर्चुअल मेमोरी स्पेस के समान पतों पर सीक किया जाता है। 2.6.39 में, /proc/pid/mem तक अनधिकृत पहुँच के विरुद्ध सुरक्षा को पर्याप्त माना गया, और इसलिए पिछला #ifdef जो मनमानी प्रक्रिया मेमोरी में लिखने के लिए राइट सपोर्ट को रोकता था, हटा दिया गया था। सही अनुमतियों वाला कोई भी व्यक्ति प्रक्रिया मेमोरी में लिख सकता था। बेशक, यह पता चला कि अनुमति जाँच खराब तरीके से की गई थी। इसका मतलब है कि सभी Linux कर्नेल >=2.6.39 असुरक्षित हैं, कुछ दिन पहले फिक्स कमिट तक। आइए पुराने कर्नेल कोड को चरण दर चरण लें और जानें कि इसमें क्या समस्या है।

जब /proc/pid/mem खोला जाता है, तो यह कर्नेल कोड कॉल किया जाता है:

root@kitploit:~
static int mem_open(struct inode* inode, struct file* file)
{
	file->private_data = (void*)((long)current->self_exec_id);
	/* OK to pass negative loff_t, we can catch out-of-range */
	file->f_mode |= FMODE_UNSIGNED_OFFSET;
	return 0;
}

खोलने पर कोई प्रतिबंध नहीं हैं; कोई भी किसी भी प्रक्रिया के लिए /proc/pid/mem fd खोल सकता है (सामान्य VFS प्रतिबंधों के अधीन)। यह केवल मूल प्रक्रिया के self_exec_id का नोट करता है जिसके साथ इसे खोला गया था और इसे बाद में पढ़ने और लिखने के दौरान जाँच के लिए संग्रहीत करता है।

हालाँकि, लिखने (और पढ़ने) में अनुमति जाँच प्रतिबंध हैं। आइए राइट फ़ंक्शन पर एक नज़र डालें:

root@kitploit:~
static ssize_t mem_write(struct file * file, const char __user *buf,
			 size_t count, loff_t *ppos)
{

/* unimportant code removed for blog post */	

	struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
	
/* unimportant code removed for blog post */

	mm = check_mem_permission(task);
	copied = PTR_ERR(mm);
	if (IS_ERR(mm))
		goto out_free;

/* unimportant code removed for blog post */	

	if (file->private_data != (void *)((long)current->self_exec_id))
		goto out_mm;

/* unimportant code removed for blog post
 * (the function here goes onto write the buffer into the memory)
 */	

तो अनधिकृत लेखन को रोकने के लिए दो प्रासंगिक जाँचें हैं: check_mem_permission और self_exec_id। आइए पहले पहली और फिर दूसरी करते हैं।

check_mem_permission का कोड बस __check_mem_permission में कॉल करता है, तो उसका कोड यहाँ है:

root@kitploit:~
static struct mm_struct *__check_mem_permission(struct task_struct *task)
{
	struct mm_struct *mm;

	mm = get_task_mm(task);
	if (!mm)
		return ERR_PTR(-EINVAL);

	/*
	 * A task can always look at itself, in case it chooses
	 * to use system calls instead of load instructions.
	 */
	if (task == current)
		return mm;

	/*
	 * If current is actively ptrace'ing, and would also be
	 * permitted to freshly attach with ptrace now, permit it.
	 */
	if (task_is_stopped_or_traced(task)) {
		int match;
		rcu_read_lock();
		match = (ptrace_parent(task) == current);
		rcu_read_unlock();
		if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH))
			return mm;
	}

	/*
	 * No one else is allowed.
	 */
	mmput(mm);
	return ERR_PTR(-EPERM);
}

मेमोरी राइट के अधिकृत होने के दो तरीके हैं। या तो task == current, जिसका अर्थ है कि जिस प्रक्रिया में लिखा जा रहा है वह लिखने वाली प्रक्रिया है, या current (लिखने वाली प्रक्रिया) के पास task (जिस प्रक्रिया में लिखा जा रहा है) के साथ खेलने के लिए गूढ़ ptrace-स्तर की अनुमतियाँ हैं। हो सकता है आपको लगे कि आप ptrace कोड को चकमा दे सकते हैं? यह आकर्षक है। लेकिन मुझे नहीं पता। इसके बजाय, आइए पता लगाएँ कि हम कैसे एक प्रक्रिया को स्वयं मनमानी मेमोरी लिखने के लिए बना सकते हैं, ताकि task == current हो।

अब स्वाभाविक रूप से, हम suid प्रक्रियाओं की मेमोरी में लिखना चाहते हैं, क्योंकि तब हम रूट प्राप्त कर सकते हैं। इसे देखें:

root@kitploit:~
$ su "yeeeee haw I am a cowboy"
Unknown id: yeeeee haw I am a cowboy

su जो भी टेक्स्ट आप चाहते हैं, उसे "Unknown id:" से उपसर्गित करके stderr पर थूक देगा। तो, हम /proc/self/mem के लिए एक fd खोल सकते हैं, लिखने के लिए मेमोरी में सही स्थान पर lseek कर सकते हैं (इस पर बाद में और), stderr और mem fd को एक साथ जोड़ने के लिए dup2 का उपयोग कर सकते हैं, और फिर exec कर सकते हैं su $shellcode प्रक्रिया मेमोरी में शेल स्पॉनर लिखने के लिए, और फिर हमारे पास रूट है। सच में? इतना आसान नहीं।

यहाँ दूसरी बाधा आती है। task == current परीक्षण पास करने के बाद, यह जाँचता है कि वर्तमान self_exec_id उस self_exec_id से मेल खाता है जिसके साथ fd खोला गया था। self_exec_id आखिर है क्या? कर्नेल में इसका केवल कुछ स्थानों पर संदर्भ है। सबसे महत्वपूर्ण exec के अंदर होता है:

root@kitploit:~
void setup_new_exec(struct linux_binprm * bprm)
{
/* massive amounts of code trimmed for the purpose of this blog post */

	/* An exec changes our domain. We are no longer part of the thread
	   group */

	current->self_exec_id++;
			
	flush_signal_handlers(current, 0);
	flush_old_files(current->files);
}
EXPORT_SYMBOL(setup_new_exec);

self_exec_id हर बार जब कोई प्रक्रिया exec करती है, बढ़ जाती है। तो इस मामले में, यह इस तरह काम करता है कि आप एक गैर-suid प्रक्रिया में fd नहीं खोल सकते, dup2 नहीं कर सकते, और फिर exec कर सकते हैं एक suid प्रक्रिया में... जो कि ठीक वही है जो हम ऊपर करने की कोशिश कर रहे थे। हमारे हमले को रोकने का काफी चालाक तरीका, है ना?

यहाँ इससे बचने का तरीका है। हम एक चाइल्ड को फोर्क करते हैं, और उस चाइल्ड के अंदर, हम एक नई प्रक्रिया में exec करते हैं। प्रारंभिक चाइल्ड फोर्क का self_exec_id उसके पैरेंट के बराबर होता है। जब हम एक नई प्रक्रिया में exec करते हैं, तो self_exec_id एक से बढ़ जाता है। इस बीच, पैरेंट स्वयं हमारे शेलकोड लिखने वाली su प्रक्रिया में exec करने में व्यस्त है, इसलिए इसका self_exec_id उसी मान पर बढ़ जाता है। तो हम जो करते हैं वह है - हम इस चाइल्ड को फोर्क करते हैं और एक नई प्रक्रिया में exec करते हैं, और उस नई प्रक्रिया के अंदर, हम अपनी प्रक्रिया के बजाय पैरेंट प्रक्रिया के pid का उपयोग करके /proc/parent-pid/mem के लिए एक fd खोलते हैं (जैसा कि पहले था)। हम इस तरह fd खोल सकते हैं क्योंकि एक साधारण खोलने के लिए कोई अनुमति जाँच नहीं है। जब इसे खोला जाता है, तो इसका self_exec_id पहले ही सही मान पर बढ़ चुका होता है जो पैरेंट का self_exec_id होगा जब हम su में exec करेंगे। तो अंत में, हम अपने खुले fd को चाइल्ड प्रक्रिया से पैरेंट प्रक्रिया को वापस पास करते हैं (कुछ बहुत ही ब्लैक यूनिक्स डोमेन सॉकेट मैजिक का उपयोग करके), अपना dup2 करते हैं, और शेल कोड के साथ su में exec करते हैं।

एक और आपत्ति बाकी है। हम कहाँ लिखें? हमें लिखने से पहले उचित मेमोरी स्थान पर lseek करना होगा, और ASLR प्रक्रिया पता स्थानों को यादृच्छिक करता है जिससे यह जानना असंभव हो जाता है कि कहाँ लिखना है। क्या हमें प्रक्रिया मेमोरी पढ़ने का तरीका निकालने के लिए और अधिक चतुराई पर समय बिताना चाहिए, और फिर एक खोज करनी चाहिए? नहीं। इसे देखें:

root@kitploit:~
$ readelf -h /bin/su | grep Type
   Type:                              EXEC (Executable file) 

इसका मतलब है कि su में एक गैर-पुनःस्थापन योग्य .text अनुभाग है (अन्यथा यह "EXEC" के बजाय "DYN" उगलता)। यह पता चला है कि अधिकांश डिस्ट्रो पर su PIE के साथ संकलित नहीं है, जो बाइनरी के .text अनुभाग के लिए ASLR को अक्षम करता है! इसलिए हमने su को समझदारी से चुना है। मेमोरी में ऑफसेट हमेशा समान होंगे। तो लिखने के लिए सही स्थान खोजने के लिए, आइए "Unknown id: blabla" त्रुटि संदेश को प्रिंट करने के आसपास की असेंबली देखें।

यह त्रुटि स्ट्रिंग यहाँ प्राप्त करता है:

root@kitploit:~
  403677:       ba 05 00 00 00          mov    $0x5,%edx
  40367c:       be ff 64 40 00          mov    $0x4064ff,%esi
  403681:       31 ff                   xor    %edi,%edi
  403683:       e8 e0 ed ff ff          callq  402468 (dcgettext@plt)

और फिर इसे stderr पर लिखता है:

root@kitploit:~
  403688:       48 8b 3d 59 51 20 00    mov    0x205159(%rip),%rdi        # 6087e8 (stderr)
  40368f:       48 89 c2                mov    %rax,%rdx
  403692:       b9 20 88 60 00          mov    $0x608820,%ecx
  403697:       be 01 00 00 00          mov    $0x1,%esi
  40369c:       31 c0                   xor    %eax,%eax
  40369e:       e8 75 ea ff ff          callq  402118 (__fprintf_chk@plt)

लॉग बंद करता है:

root@kitploit:~
  4036a3:       e8 f0 eb ff ff          callq  402298 (closelog@plt)

और फिर प्रोग्राम से बाहर निकलता है:

root@kitploit:~
  4036a8:       bf 01 00 00 00          mov    $0x1,%edi
  4036ad:       e8 c6 ea ff ff          callq  402178 (exit@plt)

इसलिए हम 0x402178 का उपयोग करना चाहते हैं, जो कि यह कॉल करता है एग्ज़िट फ़ंक्शन है। हम एक सरल bash वन-लाइनर के साथ, शोषण में, exit@plt प्रतीक की खोज को स्वचालित कर सकते हैं:

root@kitploit:~
$ objdump -d /bin/su|grep '<exit@plt>'|head -n 1|cut -d ' ' -f 1|sed 's/^[0]*\([^0]*\)/0x\1/'
0x402178

तो स्वाभाविक रूप से, हम 0x402178 से स्ट्रिंग "Unknown id: " में अक्षरों की संख्या घटाकर लिखना चाहते हैं, ताकि हमारा शेलकोड बिल्कुल सही जगह पर रखा जाए।

शेलकोड सरल और मानक होना चाहिए। यह uid और gid को 0 पर सेट करता है और एक शेल में exec करता है। यदि हम चतुर बनना चाहते हैं, तो हम stderr को फिर से खोल सकते हैं, मेमोरी fd को stderr पर dup2 करने से पहले, हम stderr को डुप करने के लिए एक और fd चुनते हैं, और फिर शेलकोड में, हम उस दूसरे fd को dup2 करते हैं वापस stderr पर।

अंत में, शोषण पूर्ण विश्वसनीयता के साथ एक आकर्षक तरीके से काम करता है:

root@kitploit:~
CVE-2012-0056 $ ls
build-and-run-exploit.sh  build-and-run-shellcode.sh  mempodipper.c  shellcode-32.s  shellcode-64.s
CVE-2012-0056 $ gcc mempodipper.c -o mempodipper
CVE-2012-0056 $ ./mempodipper 
===============================
=          Mempodipper        =
=           by zx2c4          =
=         Jan 21, 2012        =
===============================

[+] Waiting for transferred fd in parent.
[+] Executing child from child fork.
[+] Opening parent mem /proc/6454/mem in child.
[+] Sending fd 3 to parent.
[+] Received fd at 5.
[+] Assigning fd 5 to stderr.
[+] Reading su for exit@plt.
[+] Resolved exit@plt to 0x402178.
[+] Seeking to offset 0x40216c.
[+] Executing su with shellcode.
sh-4.2# whoami
root
sh-4.2# 

आप इसे क्रियाशील देखने के लिए एक वीडियो देख सकते हैं।

Dan Rosenberg को उनकी निरंतर सलाह और समर्थन के लिए धन्यवाद। मैं वर्तमान में कोई स्रोत कोड जारी नहीं कर रहा हूँ, क्योंकि Linus ने बहुत हाल ही में इसे पैच किया है। एक जिम्मेदार समय बीत जाने के बाद या यदि कोई और पहले करता है, तो मैं प्रकाशित करूँगा। यदि आप एक छात्र हैं जो चीजों के बारे में सीखने की कोशिश कर रहे हैं या अन्य वैध कारण हैं, तो हम बात कर सकते हैं।

अपडेट: जाहिर है, इस ब्लॉग पोस्ट के आधार पर, विडंबना यह है कि कुछ अन्य लोगों ने शोषण बनाए और प्रकाशित किए। तो, यहाँ मेरा है। मैंने 32-बिट और 64-बिट के लिए शेलकोड हाथ से लिखा। आनंद लें!

अपडेट 2: जैसा कि पता चला है, Fedora बहुत उपयुक्त रूप से अपने su को PIE के साथ संकलित करता है, जो इस हमले को विफल करता है। दुर्भाग्य से, वे अपने सभी SUID बाइनरी को PIE के साथ संकलित नहीं करते हैं, और इसलिए यह हमला अभी भी संभव है, उदाहरण के लिए, gpasswd के साथ। ऐसा करने का कोड git रिपॉजिटरी की "fedora" शाखा में है, और एक वीडियो प्रदर्शन भी उपलब्ध है।

अपडेट 3: Gentoo SUID बाइनरी पर रीड अनुमतियों को हटाने के लिए पर्याप्त स्मार्ट है, जिससे objdump का उपयोग करके exit@plt ऑफसेट खोजना असंभव हो जाता है। मैंने ptrace का उपयोग करके ऐसा करने का एक और तरीका निर्धारित किया। Ptrace मेमोरी में किसी भी प्रोग्राम की डिबगिंग की अनुमति देता है। SUID प्रोग्राम के लिए, ptracing इसके विशेषाधिकार गिरा देगा, लेकिन यह ठीक है, क्योंकि हम केवल आंतरिक मेमोरी स्थान खोजना चाहते हैं। सही समय पर बाइनरी के ओपकोड को पार्स करके, हम त्रुटि संदेश मुद्रित करने के बाद अगली कॉल के लक्ष्य पते को समझ सकते हैं। मैंने एक स्टैंडअलोन उपयोगिता बनाई है जो ऑफसेट लौटाती है, साथ ही इसे मुख्य mempodipper स्रोत में एकीकृत किया है।

{हमेशा की तरह, यहाँ का कार्य पूर्णतः अकादमिक है, और अनुसंधान और शिक्षा से परे उपयोग के लिए अभिप्रेत नहीं है।}

टूल डाउनलोड करें