mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-26 22:52:06 +00:00
681 lines
42 KiB
Markdown
681 lines
42 KiB
Markdown
# Méthodologie de Pentesting des Extensions de Navigateur
|
|
|
|
{% hint style="success" %}
|
|
Apprenez et pratiquez le Hacking AWS :<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
|
|
Apprenez et pratiquez le Hacking GCP : <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
|
|
|
<details>
|
|
|
|
<summary>Soutenir HackTricks</summary>
|
|
|
|
* Consultez les [**plans d'abonnement**](https://github.com/sponsors/carlospolop) !
|
|
* **Rejoignez le** 💬 [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez-nous sur** **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
|
* **Partagez des astuces de hacking en soumettant des PRs aux** [**HackTricks**](https://github.com/carlospolop/hacktricks) et [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) dépôts github.
|
|
|
|
</details>
|
|
{% endhint %}
|
|
|
|
## Informations de Base
|
|
|
|
Les extensions de navigateur sont écrites en JavaScript et chargées par le navigateur en arrière-plan. Elles ont leur [DOM](https://www.w3schools.com/js/js\_htmldom.asp) mais peuvent interagir avec les DOM d'autres sites. Cela signifie qu'elles peuvent compromettre la confidentialité, l'intégrité et la disponibilité (CIA) d'autres sites.
|
|
|
|
## Composants Principaux
|
|
|
|
Les mises en page des extensions sont mieux visualisées et se composent de trois composants. Examinons chaque composant en profondeur.
|
|
|
|
<figure><img src="../../.gitbook/assets/image (16) (1).png" alt=""><figcaption><p><a href="http://webblaze.cs.berkeley.edu/papers/Extensions.pdf">http://webblaze.cs.berkeley.edu/papers/Extensions.pdf</a></p></figcaption></figure>
|
|
|
|
### **Scripts de Contenu**
|
|
|
|
Chaque script de contenu a un accès direct au DOM d'une **page web unique** et est donc exposé à des **entrées potentiellement malveillantes**. Cependant, le script de contenu ne contient aucune autorisation autre que la capacité d'envoyer des messages au cœur de l'extension.
|
|
|
|
### **Cœur de l'Extension**
|
|
|
|
Le cœur de l'extension contient la plupart des privilèges/accès de l'extension, mais le cœur de l'extension ne peut interagir avec le contenu web que via [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) et les scripts de contenu. De plus, le cœur de l'extension n'a pas d'accès direct à la machine hôte.
|
|
|
|
### **Binaire Natif**
|
|
|
|
L'extension permet un binaire natif qui peut **accéder à la machine hôte avec tous les privilèges de l'utilisateur.** Le binaire natif interagit avec le cœur de l'extension via l'interface de programmation d'application de plugin Netscape standard ([NPAPI](https://en.wikipedia.org/wiki/NPAPI)) utilisée par Flash et d'autres plugins de navigateur.
|
|
|
|
### Limites
|
|
|
|
{% hint style="danger" %}
|
|
Pour obtenir tous les privilèges de l'utilisateur, un attaquant doit convaincre l'extension de transmettre des entrées malveillantes du script de contenu au cœur de l'extension et du cœur de l'extension au binaire natif.
|
|
{% endhint %}
|
|
|
|
Chaque composant de l'extension est séparé des autres par de **fortes limites de protection**. Chaque composant s'exécute dans un **processus de système d'exploitation séparé**. Les scripts de contenu et les cœurs d'extension s'exécutent dans des **processus de bac à sable** inaccessibles à la plupart des services du système d'exploitation.
|
|
|
|
De plus, les scripts de contenu sont séparés de leurs pages web associées en **s'exécutant dans un tas JavaScript séparé**. Le script de contenu et la page web ont **accès au même DOM sous-jacent**, mais les deux **n'échangent jamais de pointeurs JavaScript**, empêchant la fuite de la fonctionnalité JavaScript.
|
|
|
|
## **`manifest.json`**
|
|
|
|
Une extension Chrome est simplement un dossier ZIP avec une [extension de fichier .crx](https://www.lifewire.com/crx-file-2620391). Le cœur de l'extension est le **fichier `manifest.json`** à la racine du dossier, qui spécifie la mise en page, les autorisations et d'autres options de configuration.
|
|
|
|
Exemple :
|
|
```json
|
|
{
|
|
"manifest_version": 2,
|
|
"name": "My extension",
|
|
"version": "1.0",
|
|
"permissions": [
|
|
"storage"
|
|
],
|
|
"content_scripts": [
|
|
{
|
|
"js": [
|
|
"script.js"
|
|
],
|
|
"matches": [
|
|
"https://example.com/*",
|
|
"https://www.example.com/*"
|
|
],
|
|
"exclude_matches": ["*://*/*business*"],
|
|
}
|
|
],
|
|
"background": {
|
|
"scripts": [
|
|
"background.js"
|
|
]
|
|
},
|
|
"options_ui": {
|
|
"page": "options.html"
|
|
}
|
|
}
|
|
```
|
|
### `content_scripts`
|
|
|
|
Les scripts de contenu sont **chargés** chaque fois que l'utilisateur **navigue vers une page correspondante**, dans notre cas toute page correspondant à l'expression **`https://example.com/*`** et ne correspondant pas à l'expression régulière **`*://*/*/business*`**. Ils s'exécutent **comme les propres scripts de la page** et ont un accès arbitraire au [Document Object Model (DOM)](https://developer.mozilla.org/en-US/docs/Web/API/Document\_Object\_Model) de la page.
|
|
```json
|
|
"content_scripts": [
|
|
{
|
|
"js": [
|
|
"script.js"
|
|
],
|
|
"matches": [
|
|
"https://example.com/*",
|
|
"https://www.example.com/*"
|
|
],
|
|
"exclude_matches": ["*://*/*business*"],
|
|
}
|
|
],
|
|
```
|
|
Pour inclure ou exclure plus d'URLs, il est également possible d'utiliser **`include_globs`** et **`exclude_globs`**.
|
|
|
|
Ceci est un exemple de script de contenu qui ajoutera un bouton d'explication à la page lorsque [l'API de stockage](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage) sera utilisée pour récupérer la valeur `message` du stockage de l'extension.
|
|
```js
|
|
chrome.storage.local.get("message", result =>
|
|
{
|
|
let div = document.createElement("div");
|
|
div.innerHTML = result.message + " <button>Explain</button>";
|
|
div.querySelector("button").addEventListener("click", () =>
|
|
{
|
|
chrome.runtime.sendMessage("explain");
|
|
});
|
|
document.body.appendChild(div);
|
|
});
|
|
```
|
|
<figure><img src="../../.gitbook/assets/image (23).png" alt=""><figcaption></figcaption></figure>
|
|
|
|
Un message est envoyé aux pages d'extension par le script de contenu lorsque ce bouton est cliqué, grâce à l'utilisation de l'[**API runtime.sendMessage()**](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendMessage). Cela est dû à la limitation du script de contenu dans l'accès direct aux API, avec `storage` étant parmi les rares exceptions. Pour des fonctionnalités au-delà de ces exceptions, des messages sont envoyés aux pages d'extension avec lesquelles les scripts de contenu peuvent communiquer.
|
|
|
|
{% hint style="warning" %}
|
|
Selon le navigateur, les capacités du script de contenu peuvent varier légèrement. Pour les navigateurs basés sur Chromium, la liste des capacités est disponible dans la [documentation des développeurs Chrome](https://developer.chrome.com/docs/extensions/mv3/content\_scripts/#capabilities), et pour Firefox, le [MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content\_scripts#webextension\_apis) sert de source principale.\
|
|
Il est également à noter que les scripts de contenu ont la capacité de communiquer avec les scripts d'arrière-plan, leur permettant d'effectuer des actions et de relayer des réponses.
|
|
{% endhint %}
|
|
|
|
Pour visualiser et déboguer les scripts de contenu dans Chrome, le menu des outils de développement Chrome peut être accessible depuis Options > Plus d'outils > Outils de développement OU en appuyant sur Ctrl + Shift + I.
|
|
|
|
Une fois les outils de développement affichés, l'onglet **Source** doit être cliqué, suivi de l'onglet **Scripts de contenu**. Cela permet d'observer les scripts de contenu en cours d'exécution de diverses extensions et de définir des points d'arrêt pour suivre le flux d'exécution.
|
|
|
|
### Scripts de contenu injectés
|
|
|
|
{% hint style="success" %}
|
|
Notez que **les scripts de contenu ne sont pas obligatoires** car il est également possible de **dynamiser** **l'injection** de scripts et de **les injecter par programme** dans des pages web via **`tabs.executeScript`**. Cela fournit en fait un contrôle **plus granulaire**.
|
|
{% endhint %}
|
|
|
|
Pour l'injection programmatique d'un script de contenu, l'extension doit avoir des [permissions d'hôte](https://developer.chrome.com/docs/extensions/reference/permissions) pour la page dans laquelle les scripts doivent être injectés. Ces permissions peuvent être sécurisées soit en **les demandant** dans le manifeste de l'extension, soit sur une base temporaire via [**activeTab**](https://developer.chrome.com/docs/extensions/reference/manifest/activeTab).
|
|
|
|
#### Exemple d'extension basée sur activeTab
|
|
|
|
{% code title="manifest.json" %}
|
|
```json
|
|
{
|
|
"name": "My extension",
|
|
...
|
|
"permissions": [
|
|
"activeTab",
|
|
"scripting"
|
|
],
|
|
"background": {
|
|
"service_worker": "background.js"
|
|
},
|
|
"action": {
|
|
"default_title": "Action Button"
|
|
}
|
|
}
|
|
```
|
|
{% endcode %}
|
|
|
|
* **Injecter un fichier JS au clic :**
|
|
```javascript
|
|
// content-script.js
|
|
document.body.style.backgroundColor = "orange";
|
|
|
|
//service-worker.js - Inject the JS file
|
|
chrome.action.onClicked.addListener((tab) => {
|
|
chrome.scripting.executeScript({
|
|
target: { tabId: tab.id },
|
|
files: ["content-script.js"]
|
|
});
|
|
});
|
|
```
|
|
* **Injecter une fonction** au clic :
|
|
```javascript
|
|
//service-worker.js - Inject a function
|
|
function injectedFunction() {
|
|
document.body.style.backgroundColor = "orange";
|
|
}
|
|
|
|
chrome.action.onClicked.addListener((tab) => {
|
|
chrome.scripting.executeScript({
|
|
target : {tabId : tab.id},
|
|
func : injectedFunction,
|
|
});
|
|
});
|
|
```
|
|
#### Exemple avec des permissions de script
|
|
```javascript
|
|
// service-workser.js
|
|
chrome.scripting.registerContentScripts([{
|
|
id : "test",
|
|
matches : [ "https://*.example.com/*" ],
|
|
excludeMatches : [ "*://*/*business*" ],
|
|
js : [ "contentScript.js" ],
|
|
}]);
|
|
|
|
// Another example
|
|
chrome.tabs.executeScript(tabId, { file: "content_script.js" });
|
|
```
|
|
Pour inclure ou exclure plus d'URLs, il est également possible d'utiliser **`include_globs`** et **`exclude_globs`**.
|
|
|
|
### Scripts de contenu `run_at`
|
|
|
|
Le champ `run_at` contrôle **quand les fichiers JavaScript sont injectés dans la page web**. La valeur préférée et par défaut est `"document_idle"`.
|
|
|
|
Les valeurs possibles sont :
|
|
|
|
* **`document_idle`** : Chaque fois que c'est possible
|
|
* **`document_start`** : Après tous les fichiers de `css`, mais avant que tout autre DOM soit construit ou que tout autre script soit exécuté.
|
|
* **`document_end`** : Immédiatement après que le DOM soit complet, mais avant que les sous-ressources comme les images et les cadres aient été chargées.
|
|
|
|
#### Via `manifest.json`
|
|
```json
|
|
{
|
|
"name": "My extension",
|
|
...
|
|
"content_scripts": [
|
|
{
|
|
"matches": ["https://*.example.com/*"],
|
|
"run_at": "document_idle",
|
|
"js": ["contentScript.js"]
|
|
}
|
|
],
|
|
...
|
|
}
|
|
|
|
```
|
|
Via **`service-worker.js`**
|
|
```javascript
|
|
chrome.scripting.registerContentScripts([{
|
|
id : "test",
|
|
matches : [ "https://*.example.com/*" ],
|
|
runAt : "document_idle",
|
|
js : [ "contentScript.js" ],
|
|
}]);
|
|
```
|
|
### `background`
|
|
|
|
Les messages envoyés par les scripts de contenu sont reçus par la **page d'arrière-plan**, qui joue un rôle central dans la coordination des composants de l'extension. Notamment, la page d'arrière-plan persiste tout au long de la vie de l'extension, fonctionnant discrètement sans interaction directe de l'utilisateur. Elle possède son propre Document Object Model (DOM), permettant des interactions complexes et la gestion de l'état.
|
|
|
|
**Points Clés**:
|
|
|
|
* **Rôle de la Page d'Arrière-plan :** Agit comme le centre névralgique de l'extension, assurant la communication et la coordination entre les différentes parties de l'extension.
|
|
* **Persistance :** C'est une entité toujours présente, invisible à l'utilisateur mais intégrale au fonctionnement de l'extension.
|
|
* **Génération Automatique :** Si elle n'est pas explicitement définie, le navigateur créera automatiquement une page d'arrière-plan. Cette page générée automatiquement inclura tous les scripts d'arrière-plan spécifiés dans le manifeste de l'extension, garantissant le bon fonctionnement des tâches d'arrière-plan de l'extension.
|
|
|
|
{% hint style="success" %}
|
|
La commodité fournie par le navigateur en générant automatiquement une page d'arrière-plan (lorsqu'elle n'est pas explicitement déclarée) garantit que tous les scripts d'arrière-plan nécessaires sont intégrés et opérationnels, simplifiant le processus de configuration de l'extension.
|
|
{% endhint %}
|
|
|
|
Exemple de script d'arrière-plan :
|
|
```js
|
|
chrome.runtime.onMessage.addListener((request, sender, sendResponse) =>
|
|
{
|
|
if (request == "explain")
|
|
{
|
|
chrome.tabs.create({ url: "https://example.net/explanation" });
|
|
}
|
|
})
|
|
```
|
|
Il utilise l'[API runtime.onMessage](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage) pour écouter les messages. Lorsqu'un message `"explain"` est reçu, il utilise l'[API tabs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs) pour ouvrir une page dans un nouvel onglet.
|
|
|
|
Pour déboguer le script d'arrière-plan, vous pouvez aller dans les **détails de l'extension et inspecter le service worker,** cela ouvrira les outils de développement avec le script d'arrière-plan :
|
|
|
|
<figure><img src="https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/browser-extension-pentesting-methodology/broken-reference" alt=""><figcaption></figcaption></figure>
|
|
|
|
### Pages d'options et autres
|
|
|
|
Les extensions de navigateur peuvent contenir divers types de pages :
|
|
|
|
* Les **pages d'action** s'affichent dans un **menu déroulant lorsque l'icône de l'extension** est cliquée.
|
|
* Pages que l'extension va **charger dans un nouvel onglet**.
|
|
* **Pages d'options** : Cette page s'affiche au-dessus de l'extension lorsqu'elle est cliquée. Dans le manifeste précédent, dans mon cas, j'ai pu accéder à cette page dans `chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca` ou en cliquant :
|
|
|
|
<figure><img src="../../.gitbook/assets/image (24).png" alt="" width="375"><figcaption></figcaption></figure>
|
|
|
|
Notez que ces pages ne sont pas persistantes comme les pages d'arrière-plan car elles chargent dynamiquement du contenu selon les besoins. Malgré cela, elles partagent certaines capacités avec la page d'arrière-plan :
|
|
|
|
* **Communication avec les scripts de contenu :** Semblable à la page d'arrière-plan, ces pages peuvent recevoir des messages des scripts de contenu, facilitant l'interaction au sein de l'extension.
|
|
* **Accès aux API spécifiques à l'extension :** Ces pages bénéficient d'un accès complet aux API spécifiques à l'extension, sous réserve des autorisations définies pour l'extension.
|
|
|
|
### `permissions` & `host_permissions`
|
|
|
|
**`permissions`** et **`host_permissions`** sont des entrées du `manifest.json` qui indiqueront **quelles autorisations** l'extension de navigateur a (stockage, localisation...) et **sur quelles pages web**.
|
|
|
|
Comme les extensions de navigateur peuvent être si **privilégiées**, une malveillante ou compromise pourrait permettre à l'attaquant **différentes méthodes pour voler des informations sensibles et espionner l'utilisateur**.
|
|
|
|
Vérifiez comment ces paramètres fonctionnent et comment ils pourraient être abusés dans :
|
|
|
|
{% content-ref url="browext-permissions-and-host_permissions.md" %}
|
|
[browext-permissions-and-host\_permissions.md](browext-permissions-and-host\_permissions.md)
|
|
{% endcontent-ref %}
|
|
|
|
### `content_security_policy`
|
|
|
|
Une **politique de sécurité de contenu** peut également être déclarée à l'intérieur du `manifest.json`. S'il y en a une définie, elle pourrait être **vulnérable**.
|
|
|
|
Le paramètre par défaut pour les pages d'extension de navigateur est plutôt restrictif :
|
|
```bash
|
|
script-src 'self'; object-src 'self';
|
|
```
|
|
Pour plus d'informations sur CSP et les contournements potentiels, consultez :
|
|
|
|
{% content-ref url="../content-security-policy-csp-bypass/" %}
|
|
[content-security-policy-csp-bypass](../content-security-policy-csp-bypass/)
|
|
{% endcontent-ref %}
|
|
|
|
### `web_accessible_resources`
|
|
|
|
Pour qu'une page web puisse accéder à une page d'une extension de navigateur, une page `.html` par exemple, cette page doit être mentionnée dans le champ **`web_accessible_resources`** du `manifest.json`.\
|
|
Par exemple :
|
|
```javascript
|
|
{
|
|
...
|
|
"web_accessible_resources": [
|
|
{
|
|
"resources": [ "images/*.png" ],
|
|
"matches": [ "https://example.com/*" ]
|
|
},
|
|
{
|
|
"resources": [ "fonts/*.woff" ],
|
|
"matches": [ "https://example.com/*" ]
|
|
}
|
|
],
|
|
...
|
|
}
|
|
```
|
|
Ces pages sont accessibles à l'URL comme :
|
|
```
|
|
chrome-extension://<extension-id>/message.html
|
|
```
|
|
Dans les extensions publiques, l'**extension-id est accessible** :
|
|
|
|
<figure><img src="../../.gitbook/assets/image (1194).png" alt="" width="375"><figcaption></figcaption></figure>
|
|
|
|
Cependant, si le paramètre `manifest.json` **`use_dynamic_url`** est utilisé, cet **id peut être dynamique**.
|
|
|
|
{% hint style="success" %}
|
|
Notez que même si une page est mentionnée ici, elle pourrait être **protégée contre le ClickJacking** grâce à la **Content Security Policy**. Vous devez donc également vérifier cela (section frame-ancestors) avant de confirmer qu'une attaque ClickJacking est possible.
|
|
{% endhint %}
|
|
|
|
Le fait d'être autorisé à accéder à ces pages rend ces pages **potentiellement vulnérables au ClickJacking** :
|
|
|
|
{% content-ref url="browext-clickjacking.md" %}
|
|
[browext-clickjacking.md](browext-clickjacking.md)
|
|
{% endcontent-ref %}
|
|
|
|
{% hint style="success" %}
|
|
Autoriser ces pages à être chargées uniquement par l'extension et non par des URL aléatoires pourrait prévenir les attaques de ClickJacking.
|
|
{% endhint %}
|
|
|
|
{% hint style="danger" %}
|
|
Notez que les pages de **`web_accessible_resources`** et d'autres pages de l'extension sont également capables de **contacter des scripts d'arrière-plan**. Donc, si l'une de ces pages est vulnérable à **XSS**, cela pourrait ouvrir une vulnérabilité plus importante.
|
|
|
|
De plus, notez que vous ne pouvez ouvrir que les pages indiquées dans **`web_accessible_resources`** à l'intérieur des iframes, mais depuis un nouvel onglet, il est possible d'accéder à n'importe quelle page de l'extension en connaissant l'ID de l'extension. Par conséquent, si un XSS est trouvé en abusant des mêmes paramètres, il pourrait être exploité même si la page n'est pas configurée dans **`web_accessible_resources`**.
|
|
{% endhint %}
|
|
|
|
### `externally_connectable`
|
|
|
|
Selon les [**docs**](https://developer.chrome.com/docs/extensions/reference/manifest/externally-connectable), la propriété de manifeste `"externally_connectable"` déclare **quelles extensions et pages web peuvent se connecter** à votre extension via [runtime.connect](https://developer.chrome.com/docs/extensions/reference/runtime#method-connect) et [runtime.sendMessage](https://developer.chrome.com/docs/extensions/reference/runtime#method-sendMessage).
|
|
|
|
* Si la clé **`externally_connectable`** **n'est pas** déclarée dans le manifeste de votre extension ou qu'elle est déclarée comme **`"ids": ["*"]`**, **toutes les extensions peuvent se connecter, mais aucune page web ne peut se connecter**.
|
|
* Si **des ID spécifiques sont spécifiés**, comme dans `"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]`, **seules ces applications** peuvent se connecter.
|
|
* Si des **matches** sont spécifiés, ces applications web pourront se connecter :
|
|
```json
|
|
"matches": [
|
|
"https://*.google.com/*",
|
|
"*://*.chromium.org/*",
|
|
```
|
|
* S'il est spécifié comme vide : **`"externally_connectable": {}`**, aucune application ou site web ne pourra se connecter.
|
|
|
|
Le **moins d'extensions et d'URLs** indiqués ici, plus la **surface d'attaque** sera **petite**.
|
|
|
|
{% hint style="danger" %}
|
|
Si une page web **vulnérable à XSS ou takeover** est indiquée dans **`externally_connectable`**, un attaquant pourra **envoyer des messages directement au script d'arrière-plan**, contournant complètement le Content Script et son CSP.
|
|
|
|
Par conséquent, c'est un **contournement très puissant**.
|
|
|
|
De plus, si le client installe une extension malveillante, même si elle n'est pas autorisée à communiquer avec l'extension vulnérable, elle pourrait injecter **des données XSS dans une page web autorisée** ou abuser des API **`WebRequest`** ou **`DeclarativeNetRequest`** pour manipuler des requêtes sur un domaine ciblé en modifiant la requête d'une **fichier JavaScript**. (Notez que le CSP sur la page ciblée pourrait empêcher ces attaques). Cette idée vient [**de cet article**](https://www.darkrelay.com/post/opera-zero-day-rce-vulnerability).
|
|
{% endhint %}
|
|
|
|
## Résumé de la communication
|
|
|
|
### Extension <--> WebApp
|
|
|
|
Pour communiquer entre le script de contenu et la page web, des messages post sont généralement utilisés. Par conséquent, dans l'application web, vous trouverez généralement des appels à la fonction **`window.postMessage`** et dans le script de contenu des écouteurs comme **`window.addEventListener`**. Notez cependant que l'extension pourrait également **communiquer avec l'application web en envoyant un Post Message** (et donc le web devrait s'y attendre) ou simplement faire charger un nouveau script par le web.
|
|
|
|
### À l'intérieur de l'extension
|
|
|
|
Généralement, la fonction **`chrome.runtime.sendMessage`** est utilisée pour envoyer un message à l'intérieur de l'extension (généralement géré par le script `background`) et pour le recevoir et le gérer, un écouteur est déclaré en appelant **`chrome.runtime.onMessage.addListener`**.
|
|
|
|
Il est également possible d'utiliser **`chrome.runtime.connect()`** pour avoir une connexion persistante au lieu d'envoyer des messages uniques, il est possible de l'utiliser pour **envoyer** et **recevoir** **des messages** comme dans l'exemple suivant :
|
|
|
|
<details>
|
|
|
|
<summary><code>chrome.runtime.connect()</code> exemple</summary>
|
|
```javascript
|
|
var port = chrome.runtime.connect();
|
|
|
|
// Listen for messages from the web page
|
|
window.addEventListener("message", (event) => {
|
|
// Only accept messages from the same window
|
|
if (event.source !== window) {
|
|
return;
|
|
}
|
|
|
|
// Check if the message type is "FROM_PAGE"
|
|
if (event.data.type && (event.data.type === "FROM_PAGE")) {
|
|
console.log("Content script received: " + event.data.text);
|
|
// Forward the message to the background script
|
|
port.postMessage({ type: 'FROM_PAGE', text: event.data.text });
|
|
}
|
|
}, false);
|
|
|
|
// Listen for messages from the background script
|
|
port.onMessage.addListener(function(msg) {
|
|
console.log("Content script received message from background script:", msg);
|
|
// Handle the response message from the background script
|
|
});
|
|
```
|
|
</details>
|
|
|
|
Il est également possible d'envoyer des messages d'un script d'arrière-plan à un script de contenu situé dans un onglet spécifique en appelant **`chrome.tabs.sendMessage`** où vous devrez indiquer l'**ID de l'onglet** à qui envoyer le message.
|
|
|
|
### Des `externally_connectable` autorisés à l'extension
|
|
|
|
**Les applications web et les extensions de navigateur externes autorisées** dans la configuration `externally_connectable` peuvent envoyer des requêtes en utilisant :
|
|
```javascript
|
|
chrome.runtime.sendMessage(extensionId, ...
|
|
```
|
|
Où il est nécessaire de mentionner l'**ID d'extension**.
|
|
|
|
## Web **↔︎** Communication de Script de Contenu
|
|
|
|
Les environnements où les **scripts de contenu** opèrent et où les pages hôtes existent sont **séparés** les uns des autres, garantissant **l'isolement**. Malgré cet isolement, les deux ont la capacité d'interagir avec le **Document Object Model (DOM)** de la page, une ressource partagée. Pour que la page hôte engage une communication avec le **script de contenu**, ou indirectement avec l'extension via le script de contenu, il est nécessaire d'utiliser le **DOM** qui est accessible par les deux parties comme canal de communication.
|
|
|
|
### Messages Postaux
|
|
|
|
{% code title="content-script.js" %}
|
|
```javascript
|
|
// This is like "chrome.runtime.sendMessage" but to maintain the connection
|
|
var port = chrome.runtime.connect();
|
|
|
|
window.addEventListener("message", (event) => {
|
|
// We only accept messages from ourselves
|
|
if (event.source !== window) {
|
|
return;
|
|
}
|
|
|
|
if (event.data.type && (event.data.type === "FROM_PAGE")) {
|
|
console.log("Content script received: " + event.data.text);
|
|
// Forward the message to the background script
|
|
port.postMessage(event.data.text);
|
|
}
|
|
}, false);
|
|
```
|
|
{% endcode %}
|
|
|
|
{% code title="example.js" %}
|
|
```javascript
|
|
document.getElementById("theButton").addEventListener("click", () => {
|
|
window.postMessage(
|
|
{type : "FROM_PAGE", text : "Hello from the webpage!"}, "*");
|
|
}, false);
|
|
```
|
|
{% endcode %}
|
|
|
|
Une communication sécurisée par Post Message doit vérifier l'authenticité du message reçu, cela peut être fait en vérifiant :
|
|
|
|
* **`event.isTrusted`** : Ceci est vrai uniquement si l'événement a été déclenché par une action de l'utilisateur
|
|
* Le script de contenu pourrait s'attendre à un message uniquement si l'utilisateur effectue une action
|
|
* **domaine d'origine** : pourrait s'attendre à un message uniquement à partir d'une liste blanche de domaines.
|
|
* Si une regex est utilisée, soyez très prudent
|
|
* **Source** : `received_message.source !== window` peut être utilisé pour vérifier si le message provient **de la même fenêtre** où le script de contenu écoute.
|
|
|
|
Les vérifications précédentes, même si elles sont effectuées, pourraient être vulnérables, alors vérifiez sur la page suivante **les contournements potentiels de Post Message** :
|
|
|
|
{% content-ref url="../postmessage-vulnerabilities/" %}
|
|
[postmessage-vulnerabilities](../postmessage-vulnerabilities/)
|
|
{% endcontent-ref %}
|
|
|
|
### Iframe
|
|
|
|
Une autre façon possible de communication pourrait être à travers **les URL Iframe**, vous pouvez trouver un exemple dans :
|
|
|
|
{% content-ref url="browext-xss-example.md" %}
|
|
[browext-xss-example.md](browext-xss-example.md)
|
|
{% endcontent-ref %}
|
|
|
|
### DOM
|
|
|
|
Ce n'est pas "exactement" une façon de communiquer, mais le **web et le script de contenu auront accès au DOM web**. Donc, si le **script de contenu** lit certaines informations à partir de celui-ci, **faisant confiance au DOM web**, le web pourrait **modifier ces données** (car le web ne devrait pas être digne de confiance, ou parce que le web est vulnérable à XSS) et **compromettre le script de contenu**.
|
|
|
|
Vous pouvez également trouver un exemple de **XSS basé sur le DOM pour compromettre une extension de navigateur** dans :
|
|
|
|
{% content-ref url="browext-xss-example.md" %}
|
|
[browext-xss-example.md](browext-xss-example.md)
|
|
{% endcontent-ref %}
|
|
|
|
## Communication entre le Script de Contenu **↔︎** le Script d'Arrière-plan
|
|
|
|
Un Script de Contenu peut utiliser les fonctions [**runtime.sendMessage()**](https://developer.chrome.com/docs/extensions/reference/runtime#method-sendMessage) **ou** [**tabs.sendMessage()**](https://developer.chrome.com/docs/extensions/reference/tabs#method-sendMessage) pour envoyer un message **sérialisable en JSON** **à usage unique**.
|
|
|
|
Pour gérer la **réponse**, utilisez la **Promise** retournée. Bien que, pour des raisons de compatibilité ascendante, vous puissiez toujours passer un **callback** comme dernier argument.
|
|
|
|
L'envoi d'une requête depuis un **script de contenu** ressemble à ceci :
|
|
```javascript
|
|
(async () => {
|
|
const response = await chrome.runtime.sendMessage({greeting: "hello"});
|
|
// do something with response here, not outside the function
|
|
console.log(response);
|
|
})();
|
|
```
|
|
Envoyer une requête depuis l'**extension** (généralement un **script d'arrière-plan**). Exemple de la façon d'envoyer un message au script de contenu dans l'onglet sélectionné :
|
|
```javascript
|
|
// From https://stackoverflow.com/questions/36153999/how-to-send-a-message-between-chrome-extension-popup-and-content-script
|
|
(async () => {
|
|
const [tab] = await chrome.tabs.query({active: true, lastFocusedWindow: true});
|
|
const response = await chrome.tabs.sendMessage(tab.id, {greeting: "hello"});
|
|
// do something with response here, not outside the function
|
|
console.log(response);
|
|
})();
|
|
```
|
|
Sur le **receiving end**, vous devez configurer un [**runtime.onMessage**](https://developer.chrome.com/docs/extensions/reference/runtime#event-onMessage) **écouteur d'événements** pour gérer le message. Cela ressemble à la même chose depuis un script de contenu ou une page d'extension.
|
|
```javascript
|
|
// From https://stackoverflow.com/questions/70406787/javascript-send-message-from-content-js-to-background-js
|
|
chrome.runtime.onMessage.addListener(
|
|
function(request, sender, sendResponse) {
|
|
console.log(sender.tab ?
|
|
"from a content script:" + sender.tab.url :
|
|
"from the extension");
|
|
if (request.greeting === "hello")
|
|
sendResponse({farewell: "goodbye"});
|
|
}
|
|
);
|
|
```
|
|
Dans l'exemple mis en évidence, **`sendResponse()`** a été exécuté de manière synchrone. Pour modifier le gestionnaire d'événements `onMessage` pour une exécution asynchrone de `sendResponse()`, il est impératif d'incorporer `return true;`.
|
|
|
|
Une considération importante est que dans les scénarios où plusieurs pages sont configurées pour recevoir des événements `onMessage`, **la première page à exécuter `sendResponse()`** pour un événement spécifique sera la seule capable de livrer la réponse efficacement. Toute réponse ultérieure au même événement ne sera pas prise en compte.
|
|
|
|
Lors de la création de nouvelles extensions, la préférence devrait être donnée aux promesses plutôt qu'aux rappels. En ce qui concerne l'utilisation des rappels, la fonction `sendResponse()` est considérée comme valide uniquement si elle est exécutée directement dans le contexte synchrone, ou si le gestionnaire d'événements indique une opération asynchrone en retournant `true`. Si aucun des gestionnaires ne retourne `true` ou si la fonction `sendResponse()` est supprimée de la mémoire (collectée par le garbage collector), le rappel associé à la fonction `sendMessage()` sera déclenché par défaut.
|
|
|
|
## Informations sensibles en mémoire/code/clipboard
|
|
|
|
Si une extension de navigateur stocke **des informations sensibles dans sa mémoire**, celles-ci pourraient être **dumpées** (surtout sur les machines Windows) et **recherchées** pour ces informations.
|
|
|
|
Par conséquent, la mémoire de l'extension de navigateur **ne doit pas être considérée comme sécurisée** et **les informations sensibles** telles que les identifiants ou les phrases mnémotechniques **ne doivent pas être stockées**.
|
|
|
|
Bien sûr, ne **mettez pas d'informations sensibles dans le code**, car cela sera **public**.
|
|
|
|
Pour dumper la mémoire du navigateur, vous pourriez **dumper la mémoire du processus** ou aller dans les **paramètres** de l'extension de navigateur, cliquer sur **`Inspect pop-up`** -> Dans la section **`Memory`** -> **`Take a snapshot`** et **`CTRL+F`** pour rechercher dans le snapshot des informations sensibles.
|
|
|
|
De plus, des informations hautement sensibles comme des clés mnémotechniques ou des mots de passe **ne devraient pas être autorisées à être copiées dans le presse-papiers** (ou au moins les retirer du presse-papiers après quelques secondes) car alors les processus surveillant le presse-papiers pourront les obtenir.
|
|
|
|
## Chargement d'une extension dans le navigateur
|
|
|
|
1. **Téléchargez** l'extension de navigateur & décompressez-la
|
|
2. Allez à **`chrome://extensions/`** et **activez** le `Mode développeur`
|
|
3. Cliquez sur le bouton **`Load unpacked`**
|
|
|
|
Dans **Firefox**, allez à **`about:debugging#/runtime/this-firefox`** et cliquez sur le bouton **`Load Temporary Add-on`**.
|
|
|
|
## Obtenir le code source depuis le store
|
|
|
|
Le code source d'une extension Chrome peut être obtenu par divers moyens. Voici des explications détaillées et des instructions pour chaque option.
|
|
|
|
### Télécharger l'extension en tant que ZIP via la ligne de commande
|
|
|
|
Le code source d'une extension Chrome peut être téléchargé sous forme de fichier ZIP en utilisant la ligne de commande. Cela implique d'utiliser `curl` pour récupérer le fichier ZIP à partir d'une URL spécifique, puis d'extraire le contenu du fichier ZIP dans un répertoire. Voici les étapes :
|
|
|
|
1. Remplacez `"extension_id"` par l'ID réel de l'extension.
|
|
2. Exécutez les commandes suivantes :
|
|
```bash
|
|
extension_id=your_extension_id # Replace with the actual extension ID
|
|
curl -L -o "$extension_id.zip" "https://clients2.google.com/service/update2/crx?response=redirect&os=mac&arch=x86-64&nacl_arch=x86-64&prod=chromecrx&prodchannel=stable&prodversion=44.0.2403.130&x=id%3D$extension_id%26uc"
|
|
unzip -d "$extension_id-source" "$extension_id.zip"
|
|
```
|
|
### Utilisez le site CRX Viewer
|
|
|
|
[https://robwu.nl/crxviewer/](https://robwu.nl/crxviewer/)
|
|
|
|
### Utilisez l'extension CRX Viewer
|
|
|
|
Une autre méthode pratique consiste à utiliser le Chrome Extension Source Viewer, qui est un projet open-source. Il peut être installé depuis le [Chrome Web Store](https://chrome.google.com/webstore/detail/chrome-extension-source-v/jifpbeccnghkjeaalbbjmodiffmgedin?hl=en). Le code source du visualiseur est disponible dans son [dépôt GitHub](https://github.com/Rob--W/crxviewer).
|
|
|
|
### Voir le code source de l'extension installée localement
|
|
|
|
Les extensions Chrome installées localement peuvent également être inspectées. Voici comment :
|
|
|
|
1. Accédez à votre répertoire de profil local Chrome en visitant `chrome://version/` et en localisant le champ "Profile Path".
|
|
2. Naviguez vers le sous-dossier `Extensions/` dans le répertoire de profil.
|
|
3. Ce dossier contient toutes les extensions installées, généralement avec leur code source dans un format lisible.
|
|
|
|
Pour identifier les extensions, vous pouvez mapper leurs ID à des noms :
|
|
|
|
* Activez le mode développeur sur la page `about:extensions` pour voir les ID de chaque extension.
|
|
* Dans le dossier de chaque extension, le fichier `manifest.json` contient un champ `name` lisible, vous aidant à identifier l'extension.
|
|
|
|
### Utilisez un archiveur de fichiers ou un décompresseur
|
|
|
|
Allez sur le Chrome Web Store et téléchargez l'extension. Le fichier aura une extension `.crx`. Changez l'extension du fichier de `.crx` à `.zip`. Utilisez n'importe quel archiveur de fichiers (comme WinRAR, 7-Zip, etc.) pour extraire le contenu du fichier ZIP.
|
|
|
|
### Utilisez le mode développeur dans Chrome
|
|
|
|
Ouvrez Chrome et allez à `chrome://extensions/`. Activez "Mode développeur" en haut à droite. Cliquez sur "Charger l'extension non empaquetée...". Naviguez vers le répertoire de votre extension. Cela ne télécharge pas le code source, mais c'est utile pour visualiser et modifier le code d'une extension déjà téléchargée ou développée.
|
|
|
|
## Liste de contrôle de l'audit de sécurité
|
|
|
|
Bien que les extensions de navigateur aient une **surface d'attaque limitée**, certaines d'entre elles peuvent contenir des **vulnérabilités** ou des **améliorations potentielles de durcissement**. Les suivantes sont les plus courantes :
|
|
|
|
* [ ] **Limitez** autant que possible les **`permissions`** demandées
|
|
* [ ] **Limitez** autant que possible les **`host_permissions`**
|
|
* [ ] Utilisez une **politique de sécurité de contenu** **forte**
|
|
* [ ] **Limitez** autant que possible le **`externally_connectable`**, si aucun n'est nécessaire et possible, ne le laissez pas par défaut, spécifiez **`{}`**
|
|
* [ ] Si une **URL vulnérable à XSS ou à la prise de contrôle** est mentionnée ici, un attaquant pourra **envoyer des messages aux scripts d'arrière-plan directement**. Contournement très puissant.
|
|
* [ ] **Limitez** autant que possible les **`web_accessible_resources`**, même vides si possible.
|
|
* [ ] Si **`web_accessible_resources`** n'est pas nul, vérifiez pour [**ClickJacking**](browext-clickjacking.md)
|
|
* [ ] Si une **communication** se produit de l'**extension** à la **page web**, [**vérifiez les vulnérabilités XSS**](browext-xss-example.md) causées dans la communication.
|
|
* [ ] Si des messages post sont utilisés, vérifiez pour [**les vulnérabilités de message post**](../postmessage-vulnerabilities/)**.**
|
|
* [ ] Si le **Content Script accède aux détails DOM**, vérifiez qu'ils **n'introduisent pas un XSS** s'ils sont **modifiés** par le web
|
|
* [ ] Mettez un accent particulier si cette communication est également impliquée dans la **communication Content Script -> script d'arrière-plan**
|
|
* [ ] **Les informations sensibles ne doivent pas être stockées** à l'intérieur du code de l'extension de navigateur
|
|
* [ ] **Les informations sensibles ne doivent pas être stockées** à l'intérieur de la mémoire de l'extension de navigateur
|
|
|
|
## Outils
|
|
|
|
### [**Tarnish**](https://thehackerblog.com/tarnish/)
|
|
|
|
* Récupère n'importe quelle extension Chrome à partir d'un lien de Chrome Webstore fourni.
|
|
* Visualiseur de [**manifest.json**](https://developer.chrome.com/extensions/manifest) : affiche simplement une version JSON formatée du manifeste de l'extension.
|
|
* **Analyse de l'empreinte** : Détection des [web_accessible_resources](https://developer.chrome.com/extensions/manifest/web_accessible_resources) et génération automatique de JavaScript d'empreinte d'extension Chrome.
|
|
* **Analyse potentielle de Clickjacking** : Détection des pages HTML d'extension avec la directive [web_accessible_resources](https://developer.chrome.com/extensions/manifest/web_accessible_resources) définie. Celles-ci sont potentiellement vulnérables au clickjacking selon l'objectif des pages.
|
|
* Visualiseur d'avertissement(s) de permission : qui montre une liste de tous les avertissements de demande de permission Chrome qui seront affichés lorsqu'un utilisateur tentera d'installer l'extension.
|
|
* **Fonction(s) dangereuse(s)** : montre l'emplacement des fonctions dangereuses qui pourraient potentiellement être exploitées par un attaquant (par exemple, des fonctions telles que innerHTML, chrome.tabs.executeScript).
|
|
* **Point(s) d'entrée** : montre où l'extension prend des entrées utilisateur/externe. Cela est utile pour comprendre la surface d'une extension et rechercher des points potentiels pour envoyer des données malicieusement conçues à l'extension.
|
|
* Les scanners de Fonction(s) dangereuse(s) et Point(s) d'entrée ont les éléments suivants pour leurs alertes générées :
|
|
* Extrait de code pertinent et ligne qui a causé l'alerte.
|
|
* Description du problème.
|
|
* Un bouton "Voir le fichier" pour voir le fichier source complet contenant le code.
|
|
* Le chemin du fichier alerté.
|
|
* L'URI complète de l'extension Chrome du fichier alerté.
|
|
* Le type de fichier, tel qu'un script de page d'arrière-plan, un script de contenu, une action de navigateur, etc.
|
|
* Si la ligne vulnérable se trouve dans un fichier JavaScript, les chemins de toutes les pages où elle est incluse ainsi que le type de ces pages, et le statut de [web_accessible_resource](https://developer.chrome.com/extensions/manifest/web_accessible_resources).
|
|
* **Analyseur de politique de sécurité de contenu (CSP) et vérificateur de contournement** : Cela mettra en évidence les faiblesses de la CSP de votre extension et mettra également en lumière d'éventuelles façons de contourner votre CSP en raison de CDNs sur liste blanche, etc.
|
|
* **Bibliothèques vulnérables connues** : Cela utilise [Retire.js](https://retirejs.github.io/retire.js/) pour vérifier toute utilisation de bibliothèques JavaScript connues comme vulnérables.
|
|
* Télécharger l'extension et les versions formatées.
|
|
* Télécharger l'extension originale.
|
|
* Télécharger une version beautifiée de l'extension (HTML et JavaScript auto-formatés).
|
|
* Mise en cache automatique des résultats de scan, exécuter un scan d'extension prendra un bon moment la première fois que vous l'exécutez. Cependant, la deuxième fois, à condition que l'extension n'ait pas été mise à jour, sera presque instantanée grâce aux résultats étant mis en cache.
|
|
* URLs de rapport liables, permettant de lier facilement quelqu'un à un rapport d'extension généré par tarnish.
|
|
|
|
### [Neto](https://github.com/elevenpaths/neto)
|
|
|
|
Le projet Neto est un package Python 3 conçu pour analyser et déchiffrer les fonctionnalités cachées des plugins et extensions de navigateur pour des navigateurs bien connus tels que Firefox et Chrome. Il automatise le processus de décompression des fichiers empaquetés pour extraire ces fonctionnalités des ressources pertinentes dans une extension comme `manifest.json`, des dossiers de localisation ou des fichiers source Javascript et HTML.
|
|
|
|
## Références
|
|
|
|
* **Merci à** [**@naivenom**](https://twitter.com/naivenom) **pour l'aide avec cette méthodologie**
|
|
* [https://www.cobalt.io/blog/introduction-to-chrome-browser-extension-security-testing](https://www.cobalt.io/blog/introduction-to-chrome-browser-extension-security-testing)
|
|
* [https://palant.info/2022/08/10/anatomy-of-a-basic-extension/](https://palant.info/2022/08/10/anatomy-of-a-basic-extension/)
|
|
* [https://palant.info/2022/08/24/attack-surface-of-extension-pages/](https://palant.info/2022/08/24/attack-surface-of-extension-pages/)
|
|
* [https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/](https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/)
|
|
* [https://help.passbolt.com/assets/files/PBL-02-report.pdf](https://help.passbolt.com/assets/files/PBL-02-report.pdf)
|
|
* [https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts](https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts)
|
|
* [https://developer.chrome.com/docs/extensions/mv2/background-pages](https://developer.chrome.com/docs/extensions/mv2/background-pages)
|
|
* [https://thehackerblog.com/kicking-the-rims-a-guide-for-securely-writing-and-auditing-chrome-extensions/](https://thehackerblog.com/kicking-the-rims-a-guide-for-securely-writing-and-auditing-chrome-extensions/)
|
|
* [https://gist.github.com/LongJohnCoder/9ddf5735df3a4f2e9559665fb864eac0](https://gist.github.com/LongJohnCoder/9ddf5735df3a4f2e9559665fb864eac0)
|
|
|
|
{% hint style="success" %}
|
|
Learn & practice AWS Hacking:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
|
|
Learn & practice GCP Hacking: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
|
|
|
<details>
|
|
|
|
<summary>Support HackTricks</summary>
|
|
|
|
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
|
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
|
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
|
|
|
</details>
|
|
{% endhint %}
|