
Exploit pour CVE-2022-20452, élévation de privilèges sur Android depuis une application installée vers une application système (ou une autre application) via LazyValue utilisant Parcel après recycle()
Android 13 introduit de nombreuses améliorations afin de renforcer le mécanisme de sérialisation Parcel
Voici la présentation de l'équipe Android Security and Privacy sur les améliorations apportées
C'est excellent, cela élimine ou rend inexploitables de nombreuses vulnérabilités. Ils décrivent également comment casser mon précédent exploit, qui permettait aux applications de charger leur code dans d'autres applications (y compris celles du système)
Mais je reviens avec un nouvel exploit qui atteint le même résultat, bien que d'une manière différente. Il repose sur les vulnérabilités suivantes qui ont été introduites lors du durcissement susmentionné de Parcel:
![Capture d'écran de l'application affichant du texte. Titre: LeakValue. Texte principal: Créé 6 ValueLeaker-s. Verrouillage d'ActivityTaskManagerService. ActivityTaskManagerService verrouillé. Déverrouillage d'ActivityTaskManagerService. ActivityTaskManagerService déverrouillé. leakedBinders=[android.os.BinderProxy@f06702e]. Interface divulguée: android.app.IApplicationThread. Demande d'exécution de code. Le shellcode a été exécuté dans uid=1000 pid=6904 packageName=com.android.settings 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. En bas de l'écran se trouvent deux boutons: START et MANUAL TESTING](Screenshot_20220723-081920.png)
(Également logcat de l'exécution de l'application, l'exploitation est bruyante dans les journaux)
Parcel et ParcelableLa classe Parcel d'Android est la base de la communication entre les processus
Les objets peuvent implémenter l'interface Parcelable afin de pouvoir les écrire dans un Parcel, par exemple (copié depuis AOSP):```java
public class UsbAccessory implements Parcelable {
public static final Parcelable.Creator CREATOR =
new Parcelable.Creator() {
public UsbAccessory createFromParcel(Parcel in) {
String manufacturer = in.readString();
String model = in.readString();
String description = in.readString();
String version = in.readString();
String uri = in.readString();
IUsbSerialReader serialNumberReader = IUsbSerialReader.Stub.asInterface(
in.readStrongBinder());
return new UsbAccessory(manufacturer, model, description, version, uri,
serialNumberReader);
}
};
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mManufacturer);
parcel.writeString(mModel);
parcel.writeString(mDescription);
parcel.writeString(mVersion);
parcel.writeString(mUri);
parcel.writeStrongBinder(mSerialNumberReader.asBinder());
} }
Notez que `Parcel` stocke en interne la position à laquelle l'écriture ou la lecture est effectuée ; `readString()` analyse les données en une chaîne et avance également la position. Cette position peut être obtenue/définie manuellement via [`dataPosition()`](https://developer.android.com/reference/android/os/Parcel#dataPosition())/[`setDataPosition()`](https://developer.android.com/reference/android/os/Parcel#setDataPosition(int)). Les implémentations de l'interface `Parcelable` doivent garantir que leurs méthodes `writeToParcel` et `createFromParcel` écrivent/lisent la même quantité de données, sinon toutes les lectures suivantes obtiendront des données à partir de décalages incorrects
[`Bundle`](https://developer.android.com/reference/android/os/Bundle) (une carte clé-valeur pouvant être envoyée entre processus) peut contenir [une variété d'objets pouvant être écrits dans `Parcel` via `writeValue()`](https://cs.android.com/android/platform/superproject/+/android-12.1.0_r8:frameworks/base/core/java/android/os/Parcel.java;l=1792-1937). Lorsque le contenu d'un `Bundle` est lu depuis `Parcel`, toute classe `Parcelable` disponible dans le système peut être lue
`Bundle` diffère l'analyse réelle de son contenu : il écrit dans `Parcel` la longueur de l'intégralité des données sérialisées, puis [copie simplement la partie correspondante de la `Parcel` d'origine vers une `Parcel` secondaire stockée dans `mParcelledData`](https://cs.android.com/android/platform/superproject/+/android-12.1.0_r8:frameworks/base/core/java/android/os/BaseBundle.java;l=1675-1683) (cela permet par exemple à [`Activity.onSaveInstanceState()`](https://developer.android.com/reference/android/app/Activity#onSaveInstanceState(android.os.Bundle)) de fournir des `Parcelable` qui ne sont pas disponibles dans `system_server` ; le `Bundle` entier est ensuite transmis à `system_server` puis renvoyé tel quel sans analyse du contenu)
Cependant, dès qu'une valeur du `Bundle` était accédée, toutes les valeurs du `Bundle` étaient [désérialisées](https://cs.android.com/android/platform/superproject/+/android-12.1.0_r8:frameworks/base/core/java/android/os/BaseBundle.java;l=227-313) et [chaque paire clé-valeur présente était analysée](https://cs.android.com/android/platform/superproject/+/android-12.1.0_r8:frameworks/base/core/java/android/os/Parcel.java;l=3613-3632). Si une telle carte contenait un `Parcelable` dont les méthodes `writeToParcel` et `createFromParcel` étaient déséquilibrées, et que ce `Bundle` était ensuite transmis à un autre processus, cet autre processus pouvait voir un contenu différent du `Bundle`. Cela a transformé tous ces [écarts dans les classes disponibles dans le système en vulnérabilités](https://github.com/michalbednarski/ReparcelBug), car il existe des [endroits dans le système où le `Bundle` est inspecté pour être sûr](https://cs.android.com/android/platform/superproject/+/android-12.1.0_r8:frameworks/base/services/core/java/com/android/server/accounts/AccountManagerService.java;l=5037-5046) puis transmis à un autre processus
Dans cet article, j'appelle un tel `Bundle`, qui présente un contenu puis un autre après avoir été transmis, un `Bundle` auto-modifiable