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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2025-38352-PoC — PoC и GDB-скрипт для срабатывания CVE-2025-38352 | Kitploit
Инструменты/GitHubGitHub/longwasu/cve-2025-38352-poc
Криминалистика памятиАнализ уязвимостейЭксплуатацияОбратная инженерияОтладчикиСтатьи и ИсследованияОбучение и ОбразованиеЭксплуатация Бинарных Файлов
GitHublongwasu/cve-2025-38352-poc

CVE-2025-38352-PoC

PoC и GDB-скрипт для срабатывания CVE-2025-38352

Репозиторий
7 ч 9 мин назадЕщё не проверено

Популярное

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

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

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

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

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

CVE-2025-38352: Состояние гонки TOCTOU и UAF в подсистеме POSIX CPU-таймеров ядра Linux

Воспроизводимый Proof-of-Concept (PoC) и скрипт автоматизированной оркестрации GDB для CVE-2025-38352 — состояния гонки Time-of-Check to Time-of-Use (TOCTOU) в подсистеме POSIX CPU-таймеров ядра Linux (kernel/time/posix-cpu-timers.c), приводящего к Use-After-Free (UAF).

Отказ от ответственности: Этот проект предназначен исключительно для образовательных, защитных и исследовательских целей в области безопасности. Все тестирование и воспроизведение проводились в изолированной виртуальной машине ARM64 QEMU.


🧠 Как работает уязвимость

  1. Процесс A создаёт дочерний процесс B.

  2. Процесс B создаёт CPU-таймер и начинает завершение, переходя в состояние зомби. В момент завершения B на его ядре CPU приходит прерывание таймера. Ядро входит в контекст прерывания для обработки таймера, но временно освобождает свою блокировку (unlock_task_sighand), чтобы избежать взаимоблокировок.

  3. В этот же момент на другом ядре процесс A пожинает завершающийся B, очищая его обработчик сигналов (sighand = NULL) и удаляя его PID из хеш-таблицы.

  4. Другой поток в B вызывает удаление таймера (posix_cpu_timer_del). Он пытается найти задачу по её PID и проверить её обработчик сигналов, но обнаруживает, что они уже очищены / равны NULL. Ошибочно полагая, что задача полностью мертва и никакие таймеры не могут срабатывать, он считает, что всё безопасно, и освобождает таймер из памяти.

  5. Тем временем обработчик прерывания таймера на первом ядре возобновляет работу, чтобы запустить истёкший таймер. Поскольку таймер только что был освобождён на шаге 4, обращение к нему вызывает Use-After-Free и приводит к падению ядра.


🔬 Стратегия синхронизации (poc_gdb_script.py)

Поскольку GDB-стаб QEMU не поддерживает set non-stop on (остановка одного vCPU останавливает все vCPU), стандартная многопоточная синхронизация не может быть достигнута с помощью обычных точек останова.

Этот репозиторий решает проблему с помощью патчинга инструкций в памяти:

  1. Этап 1 (барьер CPU):

    • Точки останова устанавливаются на 4 критических функциях ядра:
      • exit_notify (CPU 2)
      • kernel_wait4 (CPU 0)
      • __arm64_sys_timer_delete (CPU 1)
      • handle_posix_cpu_timers (CPU 2)
    • Когда каждый vCPU достигает своей точки рандеву, GDB патчит его $pc опкодом самоперехода ARM64 0x14000000 (b . — бесконечный цикл) и возобновляет выполнение.
    • Как только все 4 vCPU зафиксированы в своих точных позициях, GDB восстанавливает исходные инструкции и передаёт управление Этапу 2.
  2. Этап 2 (последовательная оркестрация):

    • GDB блокирует планировщик (set scheduler-locking on) и продвигает каждый vCPU вперёд последовательно:
      • Шаг 1 (CPU 2): Продвинуть handle_posix_cpu_timers за unlock_task_sighand().
      • Шаг 2 (CPU 0): Продвинуть за .

🚀 Как воспроизвести

1. Загрузка исходников целевого ядра

Скачайте или клонируйте дерево исходников Android Common Kernel на коммите 1bf1aa362e6b9573a310fcd14f35bc875b42ba83:

root@kitploit:~
# Вариант A: Прямая загрузка tarball
curl -LO https://android.googlesource.com/kernel/common/+archive/1bf1aa362e6b9573a310fcd14f35bc875b42ba83.tar.gz
mkdir -p kernel-cve && tar -xzf 1bf1aa362e6b9573a310fcd14f35bc875b42ba83.tar.gz -C kernel-cve
cd kernel-cve

# Вариант B: Клонирование репозитория
git clone https://android.googlesource.com/kernel/common
cd common
git checkout 1bf1aa362e6b9573a310fcd14f35bc875b42ba83

2. Откат патча в run_posix_cpu_timers()

Откройте kernel/time/posix-cpu-timers.c, найдите функцию run_posix_cpu_timers() (примерно строки 1435–1448) и закомментируйте строки патча:

root@kitploit:~
void run_posix_cpu_timers(void)
{
    struct task_struct *tsk = current;

    lockdep_assert_irqs_disabled();

    /*
     * Ensure that release_task(tsk) can't happen while
     * handle_posix_cpu_timers() is running. Otherwise, a concurrent
     * posix_cpu_timer_del() may fail to lock_task_sighand(tsk) and
     * miss timer->it.cpu.firing != 0.
     */
//  if (tsk->exit_state)
//      return;

3. Отключение CONFIG_POSIX_CPU_TIMERS_TASK_WORK

Примечание: Когда CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y, CPU-таймеры выполняются из контекста task_work, а не из IRQ таймера, что обходит это состояние гонки. Поэтому для воспроизведения уязвимости его необходимо отключить.

Поскольку CONFIG_POSIX_CPU_TIMERS_TASK_WORK не имеет строки приглашения в upstream Kconfig, он по умолчанию равен y и не может быть переключён напрямую в menuconfig. Вы можете сделать его доступным следующим образом:

  1. В kernel/time/Kconfig (примерно строка 56) добавьте строку приглашения и измените значение по умолчанию:
    root@kitploit:~
    config POSIX_CPU_TIMERS_TASK_WORK
        bool "POSIX CPU timers task work"
        default n
    
  2. Сгенерируйте конфигурацию по умолчанию и отключите опцию:
    root@kitploit:~
    ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make defconfig
    scripts/config --disable POSIX_CPU_TIMERS_TASK_WORK
    ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make olddefconfig
    
  3. Убедитесь, что опция отключена в .config:
    root@kitploit:~
    grep POSIX_CPU_TIMERS_TASK_WORK .config
    # Ожидаемый вывод: # CONFIG_POSIX_CPU_TIMERS_TASK_WORK is not set
    

4. Сборка ядра

Скомпилируйте образ ядра ARM64:

root@kitploit:~
time ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make -j$(nproc) Image

5. Компиляция userspace PoC

Кросс-компилируйте poc.c:

root@kitploit:~
aarch64-linux-gnu-gcc -ggdb3 ./poc.c -o poc

6. Запуск QEMU с GDB-стабом

Запустите вашу виртуальную машину QEMU с 4 vCPU (-smp 4) и включите GDB-стаб (флаг -s, порт 1234):

root@kitploit:~
qemu-system-aarch64 \
    -M virt \
    -cpu cortex-a57 \
    -smp 4 \
    -m 2G \
    -kernel arch/arm64/boot/Image \
    -append "console=ttyAMA0 root=/dev/vda oops=panic panic_on_warn=1" \
    ... \
    -s

7. Подключение GDB и запуск скрипта

Из терминала вашего хоста подключите GDB к QEMU и загрузите скрипт оркестрации:

root@kitploit:~
gdb-multiarch vmlinux
pwndbg> target remote :1234
pwndbg> source poc_gdb_script.py
pwndbg> continue

8. Запуск уязвимости

Внутри гостевой оболочки QEMU запустите скомпилированный бинарник:

root@kitploit:~
./poc

[!TIP] Тайминг и устранение неполадок:
Если таймер срабатывает преждевременно, до того как целевой поток достиг состояния зомби, GDB выведет в лог:

root@kitploit:~
[!] ERROR: handle_posix_cpu_timers fired before exit_state == EXIT_ZOMBIE
  • Вариант 1: Просто перезапустите ./poc и несколько раз загрузите скрипт в GDB.
  • Вариант 2: Увеличьте TIMER_FIRE_MS в poc.c (например, с #define TIMER_FIRE_MS 10 до 20), перекомпилируйте poc.c и запустите снова. Это даст потоку дополнительное время, чтобы достичь exit_notify() и перейти в EXIT_ZOMBIE до истечения таймера.

9. Демонстрация

https://github.com/user-attachments/assets/11481b5c-25f8-46c3-be3a-7b79a06a4948


📚 Ссылки

  • Race Against Time in the Kernel Clockwork от StreyPaws
  • CVE-2025-38352 Root Cause Analysis от Faith
Скачать инструмент
kernel_wait4
tsk->sighand = NULL
  • Шаг 3 (CPU 1): Продвинуть timer_delete до вызова release_posix_timer() (освобождающего sigq).
  • Шаг 4 (CPU 2): Снять блокировку планировщика, чтобы позволить CPU 2 запустить освобождённый таймер $\rightarrow$ Падение!