Translated ['', 'src/binary-exploitation/ios-exploiting/ios-physical-uaf

This commit is contained in:
Translator 2025-09-29 08:59:28 +00:00
parent ff41abff0d
commit 4866e9a58b

View File

@ -1,97 +1,97 @@
# iOS Physical Use-After-Free via IOSurface
# iOS Physical Use After Free via IOSurface
{{#include ../../banners/hacktricks-training.md}}
## Physical use-after-free
This is a summary from the post from [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html) moreover further information about exploit using this technique can be found in [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
Este es un resumen del post en [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html). Además, más información sobre exploits que usan esta técnica puede encontrarse en [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
### Memory management in XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
El espacio de direcciones de memoria virtual para procesos de usuario en iOS abarca desde 0x0 hasta 0x8000000000. Sin embargo, estas direcciones no se mapean directamente a memoria física. En su lugar, el kernel usa page tables para traducir direcciones virtuales a direcciones físicas reales.
El espacio de direcciones de memoria virtual para procesos de usuario en iOS abarca desde 0x0 hasta 0x8000000000. Sin embargo, estas direcciones no se corresponden directamente con la memoria física. En su lugar, el kernel usa tablas de páginas para traducir direcciones virtuales a direcciones físicas reales.
#### Levels of Page Tables in iOS
Los page tables están organizados jerárquicamente en tres niveles:
Las tablas de páginas están organizadas jerárquicamente en tres niveles:
1. L1 Page Table (Level 1):
1. Tabla de páginas L1 (Level 1):
* Cada entrada aquí representa un rango grande de memoria virtual.
* Cubre 0x1000000000 bytes (o 256 GB) de memoria virtual.
2. L2 Page Table (Level 2):
2. Tabla de páginas L2 (Level 2):
* Una entrada aquí representa una región más pequeña de memoria virtual, específicamente 0x2000000 bytes (32 MB).
* Una entrada L1 puede apuntar a una tabla L2 si no puede mapear toda la región por sí misma.
3. L3 Page Table (Level 3):
* Este es el nivel más fino, donde cada entrada mapea una sola página de memoria de 4 KB.
3. Tabla de páginas L3 (Level 3):
* Este es el nivel más fino, donde cada entrada mapea una página de memoria de 4 KB.
* Una entrada L2 puede apuntar a una tabla L3 si se necesita un control más granular.
#### Mapping Virtual to Physical Memory
* Direct Mapping (Block Mapping):
* Algunas entradas en un page table mapean directamente un rango de direcciones virtuales a un rango contiguo de direcciones físicas (como un atajo).
* Algunas entradas en una tabla de páginas mapean directamente un rango de direcciones virtuales a un rango contiguo de direcciones físicas (como un atajo).
* Pointer to Child Page Table:
* Si se necesita un control más fino, una entrada en un nivel (por ejemplo, L1) puede apuntar a un child page table en el siguiente nivel (por ejemplo, L2).
* Si se necesita mayor granularidad, una entrada en un nivel (por ejemplo, L1) puede apuntar a una tabla de páginas hija en el siguiente nivel (por ejemplo, L2).
#### Example: Mapping a Virtual Address
Supongamos que intentas acceder a la dirección virtual 0x1000000000:
Imagina que intentas acceder a la dirección virtual 0x1000000000:
1. L1 Table:
* El kernel comprueba la entrada del L1 page table correspondiente a esta dirección virtual. Si tiene un pointer to an L2 page table, va a esa tabla L2.
* El kernel comprueba la entrada de la tabla L1 correspondiente a esa dirección virtual. Si tiene un pointer to an L2 page table, va a esa tabla L2.
2. L2 Table:
* El kernel comprueba el L2 page table para un mapeo más detallado. Si esta entrada apunta a un L3 page table, procede allí.
* El kernel comprueba la tabla L2 para un mapeo más detallado. Si esta entrada apunta a una L3 page table, procede allí.
3. L3 Table:
* El kernel busca la entrada final en L3, que apunta a la physical address de la página de memoria real.
* El kernel consulta la entrada final L3, que apunta a la dirección física de la página de memoria real.
#### Example of Address Mapping
Si escribes la physical address 0x800004000 en el primer índice de la L2 table, entonces:
Si escribes la dirección física 0x800004000 en el primer índice de la tabla L2, entonces:
* Las direcciones virtuales desde 0x1000000000 hasta 0x1002000000 se mapean a direcciones físicas desde 0x800004000 hasta 0x802004000.
* Esto es un block mapping a nivel L2.
Alternativamente, si la entrada L2 apunta a una tabla L3:
* Cada página de 4 KB en el rango virtual 0x1000000000 -> 0x1002000000 sería mapeada por entradas individuales en la L3 table.
* Cada página de 4 KB en el rango virtual 0x1000000000 -> 0x1002000000 sería mapeada por entradas individuales en la tabla L3.
### Physical use-after-free
Un Physical use-after-free (UAF) ocurre cuando:
1. Un proceso allocations some memory as readable and writable.
2. Los page tables se actualizan para mapear esta memoria a una physical address específica a la que el proceso puede acceder.
3. El proceso deallocates (frees) la memoria.
4. Sin embargo, debido a un bug, el kernel olvida eliminar el mapping de los page tables, aunque marca la memoria física correspondiente como libre.
5. El kernel puede entonces reallocar esta memoria física "liberada" para otros propósitos, como kernel data.
6. Dado que el mapping no fue eliminado, el proceso aún puede read y write en esta memoria física.
1. Un proceso aloja (allocate) memoria como readable and writable.
2. Las page tables se actualizan para mapear esa memoria a una dirección física específica a la que el proceso puede acceder.
3. El proceso desaloca (free) la memoria.
4. Sin embargo, debido a un bug, el kernel se olvida de eliminar el mapping de las tablas de páginas, aunque marca la memoria física correspondiente como libre.
5. El kernel puede entonces reallocar esa memoria física "liberada" para otros propósitos, como datos del kernel.
6. Como el mapping no se eliminó, el proceso aún puede read y write a esa memoria física.
Esto significa que el proceso puede acceder a páginas de kernel memory, que podrían contener datos sensibles o estructuras, posibilitando que un atacante manipule kernel memory.
Esto significa que el proceso puede acceder a páginas de kernel memory, que podrían contener datos sensibles o estructuras, permitiendo potencialmente a un atacante manipular kernel memory.
### IOSurface Heap Spray
Dado que el atacante no puede controlar qué páginas del kernel específicas serán asignadas a la memoria liberada, utiliza una técnica llamada heap spray:
Dado que el atacante no puede controlar qué páginas del kernel serán asignadas a la memoria liberada, usa una técnica llamada heap spray:
1. El atacante crea una gran cantidad de IOSurface objects en kernel memory.
2. Cada IOSurface object contiene un magic value en uno de sus campos, lo que lo hace fácil de identificar.
3. Escanean las páginas liberadas para ver si alguno de estos IOSurface objects aterrizó en una página liberada.
4. Cuando encuentran un IOSurface object en una página liberada, pueden usarlo para read y write kernel memory.
1. El atacante crea un gran número de objetos IOSurface en kernel memory.
2. Cada objeto IOSurface contiene un valor mágico en uno de sus campos, lo que facilita su identificación.
3. Escanean las páginas liberadas para ver si alguno de estos objetos IOSurface cayó en una página liberada.
4. Cuando encuentran un objeto IOSurface en una página liberada, pueden usarlo para read and write kernel memory.
More info about this in [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
Más información sobre esto en [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
> [!TIP]
> Be aware that iOS 16+ (A12+) devices bring hardware mitigations (like PPL or SPTM) that make physical UAF techniques far less viable.
> PPL enforces strict MMU protections on pages related to code signing, entitlements, and sensitive kernel data, so, even if a page gets reused, writes from userland or compromised kernel code to PPL-protected pages are blocked.
> Secure Page Table Monitor (SPTM) extends PPL by hardening page table updates themselves. It ensures that even privileged kernel code cannot silently remap freed pages or tamper with mappings without going through secure checks.
> KTRR (Kernel Text Read-Only Region), which locks down the kernels code section as read-only after boot. This prevents any runtime modifications to kernel code, closing off a major attack vector that physical UAF exploits often rely on.
> Moreover, `IOSurface` allocations are less predictable and harder to map into user-accessible regions, which makes the “magic value scanning” trick much less reliable. And `IOSurface` is now guarded by entitlements and sandbox restrictions.
> Ten en cuenta que los dispositivos iOS 16+ (A12+) incorporan mitigaciones de hardware (como PPL o SPTM) que hacen que las técnicas de physical UAF sean mucho menos viables.
> PPL impone protecciones MMU estrictas en páginas relacionadas con code signing, entitlements y datos sensibles del kernel, por lo que, incluso si una página se reutiliza, los writes desde userland o código de kernel comprometido a páginas protegidas por PPL son bloqueados.
> Secure Page Table Monitor (SPTM) amplía PPL endureciendo las propias actualizaciones de page tables. Asegura que incluso el código privilegiado del kernel no pueda remapear silenciosamente páginas liberadas o manipular mappings sin pasar por comprobaciones seguras.
> KTRR (Kernel Text Read-Only Region), que bloquea la sección de código del kernel como read-only después del arranque. Esto evita modificaciones en tiempo de ejecución al código del kernel, cerrando una vía de ataque principal de la que dependen muchos exploits de physical UAF.
> Además, las asignaciones de IOSurface son menos predictibles y más difíciles de mapear en regiones accesibles por el usuario, lo que hace que el truco de "scanear por el valor mágico" sea mucho menos fiable. Y IOSurface ahora está protegido por entitlements y restricciones de sandbox.
### Step-by-Step Heap Spray Process
1. Spray IOSurface Objects: El atacante crea muchos IOSurface objects con un identificador especial ("magic value").
2. Scan Freed Pages: Comprueban si alguno de los objects ha sido asignado en una página liberada.
3. Read/Write Kernel Memory: Manipulando campos en el IOSurface object, obtienen la capacidad de realizar arbitrary reads and writes en kernel memory. Esto les permite:
1. Spray IOSurface Objects: El atacante crea muchos objetos IOSurface con un identificador especial ("magic value").
2. Scan Freed Pages: Comprueban si alguno de los objetos ha sido asignado en una página liberada.
3. Read/Write Kernel Memory: Manipulando campos en el objeto IOSurface, obtienen la capacidad de realizar arbitrary reads and writes en kernel memory. Esto les permite:
* Usar un campo para read any 32-bit value en kernel memory.
* Usar otro campo para write 64-bit values, logrando un kernel read/write primitive estable.
* Usar otro campo para write 64-bit values, logrando una stable kernel read/write primitive.
Generate IOSurface objects with the magic value IOSURFACE\_MAGIC to later search for:
```c
@ -148,20 +148,20 @@ free(surfaceIDs);
return 0;
}
```
### Logrando Kernel Read/Write con IOSurface
### Lograr Kernel Read/Write con IOSurface
Después de lograr control sobre un objeto IOSurface en la memoria del kernel (mapeado a una página física liberada accesible desde el espacio de usuario), podemos usarlo para **operaciones arbitrarias de lectura y escritura en el kernel**.
Después de obtener control sobre un objeto IOSurface en la memoria del kernel (mapeado a una página física liberada accesible desde userspace), podemos usarlo para **arbitrary kernel read and write operations**.
**Key Fields in IOSurface**
**Campos clave en IOSurface**
El objeto IOSurface tiene dos campos cruciales:
1. **Use Count Pointer**: Permite una **lectura de 32 bits**.
2. **Indexed Timestamp Pointer**: Permite una **escritura de 64 bits**.
1. **Use Count Pointer**: Permite un **32-bit read**.
2. **Indexed Timestamp Pointer**: Permite un **64-bit write**.
Al sobrescribir estos punteros, los redirigimos a direcciones arbitrarias en la memoria del kernel, habilitando capacidades de lectura/escritura.
Al sobrescribir estos punteros, los redirigimos a direcciones arbitrarias en la memoria del kernel, habilitando capacidades de read/write.
#### Lectura de 32 bits en el kernel
#### Lectura Kernel de 32 bits
Para realizar una lectura:
@ -184,7 +184,7 @@ iosurface_set_use_count_pointer(info.object, orig);
return value;
}
```
#### 64-Bit Kernel Write
#### Escritura en el kernel de 64 bits
Para realizar una escritura:
@ -203,13 +203,13 @@ set_indexed_timestamp(info.client, info.surface, value);
iosurface_set_indexed_timestamp_pointer(info.object, orig);
}
```
#### Resumen del flujo del exploit
#### Exploit Flow Recap
1. **Activar Physical Use-After-Free**: Las páginas liberadas están disponibles para su reutilización.
2. **Spray IOSurface Objects**: Reservar muchos objetos IOSurface con un "valor mágico" único en la memoria del kernel.
3. **Identificar IOSurface accesible**: Localiza un IOSurface en una página liberada que controlas.
4. **Abusar del Use-After-Free**: Modifica punteros en el objeto IOSurface para habilitar **kernel read/write** arbitrarios vía los métodos de IOSurface.
1. **Trigger Physical Use-After-Free**: Las páginas liberadas están disponibles para su reutilización.
2. **Spray IOSurface Objects**: Asigna muchos objetos IOSurface con un "magic value" único en kernel memory.
3. **Identify Accessible IOSurface**: Localiza un IOSurface en una página liberada que controlas.
4. **Abuse Use-After-Free**: Modifica punteros en el objeto IOSurface para habilitar arbitrary **kernel read/write** vía los métodos de IOSurface.
Con estos primitivos, el exploit proporciona **lecturas de 32 bits** controladas y **escrituras de 64 bits** en la memoria del kernel. Pasos adicionales del jailbreak podrían implicar primitivos de lectura/escritura más estables, que pueden requerir sortear protecciones adicionales (p. ej., PPL en dispositivos arm64e más nuevos).
Con estas primitivas, el exploit proporciona **lecturas de 32-bit** controladas y **escrituras de 64-bit** en kernel memory. Pasos adicionales de jailbreak podrían implicar primitivas de read/write más estables, que pueden requerir eludir protecciones adicionales (p. ej., PPL en dispositivos arm64e más recientes).
{{#include ../../banners/hacktricks-training.md}}