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

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

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

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

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

Категории

Все категории
Loading categories
android-badbinder-demo — демонстрация CVE-2019-2215 (Bad Binder) для Android Q | Kitploit
Инструменты/GitHubGitHub/i-redbyte/android-badbinder-demo
Безопасность AndroidПовышение привилегийЭксплуатацияОбучение и ОбразованиеЭксплуатация Бинарных Файлов
GitHubi-redbyte/android-badbinder-demo

android-badbinder-demo

демонстрация CVE-2019-2215 (Bad Binder) для Android Q

Репозиторий
514211 месяцев назадЕщё не проверено

Популярное

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

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

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

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

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

CVE-2019-2215 (Bad Binder) — Анализ эксплойта

Этот репозиторий — небольшой тестовый проект по исследованию уязвимости
CVE-2019-2215 (Bad Binder) и написанию рабочего прототипа эксплойта под Android с простым графическим интерфейсом на Kotlin/Jetpack Compose.

В README я:

  1. Описываю подготовку среды и запуск прототипа эксплойта.
  2. Разбираю основные этапы эксплуатации CVE-2019-2215 и сопоставляю их с конкретными функциями в C-коде.
  3. Отдельно перечисляю трудности, на которые я наткнулся по пути, и как я их решал.

Готовый APK (GitHub Actions)

В репозитории настроен GitHub Actions workflow, который при каждом push/PR собирает проект командой ./gradlew assembleDebug и публикует готовый badbinder-debug.apk как артефакт.

Скачать его можно так:

  1. Открыть вкладку Actions в репозитории.
  2. Выбрать нужный запуск workflow.
  3. Внизу страницы найти секцию Artifacts и забрать архив badbinder-debug-apk с собранным APK.

Это сделано для удобства, если хочется просто потестировать приложение, не поднимая локальную среду.


Кратко про уязвимость

CVE-2019-2215 — это Use-After-Free (UAF) в IPC-подсистеме Binder ядра Android.

Упрощённо:

  • в ядре существует структура struct binder_thread, которая описывает поток, выполняющий Binder-вызовы;
  • эта структура может быть освобождена (free), но при определённой последовательности вызовов всё ещё остаётся в списках ожидания (waitqueue);
  • позднее ядро пытается работать с уже освобождённой памятью в remove_wait_queue, что открывает классический UAF-сценарий;
  • если аккуратно подобрать окружение и последующие аллокации, можно заставить ядро читать/писать по произвольным адресам, а дальше — получить привилегии ядра, а затем и root в userspace.

Более подробный теоретический разбор я делал по материалам:

  1. https://cloudfuzz.github.io/android-kernel-exploitation/
  2. https://dayzerosec.com/blog/2019/11/07/analyzing-androids-cve-2019-2215-dev-binder-uaf.html
  3. https://hernan.de/blog/tailoring-cve-2019-2215-to-achieve-root/

1. Подготовка среды и запуск прототипа эксплойта

1.1. Выбор и подготовка виртуального устройства

По заданию рекомендовано использовать AVD с образом Android 10.0 (Q) x86_64.
Я сделал следующее:

  1. В Android Studio создал AVD (Pixel-устройство, Android 10 (Q), x86_64).
  2. Убедился, что в образе включён Binder и есть устройство /dev/binder.
  3. Активировал отладку по USB/ADB и проверил доступ к устройству:
    adb shell
    ls -l /dev/binder
    

На этом этапе я столкнулся с неприятным фактом:
на данный момент актуальные образы AVD уже поставляются с пропатченным ядром, в котором CVE-2019-2215 закрыта. То есть реально получить root на современном официальном эмуляторе не удастся — эксплойт падает на более поздних стадиях или просто не даёт повышения привилегий.

В итоге я использую AVD как тренажёр для воспроизведения логики эксплойта:

  • я получаю те же последовательности системных вызовов,
  • наблюдаю попытки UAF, утечку адресов и попытку переписать addr_limit,
  • а вот финальное «получение root» на актуальном, пропатченном ядре, естественно, не срабатывает (и это ожидаемо).

Это важный нюанс: весь код и отчёт ниже — учебные, а не «боевые».


1.2. Сборка Android-приложения с нативным эксплойтом

Я сделал небольшое Android-приложение:

  • UI на Kotlin + Jetpack Compose,
  • Native-часть на C через JNI — собственно код эксплойта,
  • общение между ними — через JNI-колбэк, чтобы строки из C-кода улетали прямо в UI.

Основные шаги:

  1. Создал обычный проект в Android Studio (Kotlin, минимальная поддержка Android 10).

  2. Подключил NDK и CMake.

  3. Добавил нативный файл с эксплойтом (тот самый cve-2019-2215.c с функциями leak_task_struct, overwrite_addr_limit, и т.д.).

  4. В CMakeLists.txt добавил сборку libcve-2019-2215.so.

  5. В MainActivity:

    init {
        System.loadLibrary("cve-2019-2215")
    }
    
    external fun runNativeExploit(): String
    external fun setNativeLogger(logger: NativeLogger)
    
  6. На стороне Kotlin сделал ExploitViewModel, который реализует интерфейс NativeLogger и складывает все сообщения в StateFlow<List<String>>. UI подписан на этот поток и выводит лог в «терминале».

При старте активити я вызываю setNativeLogger(viewModel), чтобы нативный код получил объект, в который можно слать строки.


1.3. Запуск и сценарий использования

  1. Собираю и устанавливаю приложение:

    ./gradlew installDebug
    
  2. Запускаю AVD и само приложение.

  3. На экране вижу «терминал» и кнопку RUN EXPLOIT.

  4. При нажатии:

    • Kotlin вызывает runNativeExploit() в фоновом потоке.
    • C-код начинает выполнять все этапы эксплойта и логировать шаги.
    • Через JNI-колбэк лог попадает в ViewModel и отображается в Compose-UI.

На реальном уязвимом ядре я ожидал бы в конце увидеть что-то вроде:

[+] Selinux changed: Permissive now.
[+] Root escalation successful!
uid=0(root)...

На актуальном эмуляторе Android 10 этого, разумеется, не происходит, но всё остальное — утечка task_struct, попытка переписать addr_limit, вычисление cred и kernel_base — отрабатывает как «сценарий», что и требовалось для задания.


2. Разбор основных этапов эксплойта и сопоставление с кодом

Ниже — логическая схема эксплойта с привязкой к конкретным C-функциям.

2.1. Общий сценарий эксплойта

Высокоуровневый план такой:

  1. Создать UAF на объекте struct binder_thread и использовать его, чтобы утечь адрес task_struct своего процесса (leak_task_struct).
  2. Вторым UAF-циклом и аккуратно подобранными структурами переписать поле addr_limit в task_struct (overwrite_addr_limit) — это снимает ограничение между адресами user-space и kernel-space для дальнейших copy_to_user / copy_from_user.
  3. Используя пайпы, реализовать произвольное чтение/запись любой памяти ядра (arb_read / arb_write).
  4. С помощью этого найти cred текущего процесса и базу ядра (verifying), затем:
    • выключить SELinux (selinux_enforcing = 0),
    • переписать поля cred, чтобы стать root и получить полный набор capability (runNativeExploit).

Параллельно я интегрировал JNI-логгер, чтобы все эти этапы было видно прямо в UI.


2.2. Этап 1 — утечка адреса task_struct (leak_task_struct)

Ключевая функция:

void leak_task_struct() {
    android_log("[*] Starting leak_task_struct...");

    cpu_set_t cpu_set;
    CPU_ZERO(&cpu_set);
    CPU_SET(0, &cpu_set);
    ret = sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
    assert(ret >= 0);
    ...
}

Что делает функция:

  1. Фиксирует поток на CPU 0 (sched_setaffinity), чтобы поведение аллокатора ядра было более предсказуемым. Это улучшает стабильность эксплуатации UAF.

  2. Открывает /dev/binder, создаёт epoll-дескриптор:

    fd = open("/dev/binder", O_RDONLY);
    epfd = epoll_create(1000);
    

    Binder-дескриптор регистрируется в epoll:

    epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
    
  3. Готовит массив struct iovec iov_buffers[IOVEC_N] и выделяет память:

    spinner = mmap((void *)0x100000000, page_size, PROT_READ | PROT_WRITE,
                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    

    Здесь важно, чтобы младшие 32 бита адреса были нулями:

    if (((long) spinner & 0xffffffff) != 0) {
        android_log("[!] mmap returned wrong address!");
        return;
    }
    

    Это соответствует технике из статей по эксплуатации: далее ядро интерпретирует часть наших данных как структуры с указателями, и такая «красиво выровненная» адресация упрощает злоупотребление.

    Затем поля iov_buffers[0xa] и iov_buffers[0xb] заполняются так, чтобы в момент UAF ядро скопировало в пайп кусок памяти, где лежит указатель на task_struct.

Скачать инструмент