Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
optee-qemu — Environnement avec un noyau vulnérable pour l'exploitation du pilote TEE (CVE-2021-44733) | Kitploit
Outils/GitHubGitHub/pjlantz/optee-qemu
Sécurité des Systèmes EmbarquésAnalyse des VulnérabilitésExploitationFuzzingApprentissage et ÉducationExploitation de BinairesLabs et Pratique
GitHubpjlantz/optee-qemu

optee-qemu

Environnement avec un noyau vulnérable pour l'exploitation du pilote TEE (CVE-2021-44733)

Voir le dépôt
7611il y a 4 ansVérifié par Kitploit

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE-2021-44733: Fuzzing et exploitation d'une use-after-free dans le sous-système TEE du noyau Linux

Récemment, une vulnérabilité de type use-after-free a été découverte dans le sous-système TEE du noyau Linux, jusqu'à la version 5.15.11 incluse, et s'est vu attribuer le CVE-2021-44733 [1].

À première vue, elle ne semblait pas exploitable pour plusieurs raisons, mais après une analyse plus approfondie du chemin de code vulnérable et en implémentant un exploit de preuve de concept grossier, il a été possible d'écraser un pointeur de fonction dans le noyau. Aucune charge utile d'élévation de privilèges n'est présentée dans cet article, mais l'environnement complet pour exécuter OPTEE et l'exploit est disponible pour des tests supplémentaires, voir 'Mise en place de l'environnement'.

Contexte

Un TEE (Trusted Execution Environment) est un OS de confiance s'exécutant dans un environnement sécurisé, par exemple TrustZone sur les CPU ARM. Un pilote TEE gère les détails nécessaires pour communiquer avec le TEE. Parmi les tâches les plus importantes du pilote, on trouve la fourniture d'une API générique vers le TEE basée sur la spécification Globalplatform TEE Client API [3], mais aussi la gestion de la mémoire partagée entre Linux et le TEE. Ce sous-système peut être activé en configurant CONFIG_OPTEE dans les configurations du noyau pour les architectures ARM.

Le monde sécurisé contient l'OS de confiance désigné OP-TEE OS [4]. Au-dessus de cet OS, il est possible d'avoir des applications dites Trusted Applications (TA) en cours d'exécution qui peuvent effectuer certaines opérations dans l'environnement isolé, voir Figure 1.

Vue d'ensemble du TEE
Figure 1: Vue d'ensemble du TEE - d'après la présentation de Linaro [5]

Le monde normal (espace utilisateur/noyau Linux) peut interagir avec ces applications en utilisant des applications clientes (CA) et l'API exposée par le sous-système TEE. Une CA peut ouvrir une session vers une TA spécifique et invoquer des fonctions implémentées par la TA. Le passage des arguments entre la TA et la CA se fait via la mémoire partagée. L'interaction entre une CA et une TA utilisant tous les appels système pertinents est décrite ci-dessous.

  1. Une CA ouvre /dev/tee[0-9] pour communiquer avec le pilote. Notez que pour la méthode conventionnelle d'utilisation de ces API, cela se fait implicitement via libteec.

  2. La mémoire partagée peut être enregistrée par la CA à l'aide de l'IOCTL TEE_IOC_SHM_ALLOC. Cela alloue de la mémoire partagée et retourne un descripteur de fichier que l'espace utilisateur peut utiliser dans le cadre de mmap.

  3. L'étape suivante consiste à établir une session à l'aide de l'IOCTL TEE_IOC_OPEN_SESSION et en spécifiant l'uuid d'une TA spécifique. Cet uuid est codé en dur lors de la compilation de la TA.

  4. Pour invoquer une fonction spécifique dans la TA, la CA l'invoque en spécifiant l'identifiant d'une fonction ainsi que les arguments d'entrée, cela se fait à l'aide de TEE_IOC_INVOKE.

  5. Lorsque la CA a terminé toutes ses requêtes, la session peut être fermée à l'aide de TEE_IOC_CLOSE_SESSION.

Session entre CA et TA
Figure 2: Session entre CA et TA - d'après la présentation de Linaro [5]

Une grande partie de la communication entre les clients et le TEE est opaque pour le pilote. La tâche principale du pilote est de gérer le contexte, recevoir les requêtes des clients, les transmettre au TEE et renvoyer les résultats [2].

Fuzzing du pilote TEE

CVE-2021-44733 a été découvert en utilisant le fuzzing avec syzkaller. Le fichier de description utilisé pour cela est fourni ci-dessous. Notez que ioctl$TEE_SHM_REGISTER_FD ne fait partie que de l'arborescence du noyau Linaro (mainteneurs) et non en amont. L'environnement fourni dans 'Mise en place de l'environnement' pourrait être utilisé pour le fuzzing s'il est configuré correctement selon la documentation de syzkaller [6]``` #include <uapi/linux/tee.h>

resource fd_tee0[fd] resource session_resource[int32]

openat$tee0(fd const[AT_FDCWD], dev ptr[in, string["/dev/tee0"]], flags flags[open_flags], mode flags[open_mode]) fd_tee0 ioctl$TEE_OPEN_SESSION(fd fd_tee0, cmd const[0x8010a402], arg ptr[inout, tee_ioctl_buf_data_session]) ioctl$TEE_INVOKE(fd fd_tee0, cmd const[0x8010a403], arg ptr[inout, tee_ioctl_buf_data_invoke]) ioctl$TEE_CANCEL(fd fd_tee0, cmd const[0x8008a404], arg ptr[in, tee_ioctl_buf_data_cancel]) ioctl$TEE_CLOSE_SESSION(fd fd_tee0, cmd const[0x8004a405], arg ptr[in, tee_ioctl_buf_data_close]) ioctl$TEE_VERSION(fd fd_tee0, cmd const[0x800ca400], arg ptr[out, tee_ioctl_buf_data_version]) ioctl$TEE_SHM_ALLOC(fd fd_tee0, cmd const[0xc010a401], arg ptr[inout, tee_ioctl_buf_data_shm_alloc]) ioctl$TEE_SHM_REGISTER(fd fd_tee0, cmd const[0xc018a409], arg ptr[inout, tee_ioctl_buf_data_shm_register]) ioctl$TEE_SHM_REGISTER_FD(fd fd_tee0, cmd const[0xc018a408], arg ptr[inout, tee_ioctl_buf_data_shm_register_fd]) ioctl$TEE_SUPPL_RECV(fd fd_tee0, cmd const[0x8010a406], arg ptr[inout, tee_ioctl_buf_suppl_recv]) ioctl$TEE_SUPPL_SEND(fd fd_tee0, cmd const[0x8010a407], arg ptr[inout, tee_ioctl_buf_suppl_send])

COMMON

#=======================================================

define TEE_IOCTL_UUID_LEN 16

tee_ioctl_param_struct { attr flags[TEE_IOCTL_PARAM_ATTR_TYPE, int64] a int64 b int64 c int64 }

TEE_IOCTL_PARAM_ATTR_TYPE = 0, 1, 2, 3, 5, 6, 7 TEE_LOGIN = 0, 1, 2, 4, 5, 6

OPEN SESSION

#=======================================================

tee_ioctl_buf_data_session { buf_ptr ptr64[inout, tee_ioctl_open_session_struct] buf_len len[buf_ptr, int64] }

tee_ioctl_open_session_struct { uuid array[int8, TEE_IOCTL_UUID_LEN] (in) clnt_uuid array[int8, TEE_IOCTL_UUID_LEN] (in) clnt_login flags[TEE_LOGIN, int32] (in) cancel_id int32 (in) session session_resource (out) ret int32 (out) ret_origin int32 (out) num_params len[params, int32] (in) params array[tee_ioctl_param_struct] (in) }

INVOKE

#=======================================================

tee_ioctl_buf_data_invoke { buf_ptr ptr64[inout, tee_ioctl_invoke_struct] buf_len len[buf_ptr, int64] }

tee_ioctl_invoke_struct { func int32 (in) session session_resource (in) cancel_id int32 (in) ret int32 (out) ret_origin int32 (out) num_params len[params, int32] (in) params array[tee_ioctl_param_struct] (in) }

CANCEL SESSION

#=======================================================

tee_ioctl_buf_data_cancel { cancel_id int32 (in) session session_resource (in) }

CLOSE SESSION

#=======================================================

tee_ioctl_buf_data_close { session session_resource (in) }

VERSION

#=======================================================

tee_ioctl_buf_data_version { impl_id int32 (out) impl_caps int32 (out) gen_caps int32 (out) }

SHM ALLOC

#=======================================================

tee_ioctl_buf_data_shm_alloc { size int64 (inout) flags const[0, int32] (inout) id int32 (out) }

SHM REGISTER

#=======================================================

tee_ioctl_buf_data_shm_register { addr int64 (in) length int64 (inout) flags const[0, int32] (inout) id int32 (out) }

SHM REGISTER FD

#=======================================================

tee_ioctl_buf_data_shm_register_fd { fd int64 (in) size int64 (out) flags const[0, int32] (in) id int32 (out) } [align[8]]

SUPPLICANT RECV

#=======================================================

tee_ioctl_buf_suppl_recv { func int32 (in) num_params len[params, int32] (inout) params array[tee_ioctl_param_struct] (inout) }

SUPPLICANT SEND

#=======================================================

tee_ioctl_buf_suppl_send { ret int32 (out) num_params len[params, int32] (in) params array[tee_ioctl_param_struct] (in) }

root@kitploit:~
Lors du fuzzing, le crash qui a attiré l'attention était lié à un use-after-free d'un objet task_struct alors qu'un mutex était détenu :```
==================================================================
BUG: KASAN: use-after-free in __mutex_lock.constprop.0+0x118c/0x11c4
Read of size 4 at addr 863b0714 by task optee_example_r/244
 
CPU: 0 PID: 244 Comm: optee_example_r Tainted: G      D           5.14.0 #151
Hardware name: Generic DT based system
[<8012b204>] (unwind_backtrace) from [<8011f460>] (show_stack+0x20/0x24)
[<8011f460>] (show_stack) from [<81cf0108>] (dump_stack_lvl+0x5c/0x68)
[<81cf0108>] (dump_stack_lvl) from [<80650f04>] (print_address_description.constprop.0+0x38/0x304)
[<80650f04>] (print_address_description.constprop.0) from [<80651548>] (kasan_report+0x1c0/0x1dc)
[<80651548>] (kasan_report) from [<81d0a9b4>] (__mutex_lock.constprop.0+0x118c/0x11c4)
[<81d0a9b4>] (__mutex_lock.constprop.0) from [<81d0ada4>] (mutex_lock+0x128/0x13c)
[<81d0ada4>] (mutex_lock) from [<817424b0>] (tee_shm_release+0x4b0/0x6cc)
[<817424b0>] (tee_shm_release) from [<81303674>] (dma_buf_release+0x1b8/0x2f0)
[<81303674>] (dma_buf_release) from [<806d5ac0>] (__dentry_kill+0x4c4/0x678)
[<806d5ac0>] (__dentry_kill) from [<806d8a68>] (dput+0x630/0xba4)
[<806d8a68>] (dput) from [<8067d890>] (__fput+0x3b4/0x900)
[<8067d890>] (__fput) from [<801dd1d8>] (task_work_run+0x15c/0x230)
[<801dd1d8>] (task_work_run) from [<80172b70>] (do_exit+0x103c/0x3770)
[<80172b70>] (do_exit) from [<80179aec>] (do_group_exit+0x134/0x3ac)
[<80179aec>] (do_group_exit) from [<801a7658>] (get_signal+0x7d8/0x2f28)
[<801a7658>] (get_signal) from [<8011dea4>] (do_work_pending+0x984/0x154c)
[<8011dea4>] (do_work_pending) from [<801000d0>] (slow_work_pending+0xc/0x20)
Exception stack(0x85743fb0 to 0x85743ff8)
3fa0:                                     00023108 00000080 00000000 00000000
3fc0: 66bca2d0 66bca2d0 66bca2d0 000000f0 66bca2d0 66bca340 00000000 6ec00b0c
3fe0: 66bc9cc8 66bc9cb8 00011655 66c80c20 000e0130 00023108
 
Allocated by task 242:
 set_alloc_info+0x48/0x50
 __kasan_slab_alloc+0x48/0x58
 kmem_cache_alloc+0x14c/0x314
 copy_process+0x2014/0x7b18
 kernel_clone+0x244/0xfc8
 sys_clone+0xc8/0xec
 ret_fast_syscall+0x0/0x58
 0x6ec00a10
 
Freed by task 67:
 kasan_set_track+0x28/0x30
 kasan_set_free_info+0x20/0x34
 __kasan_slab_free+0xdc/0x108
 kmem_cache_free+0x80/0x394
 __put_task_struct+0x2b4/0x35c
 delayed_put_task_struct+0x104/0x384
 rcu_core+0x91c/0x2a68
 __do_softirq+0x2fc/0xfb8
 
Last potentially related work creation:
 kasan_record_aux_stack+0xb8/0xc0
 call_rcu+0x9c/0xfd0
 put_task_struct_rcu_user+0x9c/0xbc
 finish_task_switch+0x534/0xa10
 __schedule+0x934/0x1adc
 schedule_idle+0x9c/0x120
 do_idle+0x2ec/0x434
 cpu_startup_entry+0x18/0x1c
 start_kernel+0x3ec/0x430
 
The buggy address belongs to the object at 863b0700
 which belongs to the cache task_struct of size 1664
The buggy address is located 20 bytes inside of
 1664-byte region [863b0700, 863b0d80)
The buggy address belongs to the page:
page:f09c9565 refcount:1 mapcount:0 mapping:00000000 index:0x0 pfn:0x463b0
head:f09c9565 order:3 compound_mapcount:0 compound_pincount:0
flags: 0x10200(slab|head|zone=0)
raw: 00010200 00000000 00000122 82802e00 00000000 80120012 ffffffff 00000001
page dumped because: kasan: bad access detected
 
Memory state around the buggy address:
 863b0600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 863b0680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>863b0700: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                 ^
 863b0780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 863b0800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================

Cela a été déclenché en fermant tous les descripteurs de fichier de TEE_IOC_SHM_ALLOC pendant qu'un autre thread ouvre une session vers, dans notre cas, un TA inexistant. Syzkaller a réussi à le reproduire et, en expérimentant avec le code du reproducteur et en retardant légèrement l'appel à TEE_IOC_OPEN_SESSION, un autre UAF s'est produit pour un objet appartenant au cache kmalloc-64 :```

================================================================== BUG: KASAN: use-after-free in tee_shm_put+0x8c/0x98 Read of size 4 at addr 86467020 by task optee_example_h/216

CPU: 0 PID: 216 Comm: optee_example_h Not tainted 5.14.0 #21 Hardware name: Generic DT based system [<80122584>] (unwind_backtrace) from [<80117fd4>] (show_stack+0x10/0x14) [<80117fd4>] (show_stack) from [<819d57a0>] (dump_stack_lvl+0x40/0x4c) [<819d57a0>] (dump_stack_lvl) from [<819ced74>] (print_address_description.constprop.0+0x5c/0x2d8) [<819ced74>] (print_address_description.constprop.0) from [<805a12c4>] (kasan_report+0x1b4/0x1d0) [<805a12c4>] (kasan_report) from [<814cc6b0>] (tee_shm_put+0x8c/0x98) [<814cc6b0>] (tee_shm_put) from [<814c9b2c>] (tee_ioctl+0x1578/0x2e44) [<814c9b2c>] (tee_ioctl) from [<806038ec>] (sys_ioctl+0x918/0x1e70) [<806038ec>] (sys_ioctl) from [<80100060>] (ret_fast_syscall+0x0/0x58) Exception stack(0x86417fa8 to 0x86417ff0) 7fa0: 00000080 00000000 00000003 8010a402 200001c0 00000003 7fc0: 00000080 00000000 00423018 00000036 66c562d0 66c55e10 66c562d0 6ebebafc 7fe0: 66c55cb0 66c55ca0 004114bd 66cebd72

Allocated by task 216: tee_shm_alloc+0x15c/0x7e8 tee_ioctl+0x8d0/0x2e44 sys_ioctl+0x918/0x1e70 ret_fast_syscall+0x0/0x58 0x66c55ca0

Freed by task 215: kasan_set_free_info+0x20/0x34 __kasan_slab_free+0xdc/0x108 kfree+0x98/0x294 tee_shm_release+0x1dc/0x610 dma_buf_release+0x180/0x2a0 __dentry_kill+0x488/0x6ac __fput+0x2f0/0x7b4 task_work_run+0x178/0x230 do_work_pending+0xaf8/0x10a8 slow_work_pending+0xc/0x20 0x66d5bd16

The buggy address belongs to the object at 86467000 which belongs to the cache kmalloc-64 of size 64 The buggy address is located 32 bytes inside of 64-byte region [86467000, 86467040) The buggy address belongs to the page: page:(ptrval) refcount:1 mapcount:0 mapping:00000000 index:0x0 pfn:0x46467 flags: 0x200(slab|zone=0) raw: 00000200 00000000 00000122 82401200 00000000 00200020 ffffffff 00000001 page dumped because: kasan: bad access detected

Memory state around the buggy address: 86466f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 86466f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

86467000: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ^ 86467080: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc 86467100: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ==================================================================

root@kitploit:~
Cette vulnérabilité a été découverte en fuzzant le pilote TEE sans qu'aucune session ne soit établie avec une TA existante sur le système. Cela pourrait être étendu avec les soi-disant pseudo-syscalls dans syzkaller afin de configurer et initier une session vers une TA.

## Analyse de la cause racine
La conclusion est un problème de conception dans le suivi de la durée de vie d'un objet `tee_shm:dmabuf`. Le pilote est conçu pour permettre à l'espace utilisateur de conserver la seule et unique référence après un appel à `tee_ioctl_shm_alloc()`.

On suppose que si l'objet est toujours présent dans l'IDR du pilote, alors la référence au dmabuf est toujours valide et son compteur de référence peut être incrémenté. Il s'avère que cela n'est que partiellement vrai. La mémoire du dmabuf est toujours possédée par le pilote dmabuf, mais elle peut être en cours de destruction et cela ne peut pas être arrêté en rendant le compteur de référence non nul à nouveau.

Le scénario qui déclenche le problème est une application multi-threadée où un thread ferme le descripteur de fichier du dmabuf en même temps qu'un autre thread appelle la commande IOCTL `TEE_IOC_OPEN_SESSION` ou `TEE_IOC_INVOKE` en référençant cette mémoire partagée.

Tracer la destruction du dmabuf lorsque l'espace utilisateur ferme le fd exécutera ce code dans le noyau :

1. `fput()`

2. `fput_many()`  >> Le compteur de référence du fichier atteint zéro. La fenêtre de concurrence s'ouvre.

3. `[task_work gets scheduled]`

4. `__fput`

5. `dput`

6. `dma_buf_release`

7. `tee_shm_release`

     8. `mutex_lock(teedev->mutex)`

     9. `idr_remove(teedev->idr, shm->id)` >> Désormais, l'objet shm ne peut plus être référencé depuis l'espace utilisateur. La fenêtre de concurrence se ferme.

     10. `mutex_unlock()`
  
Cela signifie que la table IDR et son verrou mutex ne peuvent pas garantir que le dmabuf et le `tee_shm` correspondant sont toujours vivants. Un processus en concurrence avec `fput()` en appelant `tee_shm_get_from_id()` peut obtenir une référence à un shm qui est sur le point de devenir mort.```
/**
 * tee_shm_get_from_id() - Find shared memory object and increase reference
 * count
 * @ctx:    Context owning the shared memory
 * @id:     Id of shared memory object
 * @returns a pointer to 'struct tee_shm' on success or an ERR_PTR on failure
 */
struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id)
{
    struct tee_device *teedev;
    struct tee_shm *shm;
 
    if (!ctx)
        return ERR_PTR(-EINVAL);
 
    teedev = ctx->teedev;
    mutex_lock(&teedev->mutex);
    shm = idr_find(&teedev->idr, id);
    if (!shm || shm->ctx != ctx)
        shm = ERR_PTR(-EINVAL);
    else if (shm->flags & TEE_SHM_DMA_BUF)
        get_dma_buf(shm->dmabuf);
    mutex_unlock(&teedev->mutex);
    return shm;
}

Exploitation de l'UAF

Pour exploiter cette vulnérabilité, une réallocation doit être effectuée après que l'objet a été libéré et avant de déclencher l'UAF. Après l'appel à tee_shm_get_from_id(), la fonction tee_shm_put() (pour laquelle se produit le second crash UAF provenant de syzkaller) est appelée, ce qui déréférence l'objet tee_shm:dmabuf utilisé comme argument d'entrée de dma_buf_put().``` /**

  • tee_shm_put() - Decrease reference count on a shared memory handle
  • @shm: Shared memory handle */ void tee_shm_put(struct tee_shm *shm) { if (shm->flags & TEE_SHM_DMA_BUF) dma_buf_put(shm->dmabuf); } EXPORT_SYMBOL_GPL(tee_shm_put);
root@kitploit:~
L'objet `tee_shm` pourrait être réalloué avant l'UAF car il appartient au cache kmalloc-64. Il faudrait le réallouer avec :

1. des objets factices `tee_shm`, `tee_shm:dmabuf`, `dma_buf:file`
2. définir `file->f_count = 1`
3. créer un objet `file:file_operations` dont le pointeur de fonction `fasync` est défini sur une adresse arbitraire

Cette fonction est ensuite invoquée dans `__fput()` après l'appel à `dma_buf_put()` lorsque `file->f_count` atteint zéro.

PAN (Privileged Access Never) atténue cette vulnérabilité car les objets factices doivent être référencés dans la mémoire espace utilisateur pour définir un pointeur de fonction arbitraire dans la structure `file:f_ops`. Par conséquent, `CONFIG_CPU_SW_DOMAIN_PAN` doit être désactivé pour que cela fonctionne, ce qui est le cas dans l'environnement fourni. Il reste quelques questions ouvertes quant à savoir si PAN peut être contourné dans cette vulnérabilité, par exemple en utilisant ret2dir.

De plus, pour réussir une réallocation de l'objet shm libéré, l'appel IOCTL `TEE_IOC_OPEN_SESSION` ou `TEE_IOC_INVOKE` doit être anticipé par un thread effectuant la fermeture du descripteur de fichier et un thread de « heap spraying » qui remplit le cache kmalloc-64. Pour que cela fonctionne, le noyau doit être configuré avec `CONFIG_PREEMPT`. Dans cette Preuve de Concept, le « heap spray » de l'article de blog de Nicolas Fabretti [7] a été utilisé, basé sur `sendmsg()` bloquant.

Pour résumer, le problème concernant l'exploitation est que la libération et l'UAF doivent toutes deux se produire dans le même appel système. De plus, la libération est difficile à déclencher car elle nécessite une compétition au sein de l'appel système. Après la libération, l'intervalle de temps entre celle-ci et l'UAF effective est une petite fenêtre temporelle où un « heap spray » doit être effectué pour réallouer l'objet libéré. La figure suivante montre les threads impliqués dans le code d'exploitation et leur rôle.

<p align="center">
  <img src="https://raw.githubusercontent.com/pjlantz/pjlantz.github.io/master/docs/assets/Threads.png?raw=true" alt="Threads involved" width="50%" height="50%"/>
       <br /><em>Figure 3 : Threads impliqués dans le code d'exploitation</em>
</p>

Trois types de threads sont exécutés en continu. Afin de préempter le thread appelant système, celui-ci s'exécute avec la priorité la plus basse possible, `SCHED_IDLE`, tandis que les autres ont la priorité définie sur `SCHED_OTHER`. Comme nous utilisons `sendmsg()` bloquant, chaque tentative de « spray » doit s'exécuter dans son propre thread et doit s'exécuter sur le même cœur de CPU qui déclenche l'UAF, puisque chaque cœur conserve ses propres caches kmalloc. Il existe également un certain nombre de threads de libération qui ferment le descripteur de fichier provenant de l'allocation de mémoire partagée à l'étape 1b). Le code source complet pour ce déclenchement d'UAF et cette réécriture de pointeur de fonction se trouve à [10].

## Configuration du nouvel environnement
Pour reproduire l'environnement avec un noyau vulnérable et OPTEE, il peut être cloné depuis le dépôt suivant et construit en utilisant :```
$ mkdir optee-qemu && cd optee-qemu
$ repo init -u https://github.com/pjlantz/optee-qemu.git
$ repo sync
$ cd build
$ make toolchains -j2
$ make run

Après une compilation réussie, cela générera trois consoles, une pour QEMU - appuyez sur 'c' dans la console QEMU pour démarrer. Une deuxième console affiche la sortie du monde sécurisé et la dernière démarrera Linux. Connectez-vous en tant que root (pas de mot de passe).

Exécutez le code d'exploitation jusqu'à ce que le pointeur de fonction fasync de la structure file_operations soit défini sur 0x22000000.``` until optee_exploit | grep "0x22000000" /var/log/messages; do sleep 0.01; done

root@kitploit:~
Cela s'arrêtera à cause de Privileged execute-never (PXN) bloquant l'exécution à `PC=0x22000000`. À partir de là, les stratégies d'exploitation peuvent varier selon la version du noyau, mais il pourrait être possible d'exécuter un kernel ROP et de faire du stack pivoting, ou de rendre la zone vDSO accessible en écriture et d'y placer la charge utile. Il pourrait également être intéressant pour de futurs travaux d'étudier si PAN peut être contourné en utilisant ret2dir et du physmap spraying. PAN peut être activé dans le noyau en définissant `CONFIG_CPU_SW_DOMAIN_PAN=y` dans `linux/.config`. Sur du matériel réel, il est activé par défaut sur ARMv8.1 et AArch64, pour ARMv7 et AArch32, il est possible d'avoir une émulation logicielle de PAN en utilisant ce paramètre [8].

**Note** : Cet exploit n'est pas très bien optimisé et peut occasionnellement bloquer le pilote s'il parvient à libérer l'objet mémoire partagée trop tôt, auquel cas PC sera à `tee_shm_get_from_id()`. Si cela se produit, exécutez `system_reset` dans la console QEMU pour redémarrer l'environnement.

## Remerciements
Merci à Lars Persson d'Axis Communications pour son aide dans l'analyse de la cause racine et à Jens Wiklander de Linaro et mainteneur du sous-système TEE pour une communication fluide et une résolution rapide de ce problème [9].

## Références 

[1] CVE-2021-44733 - https://nvd.nist.gov/vuln/detail/CVE-2021-44733

[2] Sous-système TEE - https://www.kernel.org/doc/html/latest/staging/tee.html

[3] Globalplatform TEE API - https://globalplatform.org/specs-library/?filter-committee=tee

[4] OP-TEE OS - https://github.com/OP-TEE/optee_os

[5] BKK16-110: Une douce introduction à l'exécution de confiance et OP-TEE - https://connect.linaro.org/resources/bkk16/bkk16-110/

[6] Syzkaller - https://github.com/google/syzkaller 

[7] Blog de sécurité de Lexfo, par Nicolas Fabretti : CVE-2017-11176 : Une exploitation pas à pas du noyau Linux - https://blog.lexfo.fr/cve-2017-11176-linux-kernel-exploitation-part3.html

[8] Sous-système de sécurité du noyau Linux : Méthodes d'exploitation/Utilisation des données de l'espace utilisateur - http://kernsec.org/wiki/index.php/Exploit_Methods/Userspace_data_usage

[9] [PATCH v2] tee: handle lookup of shm with reference count 0 - https://lore.kernel.org/lkml/[email protected]/T/ 

[10] Exploit de preuve de concept - https://github.com/pjlantz/optee_examples/tree/master/exploit/host
Télécharger l’outil