No-exec / NX

Tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें

बुनियादी जानकारी

The No-Execute (NX) bit, जिसे Intel टर्मिनोलॉजी में Execute Disable (XD) भी कहते हैं, एक हार्डवेयर-आधारित सुरक्षा फीचर है जो buffer overflow हमलों के प्रभाव को कम करने के लिए डिज़ाइन किया गया है। जब यह लागू और सक्षम होता है, तो यह उन मेमोरी क्षेत्रों के बीच अंतर करता है जो executable code के लिए हैं और जो data के लिए हैं, जैसे कि stack और heap। मुख्य विचार यह है कि attacker द्वारा stack में malicious code रखने और execution flow को वहाँ निर्देशित करने से रोकना ताकि buffer overflow कमजोरियों के माध्यम से malicious code execute न हो सके।

Modern operating systems NX को उन page table attributes के माध्यम से लागू करते हैं जो ELF program headers को समर्थन देते हैं। उदाहरण के लिए, PT_GNU_STACK header को GNU_PROPERTY_X86_FEATURE_1_SHSTK या GNU_PROPERTY_X86_FEATURE_1_IBT properties के साथ मिलाकर loader को यह बताने देता है कि stack को RW होना चाहिए या RWX। जब NX सक्षम होता है और binary को non-executable stack (-z noexecstack) के साथ link किया गया था, तो attacker-controlled data pages (stack, heap, mmap’ed buffers, आदि) में execution pivot करने का कोई भी प्रयास तब तक fault उठाएगा जब तक कि उन pages को स्पष्ट रूप से executable के रूप में चिह्नित न किया गया हो।

NX का त्वरित पता लगाना

  • checksec --file ./vuln GNU_STACK program header के आधार पर NX enabled या NX disabled दिखाएगा।
  • readelf -W -l ./vuln | grep GNU_STACK stack permissions को प्रदर्शित करता है; यदि E flag मौजूद है तो इसका अर्थ है कि stack executable है। उदाहरण:
$ readelf -W -l ./vuln | grep GNU_STACK
GNU_STACK      0x000000 0x000000 0x000000 0x000000 0x000000 RW  0x10
  • execstack -q ./vuln (from prelink) बड़े बाइनरी संग्रहों का ऑडिट करते समय उपयोगी है क्योंकि यह उन बाइनरीज़ के लिए जो अभी भी एक executable stack रखते हैं, X प्रिंट करता है।
  • रनटाइम पर, /proc/<pid>/maps दिखाएगा कि कोई allocation rwx, rw-, r-x, आदि है या नहीं, जो JIT engines या custom allocators को verify करते समय उपयोगी होता है।

बायपास

Code-reuse primitives

बाइनरी में पहले से मौजूद executable code के टुकड़ों को execute करके इस सुरक्षा को बायपास करने के लिए ROP जैसे techniques का उपयोग संभव है। सामान्य chains में शामिल हैं:

  • Ret2libc
  • Ret2syscall
  • Ret2dlresolve when the binary does not import system/execve
  • Ret2csu or Ret2vdso to synthesize syscalls
  • Ret2… — any dispatcher that lets you stitch controlled register state with existing executable code to invoke syscalls or library gadgets.

कार्यप्रवाह आमतौर पर: (1) किसी info leak के माध्यम से कोड या libc pointer leak करना, (2) function bases resolve करना, और (3) ऐसा chain तैयार करना जिसे attacker-controlled executable bytes की आवश्यकता न हो।

Sigreturn Oriented Programming (SROP)

SROP एक writable पेज पर एक नकली sigframe बनाता है और execution को sys_rt_sigreturn (या संबंधित ABI समतुल्य) पर pivot करता है। फिर kernel crafted context को “restores” करता है, जिससे तुरंत सभी general-purpose registers, rip, और eflags पर पूर्ण नियंत्रण मिल जाता है। हाल के CTF challenges (उदा., Hostel टास्क in n00bzCTF 2023) दिखाते हैं कि SROP chains पहले mprotect को invoke करके stack को RWX में बदलते हैं, फिर उसी stack को shellcode के लिए reuse करते हैं, जिससे NX effectively बायपास हो जाता है भले ही केवल एक syscall; ret gadget उपलब्ध हो। Check the dedicated SROP page for more architecture-specific tricks.

Ret2mprotect / ret2syscall to flip permissions

अगर आप mprotect, pkey_mprotect, या यहां तक कि dlopen कॉल कर सकते हैं, तो shellcode चलाने से पहले आप वैध रूप से एक executable mapping का अनुरोध कर सकते हैं। एक छोटा pwntools स्केलेटन कुछ इस तरह दिखता है:

from pwn import *
elf = ELF("./vuln")
rop = ROP(elf)
rop.mprotect(elf.bss(), 0x1000, 7)
payload = flat({offset: rop.chain(), offset+len(rop.chain()): asm(shellcraft.sh())})

वही विचार उन ret2syscall चेन पर भी लागू होता है जो rax=__NR_mprotect सेट करती हैं, rdi को किसी mmap/.bss पेज की ओर पॉइंट करती हैं, इच्छित लंबाई rsi में स्टोर करती हैं, और rdx=7 (PROT_RWX) सेट करती हैं। एक बार RWX क्षेत्र मौजूद होने पर, execution सुरक्षित रूप से attacker-controlled bytes में कूद सकती है।

RWX primitives from JIT engines and kernels

JIT engines, interpreters, GPU drivers, और kernel subsystems जो dynamically कोड इमिट करते हैं, सख्त NX नीतियों के बावजूद executable memory वापस पाने का एक सामान्य तरीका होते हैं। 2024 Linux kernel vulnerability CVE-2024-42067 ने दिखाया कि set_memory_rox() की विफलताओं ने eBPF JIT पेजों को writable और executable छोड़ दिया, जिससे attackers को kernel के अंदर gadgets या पूरे shellcode blobs स्प्रेय करने की अनुमति मिली, NX/W^X अपेक्षाओं के बावजूद। जो एक्सप्लॉइट किसी JIT compiler (BPF, JavaScript, Lua, आदि) पर नियंत्रण हासिल करते हैं, वे अपने payload को उन RWX arenas में रखवा सकते हैं और केवल एक function pointer overwrite की जरूरत होती है उनमें कूदने के लिए।

Non-return code reuse (JOP/COP)

अगर ret निर्देश हर्डन किए गए हों (जैसे CET/IBT) या बाइनरी में प्रभावशाली ret gadgets न हों, तो Jump-Oriented Programming (JOP) या Call-Oriented Programming (COP) की ओर pivot करें। ये तकनीकें ऐसे dispatchers बनाती हैं जो बाइनरी या लोडेड लाइब्रेरीज़ में मिले jmp [reg] या call [reg] sequences का उपयोग करती हैं। ये अभी भी NX का सम्मान करती हैं क्योंकि वे मौजूदा executable code को reuse करती हैं, पर वे उन mitigations को बायपास कर देती हैं जो विशेष रूप से बड़े ret instruction chains पर नजर रखते हैं।

ROP & JOP

References

Tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें