Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
optee-qemu — Среда с уязвимым ядром для эксплуатации драйвера TEE (CVE-2021-44733) | Kitploit
Инструменты/GitHubGitHub/pjlantz/optee-qemu
Безопасность встроенных системАнализ уязвимостейЭксплуатацияФаззингОбучение и ОбразованиеЭксплуатация Бинарных ФайловЛаборатории и Практика
GitHubpjlantz/optee-qemu

optee-qemu

Среда с уязвимым ядром для эксплуатации драйвера TEE (CVE-2021-44733)

Репозиторий
76114 лет назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2021-44733: Фаззинг и эксплуатация use-after-free в подсистеме TEE ядра Linux

Недавно была обнаружена уязвимость use-after-free в подсистеме TEE ядра Linux, вплоть до версии 5.15.11 включительно, которой был присвоен идентификатор CVE-2021-44733 [1].

На первый взгляд она казалась неэксплуатируемой по нескольким причинам, однако после дальнейшего анализа уязвимого пути кода и реализации чернового эксплойта proof-of-concept стало возможным перезаписать указатель на функцию в ядре. В этой статье не представлена полезная нагрузка для повышения привилегий, однако вся среда для запуска OPTEE и эксплойта доступна для дальнейшего тестирования, см. «Настройка среды».

Предыстория

TEE (Trusted Execution Environment) — это доверенная ОС, работающая в некотором безопасном окружении, например, TrustZone на процессорах ARM. Драйвер TEE обрабатывает детали, необходимые для взаимодействия с TEE. Одними из наиболее важных задач драйвера являются предоставление общего API к TEE на основе спецификации Globalplatform TEE Client API [3], а также управление разделяемой памятью между Linux и TEE. Эта подсистема может быть включена с помощью конфигурации CONFIG_OPTEE в настройках ядра для архитектур ARM.

В защищенном мире работает доверенная ОС, обозначаемая как OP-TEE OS [4]. Поверх этой ОС могут работать так называемые доверенные приложения (Trusted Applications, TAs), которые могут выполнять некоторые операции в изолированной среде, см. Рисунок 1.

Обзор TEE
Рисунок 1: Обзор TEE — из презентации Linaro [5]

Обычный мир (пространство пользователя/ядро Linux) может взаимодействовать с этими приложениями с помощью клиентских приложений (CAs) и API, предоставляемого подсистемой TEE. CA может открыть сессию к конкретному TA и вызывать функции, которые реализует TA. Передача любых аргументов между TA и CA осуществляется с использованием разделяемой памяти. Далее описывается взаимодействие между CA и TA с использованием всех соответствующих системных вызовов.

  1. CA открывает /dev/tee[0-9] для связи с драйвером. Обратите внимание, что для обычного способа использования этих API это делается неявно с помощью libteec.

  2. Разделяемая память может быть зарегистрирована CA с помощью IOCTL TEE_IOC_SHM_ALLOC. Это выделяет разделяемую память и возвращает файловый дескриптор, который пространство пользователя может использовать как часть mmap.

  3. Следующий шаг — установление сессии с помощью IOCTL TEE_IOC_OPEN_SESSION с указанием uuid конкретного TA. Этот uuid жестко закодирован во время компиляции TA.

  4. Чтобы вызвать любую конкретную функцию в TA, CA вызывает это, указывая идентификатор функции вместе с входными аргументами; это делается с помощью TEE_IOC_INVOKE.

  5. Когда CA завершает все запросы, сессия может быть закрыта с помощью TEE_IOC_CLOSE_SESSION.

Сессия между CA и TA
Рисунок 2: Сессия между CA и TA — из презентации Linaro [5]

Большая часть взаимодействия между клиентами и TEE является непрозрачной для драйвера. Основная задача драйвера — управление контекстом, получение запросов от клиентов, их пересылка в TEE и отправка результатов обратно [2].

Фаззинг драйвера TEE

CVE-2021-44733 была обнаружена с помощью фаззинга с использованием syzkaller. Файл описания, использованный для этого, приведен ниже. Обратите внимание, что ioctl$TEE_SHM_REGISTER_FD является частью только дерева ядра Linaro (мейнтейнеров) и отсутствует в upstream. Среда, предоставленная в разделе «Настройка среды», может быть использована для фаззинга при правильной настройке в соответствии с документацией 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:~
Во время фаззинга краш, который привлек внимание, был связан с use-after-free объекта task_struct при удержании mutex:```
==================================================================
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
==================================================================

Это было вызвано закрытием всех файловых дескрипторов из TEE_IOC_SHM_ALLOC в то время, как другой поток открывает сессию к, в нашем случае, несуществующему TA. Syzkaller удалось воспроизвести это, и, экспериментируя с кодом репродуктора и слегка задерживая вызов TEE_IOC_OPEN_SESSION, возникла другая UAF для объекта, принадлежащего кэшу 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:~
Эта уязвимость была обнаружена при фаззинге драйвера TEE без установления какой-либо сессии с существующим TA, работающим в системе. Это можно расширить с помощью так называемых псевдо-системных вызовов в syzkaller для настройки и инициирования сессии с некоторым TA.

## Анализ первопричины

Вывод заключается в проблеме проектирования отслеживания времени жизни объекта `tee_shm:dmabuf`. Драйвер спроектирован так, чтобы позволить пользовательскому пространству удерживать единственную ссылку после вызова `tee_ioctl_shm_alloc()`.

Предполагается, что если объект всё ещё находится в IDR-объекте драйвера, то ссылка на dmabuf всё ещё действительна, и её счётчик ссылок можно увеличить. Оказывается, это верно лишь отчасти. Память dmabuf по-прежнему принадлежит драйверу dmabuf, но она может находиться в процессе уничтожения, и это невозможно остановить повторным увеличением счётчика ссылок.

Сценарий, вызывающий проблему, — это многопоточное приложение, в котором один поток закрывает файловый дескриптор dmabuf в то же время, когда другой поток выполняет вызов команды IOCTL `TEE_IOC_OPEN_SESSION` или `TEE_IOC_INVOKE`, ссылаясь на эту общую память.

Прослеживание уничтожения dmabuf, когда пользовательское пространство закрывает fd, приводит к выполнению следующего кода в ядре:

1. `fput()`

2. `fput_many()`  >> Счётчик ссылок на файл достигает нуля. Окно гонки открывается.

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)` >> Теперь объект shm больше нельзя получить из пользовательского пространства. Окно гонки закрывается.

     10. `mutex_unlock()`
  
Это означает, что таблица IDR и её мьютекс не могут гарантировать, что dmabuf и соответствующий `tee_shm` всё ещё живы. Процесс, конкурирующий с `fput()` при вызове `tee_shm_get_from_id()`, может получить ссылку на shm, который собирается стать мёртвым.```
/**
 * 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;
}

Эксплуатация UAF

Для эксплуатации этой уязвимости необходимо выполнить перераспределение после того, как объект был освобожден и до вызова UAF. После вызова tee_shm_get_from_id() вызывается функция tee_shm_put() (для которой происходит второй сбой UAF от syzkaller), которая разыменовывает объект tee_shm:dmabuf, используемый в качестве входного аргумента для 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:~
Объект `tee_shm` может быть перераспределён до UAF, так как он принадлежит к кешу kmalloc-64. Его нужно будет перераспределить с:

1. поддельными объектами `tee_shm`, `tee_shm:dmabuf`, `dma_buf:file`
2. установить `file->f_count = 1`
3. создать объект `file:file_operations`, у которого указатель на функцию `fasync` установлен на произвольный адрес

Эта функция вызывается в `__fput()` после вызова `dma_buf_put()`, когда `file->f_count` достигает нуля.

PAN (Privileged Access Never) смягчает эту атаку, так как поддельные объекты должны быть расположены в пользовательской памяти, чтобы установить произвольный указатель функции в структуре `file:f_ops`. Поэтому для работы этой атаки необходимо отключить `CONFIG_CPU_SW_DOMAIN_PAN`, что и сделано в предоставленной среде. Остаются открытые вопросы, можно ли обойти PAN в этой уязвимости, например, с помощью ret2dir.

Кроме того, для успешного перераспределения освобождённого объекта shm вызов IOCTL `TEE_IOC_OPEN_SESSION` или `TEE_IOC_INVOKE` должен быть вытеснен потоком, выполняющим закрытие файлового дескриптора, и потоком heap spraying, который заполняет кеш kmalloc-64. Для этого ядро должно быть скомпилировано с `CONFIG_PREEMPT`. В данной PoC использовался heap spray из статьи Nicolas Fabretti [7], основанный на блокирующем `sendmsg()`.

Таким образом, проблема с эксплуатацией заключается в том, что и освобождение, и UAF должны произойти в одном и том же системном вызове. Кроме того, освобождение сложно вызвать, так как требует гонки внутри системного вызова. После освобождения между ним и фактическим UAF остаётся небольшое временное окно, в течение которого необходимо выполнить heap spray для перераспределения освобождённого объекта. На следующем рисунке показаны потоки, участвующие в коде эксплойта, и их роли.

<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>Рисунок 3: Потоки, участвующие в коде эксплойта</em>
</p>

  
Непрерывно работают три типа потоков. Чтобы вытеснить поток, выполняющий системный вызов, он работает с наименьшим возможным приоритетом `SCHED_IDLE`, в то время как другие имеют приоритет `SCHED_OTHER`. Поскольку мы используем блокирующий `sendmsg()`, каждая попытка spray должна выполняться в собственном потоке и на том же ядре CPU, которое вызывает UAF, так как каждое ядро поддерживает собственные кеши kmalloc. Также существует несколько потоков освобождения, которые закрывают файловый дескриптор из выделения разделяемой памяти на шаге 1b). Полный исходный код для этого триггера UAF и перезаписи указателя функции можно найти в [10].

## Настройка новой среды
Чтобы воспроизвести среду с уязвимым ядром и OPTEE, её можно склонировать из следующего репозитория и собрать с помощью:```
$ 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

После успешной сборки будут запущены три консоли: одна для QEMU - нажмите 'c' в консоли QEMU для загрузки. Вторая консоль показывает вывод из защищенного мира, а последняя загрузит Linux. Войдите как root (без пароля).

Запустите код эксплойта до тех пор, пока указатель на функцию fasync в структуре file_operations не будет установлен в 0x22000000.``` until optee_exploit | grep "0x22000000" /var/log/messages; do sleep 0.01; done

root@kitploit:~
Это будет остановлено из-за блокировки выполнения Privileged execute-never (PXN) по адресу `PC=0x22000000`. Дальнейшие стратегии эксплуатации могут различаться в зависимости от версии ядра, но возможно выполнить ROP ядра и сделать pivot стека, или сделать область vDSO доступной для записи и разместить там полезную нагрузку. Также может представлять интерес для будущих исследований — возможно ли обойти PAN с помощью ret2dir и распыления physmap. PAN можно включить в ядре, установив `CONFIG_CPU_SW_DOMAIN_PAN=y` в `linux/.config`. На реальном оборудовании он включён по умолчанию на ARMv8.1 и AArch64, для ARMv7 и AArch32 возможно программное эмулирование PAN с помощью этой настройки [8].

**Примечание**: Этот эксплойт не очень хорошо оптимизирован и иногда может «повесить» драйвер, если ему удастся освободить объект разделяемой памяти слишком рано; в этом случае PC будет находиться в `tee_shm_get_from_id()`. Если это произойдёт, выполните `system_reset` в консоли QEMU для перезагрузки окружения.

## Благодарности
Спасибо Ларсу Перссону (Lars Persson) из Axis Communications за помощь в анализе первопричины и Йенсу Викландеру (Jens Wiklander) из Linaro, мейнтейнеру подсистемы TEE, за гладкое общение и быстрое решение этой проблемы [9].

## Ссылки

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

[2] Подсистема 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: A Gentle Introduction to Trusted Execution and OP-TEE - https://connect.linaro.org/resources/bkk16/bkk16-110/

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

[7] Блог по безопасности Lexfo, автор Nicolas Fabretti: CVE-2017-11176: Пошаговая эксплуатация ядра Linux - https://blog.lexfo.fr/cve-2017-11176-linux-kernel-exploitation-part3.html

[8] Subsystem безопасности ядра Linux: Методы эксплуатации/Использование данных пользовательского пространства - 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] Proof of concept exploit - https://github.com/pjlantz/optee_examples/tree/master/exploit/host
Скачать инструмент