
Exploit para CVE-2022-20452, escalada de privilégios no Android de um aplicativo instalado para aplicativo de sistema (ou outro aplicativo) via LazyValue usando Parcel após recycle()
Android 13 introduz muitas melhorias para endurecer o mecanismo de serialização Parcel
Aqui está a apresentação da equipe de Segurança e Privacidade do Android sobre as melhorias feitas
Isso é ótimo, definitivamente elimina ou torna inexploráveis muitas vulnerabilidades. Além disso, eles descrevem como quebrar meu exploit anterior, que permitia que aplicativos carregassem seu código em outros aplicativos (incluindo os do sistema)
Mas agora estou de volta com um novo exploit que alcança o mesmo, embora de forma diferente. Ele depende das seguintes vulnerabilidades que foram introduzidas durante o endurecimento do Parcel mencionado:
![Captura de tela do aplicativo exibindo texto. Título: LeakValue. Texto principal: Created 6 ValueLeaker-s. Locking ActivityTaskManagerService. Locked ActivityTaskManagerService. Unlocking ActivityTaskManagerService. Unlocked ActivityTaskManagerService. leakedBinders=[android.os.BinderProxy@f06702e]. Leaked interface: android.app.IApplicationThread. Requesting code execution. Shellcode has been executed in 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. Na parte inferior da tela, há dois botões: START e MANUAL TESTING](Screenshot_20220723-081920.png)
(Também logcat da execução do aplicativo, a exploração é barulhenta nos logs)
Parcel e ParcelableA classe Parcel do Android é a base da comunicação entre processos
Objetos podem implementar a interface Parcelable para permitir que sejam escritos em um Parcel, por exemplo (copiado do 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());
} }
Note que `Parcel` internamente armazena a posição na qual a escrita ou leitura é realizada; `readString()` analisa dados em String e também avança a posição. Essa posição pode ser obtida/definida manualmente através de [`dataPosition()`](https://developer.android.com/reference/android/os/Parcel#dataPosition())/[`setDataPosition()`](https://developer.android.com/reference/android/os/Parcel#setDataPosition(int)). Implementações da interface `Parcelable` devem garantir que seus métodos `writeToParcel` e `createFromParcel` escrevam/leiam a mesma quantidade de dados; caso contrário, todas as leituras subsequentes obterão dados com deslocamentos incorretos
[`Bundle`](https://developer.android.com/reference/android/os/Bundle) (mapa chave-valor que pode ser enviado entre processos) pode conter [uma variedade de objetos que podem ser escritos em Parcel através de `writeValue()`](https://cs.android.com/android/platform/superproject/+/android-12.1.0_r8:frameworks/base/core/java/android/os/Parcel.java;l=1792-1937). Quando o conteúdo de `Bundle` é lido de `Parcel`, qualquer classe `Parcelable` disponível no sistema pode ser lida
`Bundle` adia a análise real do conteúdo ao ter o comprimento de todos os dados empacotados escritos em `Parcel` e então apenas [copiando a parte relevante do Parcel original para um Parcel secundário armazenado em `mParcelledData`](https://cs.android.com/android/platform/superproject/+/android-12.1.0_r8:frameworks/base/core/java/android/os/BaseBundle.java;l=1675-1683) (isso permite, por exemplo, que [`Activity.onSaveInstanceState()`](https://developer.android.com/reference/android/app/Activity#onSaveInstanceState(android.os.Bundle)) forneça `Parcelable`s que não estão disponíveis em `system_server`; o `Bundle` inteiro é então passado para `system_server` e de volta sem análise do conteúdo)
No entanto, uma vez que qualquer valor em `Bundle` foi acessado, todos os valores dentro de `Bundle` [eram desempacotados](https://cs.android.com/android/platform/superproject/+/android-12.1.0_r8:frameworks/base/core/java/android/os/BaseBundle.java;l=227-313) e [cada par chave-valor presente era analisado](https://cs.android.com/android/platform/superproject/+/android-12.1.0_r8:frameworks/base/core/java/android/os/Parcel.java;l=3613-3632). Se tal mapa contivesse um `Parcelable` com métodos `writeToParcel` e `createFromParcel` desequilibrados e, posteriormente, tal `Bundle` fosse encaminhado para outro processo, esse outro processo poderia ver conteúdo diferente do `Bundle`. Isso tornou todas essas [incompatibilidades em classes disponíveis em vulnerabilidades do sistema](https://github.com/michalbednarski/ReparcelBug), pois existem [lugares no sistema onde o `Bundle` é inspecionado para ser seguro](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) e então encaminhado para outro processo
Neste artigo, chamo tal `Bundle` que apresenta um conteúdo e depois outro após ser encaminhado de `Bundle` auto-alterável