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

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

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

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

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

Категории

Все категории
Loading categories
Инструменты/GitHubGitHub/michalbednarski/reparcelbug2
Безопасность AndroidПовышение привилегийАнализ уязвимостейЭксплуатацияМобильная безопасностьАнализ Бинарных Файлов
GitHubmichalbednarski/reparcelbug2

ReparcelBug2

Writeup и эксплойт для повышения привилегий установленного приложения до системных на Android 12 Beta через CVE-2021-0928, несоответствие сериализации `writeToParcel`/`createFromParcel` в `OutputConfiguration`

Популярное

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

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

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

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

Смотреть все инструменты →
Поделиться
Репозиторий
12524684 лет назадПроверено Kitploit

CVE-2021-0928, несоответствие сериализации writeToParcel/createFromParcel в android.hardware.camera2.params.OutputConfiguration

Это эксплойт, использующий данную уязвимость для повышения привилегий из установленного Android-приложения в приложение «Настройки» Android (или любое другое установленное приложение, которому можно отправить сообщение в <receiver>, объявленный в AndroidManifest.xml; повышение привилегий путём отправки в <activity> также было возможно, хотя здесь не представлено)

Изначально я обнаружил проблему в Android 12 Developer Preview 3

Версия эксплойта, представленная в этом репозитории, работает на Android 12 Beta 2 и 3

Уязвимость была исправлена в первом официальном выпуске Android 12

Описание ниже изначально было написано для Google для рассмотрения этого отчёта как полной цепочки эксплойта

На момент написания Android 12 не был доступен в AOSP (релизы Android Developer Preview/Beta не являются открытым исходным кодом)

Скриншот уведомления Android из приложения «Настройки»: Hello from uid=1000(system) gid=1000(system) groups=1000(system),1007(log),1065(reserved_disk),1077(external_storage),3001(net_bt_admin),3002(net_bt),3003(inet),3007(net_bw_acct),9997(everybody) context=u:r:system_app:s0

Введение в Parcel

Большая часть IPC в Android осуществляется через класс Parcel

Базовое использование Parcel выглядит следующим образом:```java Parcel p = Parcel.obtain(); p.writeInt(1); p.writeString("Hello");

Затем `Parcel` отправляется в другой процесс [через `Binder`](https://developer.android.com/reference/android/os/IBinder#transact(int,%20android.os.Parcel,%20android.os.Parcel,%20int)). Альтернативно для тестирования можно вызвать [`p.setDataPosition(0)`](https://developer.android.com/reference/android/os/Parcel#setDataPosition(int)), чтобы перемотать parcel в начальную позицию и начать чтение:```java
int a = p.readInt(); // a = 1
String b = p.readString(); // b = "Hello"

Следует отметить, что Parcel внутренне хранит позицию, с которой выполняются чтения. Ответственность пользователя класса Parcel заключается в том, чтобы методы read* соответствовали ранее использованным методам write*, иначе последующие чтения будут выполняться с неправильных позиций в буфере.

Parcel также предоставляет возможность записи пользовательских объектов, предпочтительный способ сделать это — реализация интерфейса Parcelable.

Вот пример реализации интерфейса Parcelable (нерелевантный код удалён, класс WindowContainerTransaction используется в эксплойте как часть цепочки гаджетов, однако с ним нет ничего плохого)```java package android.window; public final class WindowContainerTransaction implements Parcelable { private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>(); private final ArrayList mHierarchyOps = new ArrayList<>();

private WindowContainerTransaction(Parcel in) {
    in.readMap(mChanges, null /* loader */);
    in.readList(mHierarchyOps, null /* loader */);
}

@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
    dest.writeMap(mChanges);
    dest.writeList(mHierarchyOps);
}

@NonNull
public static final Creator<WindowContainerTransaction> CREATOR =
        new Creator<WindowContainerTransaction>() {
            @Override
            public WindowContainerTransaction createFromParcel(Parcel in) {
                return new WindowContainerTransaction(in);
            }
        };

}

As can be seen above, `writeToParcel()` method is used during writing. Then while reading `CREATOR.createFromParcel()` factory method is called. It is responsibility of `Parcelable` implementation to ensure that `createFromParcel` reads same amount of data as was written by `writeToParcel`, otherwise all subsequent reads from that `Parcel` will read data from wrong offset

Such class can be written to/read from `Parcel` through:

* Directly calling `obj.writeToParcel(parcel, 0)` / `obj = WindowContainerTransaction.CREATOR.createFromParcel()`, this is often used when type of class is known, for example when `Parcelable` has field with different `Parcelable` or in code generated by AIDL when defined RPC method has `Parcelable` as argument
* Through `Parcel.writeParcelable`/`readParcelable`. [`writeParcelable`](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/os/Parcel.java;l=1909;drc=58787794eb5c879f6e39ee58c0071b36e337f8e3) first writes name of class and then calls `writeToParcel` method from `Parcelable` interface. [`readParcelable`](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/os/Parcel.java;l=3282;drc=58787794eb5c879f6e39ee58c0071b36e337f8e3) reads written class name, finds class with that name in provided `ClassLoader` or `BOOTCLASSPATH` if null was provided. Once class is found it's static field `CREATOR` is used to obtain [`Parcelable.Creator`](https://developer.android.com/reference/android/os/Parcelable.Creator) instance which is factory used to read that class. It is important to note that when `readParcelable` method is used it can read any `Parcelable` available in class path as name of object to be created is read from same `Parcel`
* `readParcelable` is used by many other `Parcel` methods, for example `readList` seen in example above reads elements through `readValue`, which is most generic method of transferring objects in `Parcel` and one of ways it uses is through `readParcelable`. Also in above example due to Java's Type Erasure `ArrayList<HierarchyOp> mHierarchyOps` field can actually contain any objects supported by Parcel, not only those compatible with type specified in generic type declaration

# Несоответствия `writeToParcel`/`createFromParcel`

Как отмечено выше, именно реализация интерфейса `Parcelable` обязана гарантировать, что `createFromParcel` считывает из `Parcel` тот же объём данных, который ранее был записан соответствующим `writeToParcel`. Всякий раз, когда в `BOOTCLASSPATH` существует `Parcelable`, способный нарушить этот контракт, это создаёт уязвимость, поскольку позволяет реализовать следующий сценарий:

1. Вредоносное приложение отправляет в `system_server` `Bundle` ИЛИ `Parcelable`, содержащий повреждённый экземпляр `Parcelable`, вместе со специально сконструированными данными, которые будут фактически прочитаны на шаге 3, но переданы без изменений на шаге 2
2. `system_server` проверяет, что `Bundle` безопасен, и пересылает его ИЛИ `system_server` передаёт предоставленный `Parcelable` в метод AIDL, который также получает критически важные данные в следующем параметре (если бы данные, полученные в этом параметре, можно было изменить, это вызвало бы проблему безопасности)
3. Другое приложение получает данные от `system_server` и доверяет им, однако из-за некорректной сериализации данные, которые оно фактически видит, отличаются от данных, которые `system_server` намеревался отправить

Я использовал "ИЛИ" в приведённых шагах, поскольку эти шаги описывают как [старый вариант эксплуатации, который приводит к запуску произвольного Activity и который я опубликовал в 2017 году](https://github.com/michalbednarski/ReparcelBug) (слева от "ИЛИ"), так и новый вариант, который я опишу здесь в следующем разделе

# Как `BroadcastReceiver` выполняется в приложении
Скачать инструмент