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

This commit is contained in:
Translator 2025-09-29 09:00:03 +00:00
parent 32c7c0ed3e
commit d849535ddf

View File

@ -1,56 +1,56 @@
# 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)
Ceci est un résumé de larticle disponible sur [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html). De plus, des informations complémentaires sur des exploits utilisant cette technique se trouvent sur [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>
### Gestion de la mémoire dans XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
L'espace d'adressage mémoire virtuel pour les processus utilisateur sur iOS s'étend de 0x0 à 0x8000000000. Toutefois, ces adresses ne correspondent pas directement à la mémoire physique. Le noyau utilise des tables de pages pour traduire les adresses virtuelles en adresses physiques réelles.
L**espace dadresses mémoire virtuelle** pour les process utilisateur sur iOS sétend de **0x0 à 0x8000000000**. Cependant, ces adresses ne correspondent pas directement à la mémoire physique. Le **kernel** utilise des **page tables** pour traduire les adresses virtuelles en adresses **physiques** réelles.
#### Levels of Page Tables in iOS
#### Niveaux des page tables sur iOS
Les tables de pages sont organisées de manière hiérarchique en trois niveaux :
Les page tables sont organisées hiérarchiquement en trois niveaux :
1. **L1 Page Table (Level 1)** :
* Chaque entrée ici représente une large plage de mémoire virtuelle.
* Elle couvre **0x1000000000 bytes** (ou **256 GB**) de mémoire virtuelle.
* Chaque entrée représente une large plage de mémoire virtuelle.
* Elle couvre **0x1000000000 bytes** (soit **256 GB**) de mémoire virtuelle.
2. **L2 Page Table (Level 2)** :
* Une entrée ici représente une région plus petite de mémoire virtuelle, spécifiquement **0x2000000 bytes** (32 MB).
* Une entrée représente une région plus petite de mémoire virtuelle, spécifiquement **0x2000000 bytes** (32 MB).
* Une entrée L1 peut pointer vers une table L2 si elle ne peut pas mapper toute la région elle-même.
3. **L3 Page Table (Level 3)** :
* C'est le niveau le plus fin, où chaque entrée mappe une page mémoire de **4 KB**.
* Cest le niveau le plus fin, où chaque entrée mappe une page mémoire de **4 KB**.
* Une entrée L2 peut pointer vers une table L3 si un contrôle plus granulaire est nécessaire.
#### Mapping Virtual to Physical Memory
#### Mapper le virtuel vers le physique
* **Direct Mapping (Block Mapping)** :
* Certaines entrées dans une table de pages mappent directement une plage d'adresses virtuelles à une plage contiguë d'adresses physiques (comme un raccourci).
* **Pointer to Child Page Table** :
* Si un contrôle plus fin est nécessaire, une entrée à un niveau (par exemple L1) peut pointer vers une table de pages enfant au niveau suivant (par exemple L2).
* Certaines entrées dans une page table mapent directement une plage dadresses virtuelles vers une plage contiguë dadresses physiques (comme un raccourci).
* **Pointeur vers une child page table** :
* Si un contrôle plus fin est requis, une entrée à un niveau (par ex. L1) peut pointer vers une **child page table** au niveau suivant (par ex. L2).
#### Example: Mapping a Virtual Address
#### Exemple : résolution dune adresse virtuelle
Supposons que vous essayez d'accéder à l'adresse virtuelle **0x1000000000** :
Supposons que vous accédiez à ladresse virtuelle **0x1000000000** :
1. **L1 Table** :
* Le noyau vérifie l'entrée correspondante de la table L1 pour cette adresse virtuelle. Si elle contient un **pointer to an L2 page table**, il se rend dans cette table L2.
* Le kernel vérifie lentrée de la table L1 correspondant à cette adresse virtuelle. Si elle contient un **pointeur vers une L2 page table**, il se rend dans cette L2.
2. **L2 Table** :
* Le noyau vérifie la table L2 pour un mapping plus détaillé. Si cette entrée pointe vers une **L3 page table**, il poursuit vers elle.
* Le kernel vérifie la L2 pour un mapping plus détaillé. Si cette entrée pointe vers une **L3 page table**, il continue vers celle-ci.
3. **L3 Table** :
* Le noyau consulte l'entrée finale L3, qui pointe vers l'adresse physique de la page mémoire réelle.
* Le kernel consulte lentrée finale de L3, qui pointe vers l**adresse physique** de la page mémoire réelle.
#### Example of Address Mapping
#### Exemple de mapping dadresses
Si vous écrivez l'adresse physique **0x800004000** dans le premier index de la table L2, alors :
Si vous écrivez ladresse physique **0x800004000** dans le premier index de la table L2, alors :
* Les adresses virtuelles de **0x1000000000** à **0x1002000000** sont mappées aux adresses physiques de **0x800004000** à **0x802004000**.
* C'est un **block mapping** au niveau L2.
* Les adresses virtuelles de **0x1000000000** à **0x1002000000** sont mappées vers les adresses physiques de **0x800004000** à **0x802004000**.
* Il sagit dun **block mapping** au niveau L2.
Alternativement, si l'entrée L2 pointe vers une table L3 :
Alternativement, si lentrée L2 pointe vers une table L3 :
* Chaque page de 4 KB dans la plage virtuelle **0x1000000000 -> 0x1002000000** serait mappée par des entrées individuelles dans la table L3.
@ -58,40 +58,40 @@ Alternativement, si l'entrée L2 pointe vers une table L3 :
Un **physical use-after-free** (UAF) se produit lorsque :
1. Un processus **alloue** de la mémoire en lecture/écriture.
2. Les **tables de pages** sont mises à jour pour mapper cette mémoire vers une adresse physique spécifique accessible par le processus.
3. Le processus **désalloue** (libère) la mémoire.
4. Cependant, à cause d'un **bogue**, le noyau **oublie de supprimer le mapping** des tables de pages, même s'il marque la mémoire physique correspondante comme libre.
5. Le noyau peut alors **réallouer cette mémoire physique "libérée"** à d'autres fins, comme des structures de données du noyau.
6. Puisque le mapping n'a pas été supprimé, le processus peut toujours **lire et écrire** dans cette mémoire physique.
1. Un process **alloue** de la mémoire en lecture/écriture.
2. Les **page tables** sont mises à jour pour mapper cette mémoire à une adresse physique spécifique accessible par le process.
3. Le process **désalloue** (libère) la mémoire.
4. Cependant, en raison dun **bug**, le kernel **oublie de supprimer le mapping** des page tables, alors même quil marque la mémoire physique correspondante comme libre.
5. Le kernel peut alors **réallouer cette mémoire physique "libérée"** pour dautres usages, comme des données kernel.
6. Comme le mapping na pas été supprimé, le process peut toujours **lire et écrire** cette mémoire physique.
Cela signifie que le processus peut accéder à des pages de la mémoire du noyau, qui peuvent contenir des données sensibles ou des structures, permettant potentiellement à un attaquant de **manipuler la mémoire du noyau**.
Cela signifie que le process peut accéder à des **pages de mémoire kernel**, qui peuvent contenir des données sensibles ou des structures, permettant potentiellement à un attaquant de **manipuler la mémoire kernel**.
### IOSurface Heap Spray
Since the attacker cant control which specific kernel pages will be allocated to freed memory, they use a technique called **heap spray**:
Étant donné que lattaquant ne peut pas contrôler quelles pages kernel spécifiques seront allouées à la mémoire libérée, il utilise une technique appelée **heap spray** :
1. The attacker **creates a large number of IOSurface objects** in kernel memory.
2. Each IOSurface object contains a **magic value** in one of its fields, making it easy to identify.
3. They **scan the freed pages** to see if any of these IOSurface objects landed on a freed page.
4. When they find an IOSurface object on a freed page, they can use it to **read and write kernel memory**.
1. Lattaquant **crée un grand nombre dobjets IOSurface** dans la mémoire kernel.
2. Chaque objet IOSurface contient une **valeur magique** dans lun de ses champs, ce qui facilite son identification.
3. Ils **scannent les pages libérées** pour voir si lun de ces objets IOSurface a été placé sur une page libérée.
4. Lorsquils trouvent un objet IOSurface sur une page libérée, ils peuvent lutiliser pour **lire et écrire la mémoire kernel**.
More info about this in [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
Plus dinfos à ce sujet sur [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.
> Notez que les appareils iOS 16+ (A12+) apportent des mitigations matérielles (comme PPL ou SPTM) qui rendent les techniques de physical UAF beaucoup moins viables.
> PPL applique des protections MMU strictes sur les pages liées au code signing, aux entitlements et aux données kernel sensibles : même si une page est réutilisée, les écritures depuis userland ou depuis du code kernel compromis vers des pages protégées par PPL sont bloquées.
> Secure Page Table Monitor (SPTM) étend PPL en renforçant les mises à jour des page tables elles-mêmes. Il garantit que même du code kernel privilégié ne peut pas remapper silencieusement des pages libérées ou altérer des mappings sans passer par des vérifications sécurisées.
> KTRR (Kernel Text Read-Only Region) verrouille la section code du kernel en lecture seule après le boot. Cela empêche toute modification à lexécution du code kernel, fermant un vecteur dattaque majeur sur lequel les exploits physical UAF sappuient souvent.
> De plus, les allocations `IOSurface` sont moins prévisibles et plus difficiles à mapper dans des régions accessibles par lutilisateur, ce qui rend la technique de “scan de valeur magique” beaucoup moins fiable. Et `IOSurface` est désormais protégé par des entitlements et des restrictions de sandbox.
### Step-by-Step Heap Spray Process
1. **Spray IOSurface Objects**: The attacker creates many IOSurface objects with a special identifier ("magic value").
2. **Scan Freed Pages**: They check if any of the objects have been allocated on a freed page.
3. **Read/Write Kernel Memory**: By manipulating fields in the IOSurface object, they gain the ability to perform **arbitrary reads and writes** in kernel memory. This lets them:
* Use one field to **read any 32-bit value** in kernel memory.
* Use another field to **write 64-bit values**, achieving a stable **kernel read/write primitive**.
1. **Spray IOSurface Objects** : Lattaquant crée de nombreux objets IOSurface avec un identifiant spécial (« valeur magique »).
2. **Scan Freed Pages** : Il vérifie si lun des objets a été alloué sur une page libérée.
3. **Read/Write Kernel Memory** : En manipulant les champs de lobjet IOSurface, il obtient la capacité deffectuer des **lectures et écritures arbitraires** en mémoire kernel. Cela lui permet de :
* Utiliser un champ pour **lire nimporte quelle valeur 32 bits** en mémoire kernel.
* Utiliser un autre champ pour **écrire des valeurs 64 bits**, obtenant ainsi un primitive stable de **kernel read/write**.
Générez des objets IOSurface avec la valeur magique IOSURFACE\_MAGIC pour les rechercher ensuite :
```c
@ -148,24 +148,24 @@ free(surfaceIDs);
return 0;
}
```
### Obtention de lecture/écriture au noyau avec IOSurface
### Obtenir Kernel Read/Write avec IOSurface
Après avoir pris le contrôle d'un objet IOSurface dans la mémoire du noyau (mappé sur une page physique libérée accessible depuis l'espace utilisateur), nous pouvons l'utiliser pour effectuer des opérations **de lecture et d'écriture arbitraires dans le noyau**.
Après avoir pris le contrôle d'un objet IOSurface dans kernel memory (mappé sur une page physique libérée accessible depuis userspace), nous pouvons l'utiliser pour **arbitrary kernel read and write operations**.
**Champs clés dans IOSurface**
L'objet IOSurface possède deux champs cruciaux :
L'objet IOSurface contient deux champs cruciaux :
1. **Use Count Pointer** : Permet une **lecture 32-bit**.
2. **Indexed Timestamp Pointer** : Permet une **écriture 64-bit**.
1. **Use Count Pointer** : Permet un **32-bit read**.
2. **Indexed Timestamp Pointer** : Permet un **64-bit write**.
En écrasant ces pointeurs, nous les redirigeons vers des adresses arbitraires dans la mémoire du noyau, ce qui active des capacités de lecture/écriture.
En écrasant ces pointeurs, nous les redirigeons vers des adresses arbitraires dans kernel memory, ce qui permet des capacités de read/write.
#### Lecture 32-bit du noyau
#### 32-Bit Kernel Read
Pour effectuer une lecture :
1. Écrasez le **use count pointer** pour qu'il pointe vers l'adresse cible moins un décalage de 0x14 octets.
1. Écrasez le **use count pointer** pour qu'il pointe vers l'adresse cible moins un 0x14-byte offset.
2. Utilisez la méthode `get_use_count` pour lire la valeur à cette adresse.
```c
uint32_t get_use_count(io_connect_t client, uint32_t surfaceID) {
@ -184,12 +184,12 @@ iosurface_set_use_count_pointer(info.object, orig);
return value;
}
```
#### Écriture 64 bits dans le kernel
#### Écriture 64 bits du Kernel
Pour effectuer une écriture :
1. Écraser le **indexed timestamp pointer** pour qu'il pointe vers l'adresse cible.
2. Utiliser la méthode `set_indexed_timestamp` pour écrire une valeur 64 bits.
1. Écraser le **indexed timestamp pointer** par l'adresse cible.
2. Utilisez la méthode `set_indexed_timestamp` pour écrire une valeur 64 bits.
```c
void set_indexed_timestamp(io_connect_t client, uint32_t surfaceID, uint64_t value) {
uint64_t args[3] = {surfaceID, 0, value};
@ -203,13 +203,13 @@ set_indexed_timestamp(info.client, info.surface, value);
iosurface_set_indexed_timestamp_pointer(info.object, orig);
}
```
#### Récapitulatif du déroulement de l'exploit
#### Récapitulatif du flux d'exploit
1. **Trigger Physical Use-After-Free** : les pages libérées sont disponibles pour réutilisation.
1. **Trigger Physical Use-After-Free**: Des pages libérées sont disponibles pour réutilisation.
2. **Spray IOSurface Objects**: Allouer de nombreux objets IOSurface avec une "magic value" unique dans kernel memory.
3. **Identify Accessible IOSurface**: Localiser un IOSurface sur une page libérée que vous contrôlez.
4. **Abuse Use-After-Free** : Modifier les pointeurs dans l'objet IOSurface pour permettre des **kernel read/write** arbitraires via les méthodes IOSurface.
4. **Abuse Use-After-Free**: Modifier des pointeurs dans l'objet IOSurface pour permettre des **kernel read/write** arbitraires via les méthodes IOSurface.
Avec ces primitives, l'exploit fournit des **32-bit reads** contrôlés et des **64-bit writes** vers kernel memory. Les étapes de jailbreak ultérieures pourraient impliquer des primitives de lecture/écriture plus stables, ce qui peut nécessiter de contourner des protections supplémentaires (p. ex., PPL sur les appareils arm64e plus récents).
Avec ces primitives, l'exploit fournit des **32-bit reads** contrôlés et des **64-bit writes** vers kernel memory. Des étapes de jailbreak supplémentaires pourraient impliquer des primitives de read/write plus stables, ce qui peut nécessiter de contourner des protections additionnelles (par ex., PPL sur les nouveaux appareils arm64e).
{{#include ../../banners/hacktricks-training.md}}