Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
optee-qemu — Ambiente com kernel vulnerável para exploração do driver TEE (CVE-2021-44733) | Kitploit
Ferramentas/GitHubGitHub/pjlantz/optee-qemu
Segurança de Sistemas EmbarcadosAnálise de VulnerabilidadesExploraçãoFuzzingAprendizado e EducaçãoExploração de BináriosLabs e Prática
GitHubpjlantz/optee-qemu

optee-qemu

Ambiente com kernel vulnerável para exploração do driver TEE (CVE-2021-44733)

Ver Repositório
7611há 4 anosRevisado pelo Kitploit

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2021-44733: Fuzzing e exploração de um use-after-free no subsistema TEE do kernel Linux

Recentemente, uma vulnerabilidade de use-after-free foi descoberta no subsistema TEE do kernel Linux, até e incluindo a versão 5.15.11, e recebeu o identificador CVE-2021-44733 [1].

À primeira vista, não parecia ser explorável por várias razões, no entanto, após uma análise mais aprofundada do caminho de código vulnerável e implementando um exploit de prova de conceito simplório, foi possível sobrescrever um ponteiro de função no kernel. Nenhum payload de escalonamento de privilégio é apresentado neste post, no entanto, todo o ambiente para executar o OPTEE e o exploit está disponível para testes adicionais, veja 'Configurando o ambiente'.

Contexto

Um TEE (Trusted Execution Environment) é um SO confiável executando em algum ambiente seguro, por exemplo, TrustZone em CPUs ARM. Um driver TEE lida com os detalhes necessários para se comunicar com o TEE. Algumas das funções mais importantes do driver são fornecer uma API genérica para o TEE baseada na especificação Globalplatform TEE Client API [3], mas também gerenciar a memória compartilhada entre o Linux e o TEE. Este subsistema pode ser habilitado configurando CONFIG_OPTEE nas configurações do kernel para arquiteturas ARM.

O mundo seguro contém o SO confiável denominado OP-TEE OS [4]. Sobre este SO é possível ter as chamadas Aplicações Confiáveis (TAs) em execução, que podem realizar algumas operações no ambiente isolado, veja a Figura 1.

Visão geral do TEE
Figura 1: Visão geral do TEE - da apresentação da Linaro [5]

O mundo normal (userspace/kernel Linux) pode interagir com essas aplicações usando aplicações cliente (CAs) e a API exposta pelo subsistema TEE. Uma CA pode abrir uma sessão para uma TA específica e invocar funções que a TA implementa. A passagem de argumentos entre a TA e a CA é feita usando memória compartilhada. A interação entre uma CA e uma TA usando todas as syscalls relevantes é descrita a seguir.

  1. Uma CA abre /dev/tee[0-9] para se comunicar com o driver. Note que, para a forma convencional de usar essas APIs, isso é feito implicitamente usando o libteec.

  2. A memória compartilhada pode ser registrada pela CA usando o IOCTL TEE_IOC_SHM_ALLOC. Isso aloca memória compartilhada e retorna um descritor de arquivo que o espaço do usuário pode usar como parte do mmap.

  3. O próximo passo é estabelecer uma sessão usando o IOCTL TEE_IOC_OPEN_SESSION e especificando o uuid para uma TA específica. Este uuid é hardcoded durante a compilação da TA.

  4. Para invocar qualquer função específica na TA, a CA a invoca especificando o identificador de uma função juntamente com quaisquer argumentos de entrada, isso é feito usando TEE_IOC_INVOKE.

  5. Quando a CA terminar todas as requisições, a sessão pode ser fechada usando TEE_IOC_CLOSE_SESSION.

Sessão entre CA e TA
Figura 2: Sessão entre CA e TA - da apresentação da Linaro [5]

Grande parte da comunicação entre clientes e o TEE é opaca para o driver. O principal trabalho do driver é gerenciar o contexto, receber requisições dos clientes, encaminhá-las para o TEE e enviar de volta os resultados [2].

Fuzzing do driver TEE

CVE-2021-44733 foi descoberta usando fuzzing com syzkaller. O arquivo de descrição usado para isso é fornecido abaixo. Note que ioctl$TEE_SHM_REGISTER_FD é apenas parte da árvore do kernel da Linaro (mantenedores) e não no upstream. O ambiente fornecido em 'Configurando o ambiente' poderia ser usado para fuzzing se configurado adequadamente de acordo com a documentação do 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:~
Durante o fuzzing, a falha que chamou a atenção estava relacionada a um use-after-free de um objeto task_struct enquanto um mutex estava sendo mantido:```
==================================================================
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
==================================================================

Isso foi acionado ao fechar todos os descritores de arquivo de TEE_IOC_SHM_ALLOC enquanto uma thread diferente abre uma sessão em direção a, no nosso caso, um TA inexistente. Syzkaller conseguiu reproduzi-lo e, ao experimentar com o código do reprodutor e atrasar ligeiramente a chamada a TEE_IOC_OPEN_SESSION, ocorreu um UAF diferente para um objeto pertencente ao 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:~
Essa vulnerabilidade foi descoberta ao fazer fuzzing no driver TEE sem que nenhuma sessão fosse estabelecida com uma TA existente em execução no sistema. Isso poderia ser estendido ainda mais com as chamadas pseudo syscalls no syzkaller para configurar e iniciar uma sessão em direção a alguma TA.

## Análise da causa raiz

A conclusão é um problema de design com o rastreamento do tempo de vida de um objeto `tee_shm:dmabuf`. O driver é projetado para permitir que o espaço do usuário mantenha a contagem de referência única após uma chamada a `tee_ioctl_shm_alloc()`.

Supõe-se que, se o objeto ainda for encontrado no objeto IDR do driver, então a referência ao dmabuf ainda é válida e sua contagem de referência pode ser incrementada. Acontece que isso é apenas parcialmente verdadeiro. A memória dmabuf ainda é de propriedade do driver dmabuf, mas pode estar em processo de destruição e isso não pode ser interrompido tornando a contagem de referência diferente de zero novamente.

O cenário que desencadeia o problema é um aplicativo multi-thread onde uma thread fecha o descritor de arquivo dmabuf ao mesmo tempo que outra thread faz uma chamada ao comando IOCTL `TEE_IOC_OPEN_SESSION` ou `TEE_IOC_INVOKE` referenciando essa memória compartilhada.

Rastreando a destruição do dmabuf quando o espaço do usuário fecha o fd, o seguinte código será executado no kernel:

1. `fput()`

2. `fput_many()`  >> A contagem de referência do arquivo chega a zero. A janela de corrida se abre.

3. `[task_work é agendado]`

4. `__fput`

5. `dput`

6. `dma_buf_release`

7. `tee_shm_release`

     8. `mutex_lock(teedev->mutex)`

     9. `idr_remove(teedev->idr, shm->id)` >> Agora, o objeto shm não pode mais ser referenciado a partir do espaço do usuário. A janela de corrida fecha.

     10. `mutex_unlock()`

Isso significa que a tabela IDR e seu bloqueio mutex não podem garantir que o dmabuf e o `tee_shm` correspondente ainda estejam vivos. Um processo competindo com `fput()` chamando `tee_shm_get_from_id()` pode obter uma referência a um shm que está prestes a ficar inativo.```
/**
 * 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;
}

Explorando a UAF

Para explorar isso, uma realocação deve ser feita após o objeto ter sido liberado e antes de acionar a UAF. Após a chamada a tee_shm_get_from_id(), a função tee_shm_put() (para a qual ocorre a segunda falha UAF do syzkaller) é chamada, que desreferencia o objeto tee_shm:dmabuf usado como argumento de entrada para 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:~
O objeto `tee_shm` poderia ser realocado antes do UAF, pois pertence ao cache kmalloc-64. Ele teria que ser realocado com:

1. objetos `tee_shm`, `tee_shm:dmabuf`, `dma_buf:file` falsos
2. definir `file->f_count = 1`
3. criar um objeto `file:file_operations` que tenha o ponteiro de função `fasync` configurado para um endereço arbitrário

Esta função é então invocada em `__fput()` após a chamada para `dma_buf_put()` quando `file->f_count` atinge zero.

O PAN (Privileged Access Never) mitiga isso, pois objetos falsos devem ser referenciados na memória do espaço do usuário para definir um ponteiro de função arbitrário na estrutura `file:f_ops`. Portanto, `CONFIG_CPU_SW_DOMAIN_PAN` deve estar desabilitado para que isso funcione, o que está no ambiente fornecido. Restam algumas questões em aberto sobre se o PAN pode ser contornado nesta vulnerabilidade, por exemplo, usando ret2dir.

Além disso, para realizar uma realocação bem-sucedida do objeto shm liberado, a chamada IOCTL `TEE_IOC_OPEN_SESSION` ou `TEE_IOC_INVOKE` deve ser antecipada por uma thread que realiza o fechamento do descritor de arquivo e pela thread de heap spray que preenche o cache kmalloc-64. Para que isso funcione, o kernel deve estar configurado com `CONFIG_PREEMPT`. Neste PoC, foi utilizado o heap spray do post do blog de Nicolas Fabretti [7] baseado em `sendmsg()` bloqueante.

Resumindo, o problema em relação à exploração é que tanto a liberação quanto o UAF devem ocorrer dentro da mesma chamada de sistema. Além disso, a liberação é difícil de acionar, pois requer competição dentro da syscall. Após a liberação, o tempo entre ela e o UAF real é uma pequena janela de tempo onde um heap spray deve ser realizado para realocar o objeto liberado. A figura a seguir mostra as threads envolvidas no código do exploit e suas funções.

<p align="center">
  <img src="https://raw.githubusercontent.com/pjlantz/pjlantz.github.io/master/docs/assets/Threads.png?raw=true" alt="Threads envolvidas" width="50%" height="50%"/>
       <br /><em>Figura 3: Threads envolvidas no código do exploit</em>
</p>

  
Três tipos de threads estão sendo executados continuamente. Para antecipar a thread que faz a chamada de sistema, ela está sendo executada com a prioridade mais baixa possível, `SCHED_IDLE`, enquanto as outras têm a prioridade definida como `SCHED_OTHER`. Como estamos usando `sendmsg()` bloqueante, cada tentativa de spray deve ser executada em sua própria thread e deve ser executada no mesmo núcleo de CPU que aciona o UAF, pois cada núcleo mantém seus próprios caches kmalloc. Há também um número de threads de liberação que fecham o descritor de arquivo da alocação de memória compartilhada na etapa 1b). O código-fonte completo para este acionamento de UAF e sobrescrita de ponteiro de função pode ser encontrado em [10].

## Configurando o novo ambiente
Para reproduzir o ambiente com um kernel vulnerável e OPTEE, ele pode ser clonado do seguinte repositório e construído usando:```
$ 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

Após a build bem-sucedida, serão gerados três consoles, um para QEMU – pressione 'c' no console do QEMU para iniciar a inicialização. Um segundo console mostra a saída do mundo seguro e o último iniciará o Linux. Faça login como root (sem senha).

Execute o código de exploração até que o ponteiro de função fasync da estrutura file_operations seja definido como 0x22000000.``` until optee_exploit | grep "0x22000000" /var/log/messages; do sleep 0.01; done

root@kitploit:~
Isto irá parar devido ao Privileged execute-never (PXN) bloquear a execução em `PC=0x22000000`. A partir daqui, as estratégias de exploração podem variar dependendo da versão do kernel, mas pode ser possível executar um ROP do kernel e fazer stack pivoting, ou tornar a área vDSO gravável e colocar o payload lá. Também pode ser interessante para trabalhos futuros investigar se o PAN pode ser contornado usando ret2dir e algum physmap spraying. O PAN pode ser ativado no kernel definindo `CONFIG_CPU_SW_DOMAIN_PAN=y` em `linux/.config`. Em hardware real, ele é ativado por padrão no ARMv8.1 e AArch64, para ARMv7 e AArch32 é possível ter PAN emulado por software usando esta configuração [8]. 

**Nota**: Este exploit não é muito bem otimizado e pode ocasionalmente travar o driver se conseguir libertar o objeto de memória compartilhada demasiado cedo, neste caso o PC estará em `tee_shm_get_from_id()`. Se isto acontecer, execute um `system_reset` no console do QEMU para reiniciar o ambiente.

## Agradecimentos
Agradecimentos a Lars Persson da Axis Communications pela ajuda na análise da causa raiz e a Jens Wiklander da Linaro e mantenedor do subsistema TEE pela comunicação tranquila e rápida resolução deste problema [9].

## Referências 

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

[2] Subsistema TEE - https://www.kernel.org/doc/html/latest/staging/tee.html

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

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

[5] BKK16-110: Uma Introdução Gentil à Execução Confiável e OP-TEE - https://connect.linaro.org/resources/bkk16/bkk16-110/

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

[7] Blog de segurança da Lexfo, por Nicolas Fabretti: CVE-2017-11176: Uma exploração passo a passo do kernel Linux - https://blog.lexfo.fr/cve-2017-11176-linux-kernel-exploitation-part3.html

[8] Subsistema de Segurança do Kernel Linux: Métodos de Exploração/Uso de dados do espaço do usuário - http://kernsec.org/wiki/index.php/Exploit_Methods/Userspace_data_usage

[9] [PATCH v2] tee: lidar com a busca de shm com contagem de referência 0 - https://lore.kernel.org/lkml/[email protected]/T/ 

[10] Exploit de prova de conceito - https://github.com/pjlantz/optee_examples/tree/master/exploit/host
Baixar ferramenta