Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
TheLastBundleMismatch — Writeup et exploit pour CVE-2023-45777, contournement de la validation d'Intent dans AccountManagerService sur Android 13 malgré l'atténuation « Lazy Bundle » | Kitploit
Outils/GitHubGitHub/michalbednarski/thelastbundlemismatch
Sécurité AndroidAnalyse des VulnérabilitésExploitationAnalyse de BinairesArticles et Recherche
GitHubmichalbednarski/thelastbundlemismatch

TheLastBundleMismatch

Writeup et exploit pour CVE-2023-45777, contournement de la validation d'Intent dans AccountManagerService sur Android 13 malgré l'atténuation « Lazy Bundle »

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager
Voir le dépôt
1011467il y a 2 ansVérifié par Kitploit

Correctif mystérieux

Commençons cette fois-ci par le correctif apparu comme solution pour CVE-2023-45777 dans le Bulletin de sécurité Android :```diff diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 7a19d034c2c8..5238595fe2a2 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -4923,7 +4923,7 @@ public class AccountManagerService p.setDataPosition(0); Bundle simulateBundle = p.readBundle(); p.recycle();

  •        Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
    
  •        Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT, Intent.class);
           if (intent != null && intent.getClass() != Intent.class) {
               return false;
           }
    
Peu de personnes ont été assez intriguées pour me le demander ; auparavant, je leur avais répondu avec quelques indices, et maintenant je publie l'analyse complète de ce problème.

Mais d'abord, apportons un peu de contexte sur ce qui se passe dans ce correctif.

Il s'agit d'un changement dans la [méthode `checkKeyIntent()`](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/services/core/java/com/android/server/accounts/AccountManagerService.java;l=4938-4954;drc=47de64a38aa1799cb41f41b2ea0c539ee61de64d). Cette méthode effectue plusieurs vérifications pour s'assurer que l'`Intent` fourni par l'application est sûr pour que le système le lance (en utilisant les privilèges du système).

Tout d'abord, cette méthode utilise `checkKeyIntentParceledCorrectly()`, qui sérialise puis désérialise à nouveau le `Bundle` que nous vérifions, et s'assure que l'`Intent` extrait du `Bundle` avant cela correspond à l'`Intent` du `Bundle` après un tel cycle. Étant donné que le lancement de l'`Intent` se produit dans d'autres processus d'applications système que celui qui effectue la validation, il était auparavant [possible de construire des `Bundle` qui semblaient sûrs lors de la validation dans `AccountManagerService`, mais qui contenaient un `Intent` différent après avoir été envoyés au processus suivant](https://github.com/michalbednarski/IntentsLab/issues/2#issuecomment-344365482). Cela simule l'envoi du `Bundle` au processus suivant afin de détecter de telles situations.

Après `checkKeyIntentParceledCorrectly()`, nous avons l'appel `bundle.getParcelable()`, que ce correctif fait passer de la version obsolète qui pouvait construire n'importe quel objet à une version qui valide que l'objet sur le point d'être désérialisé est du type spécifié dans le second paramètre.

Cette version avec paramètre de type a été introduite dans Android 13, dans le cadre d'un durcissement plus large de `Parcel`/`Bundle`. En particulier, avant Android 13, lorsqu'un `Bundle` était envoyé entre processus, il conservait une copie brute de l'intégralité des données sérialisées jusqu'à ce qu'un élément soit accédé, moment auquel chaque valeur était désérialisée. Désormais, lorsqu'une valeur est accédée pour la première fois après la réception du `Bundle`, seules les clés `String` et les valeurs de types primitifs sont désérialisées, tandis que les valeurs non primitives sont laissées sous forme de `LazyValue`, dont la longueur est stockée dans les données sérialisées afin de garantir que même en cas de désynchronisation de la logique de sérialisation/désérialisation, ces désynchronisations n'affectent pas les autres entrées.

Avant d'entrer dans le vif du sujet, examinons `LazyValue` : dans son code source, [nous avons un joli commentaire expliquant sa structure de données](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/os/Parcel.java;l=4392-4399;drc=03c34f57c05feecfb090de3917787f049cb5f804).```
                     |   4B   |   4B   |
mSource = Parcel{... |  type  | length | object | ...}
                     a        b        c        d
length = d - c
mPosition = a
mLength = d - a

mPosition et mLength décrivent l'emplacement de l'ensemble des données LazyValue dans le Parcel d'origine, y compris type et length. « length » (sans « m » au début) fait référence à la valeur de longueur telle qu'écrite dans le Parcel et exclut l'en-tête (type et length)

Si un Bundle contenant un LazyValue est transféré vers un autre processus, l'ensemble du LazyValue y compris les champs type et length est copié tel quel de Bundle.mParcelledData vers le Parcel de destination

Lorsque l'élément du Bundle représenté par LazyValue est accédé, le Parcel est rembobiné à mPosition et readValue() est appelé. Si un argument de type est passé à bundle.getParcelable(), il est propagé à readValue() qui garantira à la fois que le type sur le point d'être désérialisé est celui attendu et vérifiera après désérialisation que le type de la valeur désérialisée est celui attendu. Après désérialisation, le LazyValue est remplacé afin que la prochaine fois que le Bundle est écrit dans un Parcel, la valeur soit sérialisée à nouveau via writeValue()

L'utilisation du paramètre typé Bundle.get*()/Parcel.read*() est surtout pertinente pour des méthodes telles que Parcel.readParcelableList(), qui renvoie un ArrayList et, en raison de l'effacement de type en Java, même si vous faisiez quelque chose comme List<SomeParcelableType> field = parcel.readParcelableList();, la partie <SomeParcelableType> n'était pas appliquée à l'exécution et une telle List pouvait contenir n'importe quelle classe Parcelable disponible dans le système, et donc tous les createFromParcel/writeToParcel disponibles dans le système pouvaient être utilisés dans le cadre de la sérialisation/désérialisation du type contenant une telle List

Vous pourriez également consulter la présentation de l'équipe Android Security and Privacy sur l'introduction de ces mécanismes (diapositives, vidéo)

Ici, cependant, l'utilisation de la version typée semble redondante, car nous vérifions également explicitement le type de l'objet renvoyé. Alors, que se passe-t-il et quelle vulnérabilité est corrigée ici ?

Effets secondaires

Revenons au début du correctif

Télécharger l’outil