mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-24 20:13:37 +00:00
678 lines
40 KiB
Markdown
678 lines
40 KiB
Markdown
# Metodologia de Pentesting de Extensões do Navegador
|
|
|
|
<details>
|
|
|
|
<summary><strong>Aprenda hacking AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
|
|
|
Outras maneiras de apoiar o HackTricks:
|
|
|
|
* Se você deseja ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF** Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
|
* Adquira [**produtos oficiais PEASS & HackTricks**](https://peass.creator-spring.com)
|
|
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
|
* **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
|
* **Compartilhe seus truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
|
|
|
|
</details>
|
|
|
|
## Informações Básicas
|
|
|
|
As extensões do navegador são escritas em JavaScript e carregadas pelo navegador em segundo plano. Elas têm seu [DOM](https://www.w3schools.com/js/js\_htmldom.asp) mas podem interagir com o DOM de outros sites. Isso significa que elas podem comprometer a confidencialidade, integridade e disponibilidade de outros sites (CIA).
|
|
|
|
## Componentes Principais
|
|
|
|
Os layouts das extensões ficam melhores quando visualizados e consistem em três componentes. Vamos analisar cada componente em detalhes.
|
|
|
|
<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 Conteúdo**
|
|
|
|
Cada script de conteúdo tem acesso direto ao DOM de uma **única página da web** e, portanto, está exposto a **entradas potencialmente maliciosas**. No entanto, o script de conteúdo não possui permissões além da capacidade de enviar mensagens para o núcleo da extensão.
|
|
|
|
### **Núcleo da Extensão**
|
|
|
|
O núcleo da extensão contém a maioria dos privilégios/acessos da extensão, mas o núcleo da extensão só pode interagir com o conteúdo da web via [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) e scripts de conteúdo. Além disso, o núcleo da extensão não tem acesso direto à máquina hospedeira.
|
|
|
|
### **Binário Nativo**
|
|
|
|
A extensão permite um binário nativo que pode **acessar a máquina hospedeira com os privilégios completos do usuário**. O binário nativo interage com o núcleo da extensão por meio da Interface de Programação de Aplicativos de Plug-in Netscape padrão ([NPAPI](https://en.wikipedia.org/wiki/NPAPI)) usada pelo Flash e outros plug-ins de navegador.
|
|
|
|
### Limites
|
|
|
|
{% hint style="danger" %}
|
|
Para obter os privilégios completos do usuário, um atacante deve convencer a extensão a passar uma entrada maliciosa do script de conteúdo para o núcleo da extensão e do núcleo da extensão para o binário nativo.
|
|
{% endhint %}
|
|
|
|
Cada componente da extensão é separado uns dos outros por **fortes limites de proteção**. Cada componente é executado em um **processo de sistema operacional separado**. Os scripts de conteúdo e os núcleos de extensão são executados em **processos de sandbox** indisponíveis para a maioria dos serviços do sistema operacional.
|
|
|
|
Além disso, os scripts de conteúdo são separados de suas páginas da web associadas por **serem executados em um heap JavaScript separado**. O script de conteúdo e a página da web têm **acesso ao mesmo DOM subjacente**, mas os dois **nunca trocam ponteiros JavaScript**, evitando o vazamento de funcionalidades JavaScript.
|
|
|
|
## **`manifest.json`**
|
|
|
|
Uma extensão do Chrome é apenas uma pasta ZIP com uma extensão de arquivo [.crx](https://www.lifewire.com/crx-file-2620391). O núcleo da extensão é o arquivo **`manifest.json`** na raiz da pasta, que especifica o layout, permissões e outras opções de configuração.
|
|
|
|
Exemplo:
|
|
```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`
|
|
|
|
Os scripts de conteúdo são **carregados** sempre que o usuário **navega para uma página correspondente**, no nosso caso qualquer página correspondente à expressão **`https://example.com/*`** e que não corresponda ao regex **`*://*/*/business*`**. Eles são executados **como os próprios scripts da página** e têm acesso arbitrário ao [Modelo de Objeto de Documento (DOM)](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model) da página.
|
|
```json
|
|
"content_scripts": [
|
|
{
|
|
"js": [
|
|
"script.js"
|
|
],
|
|
"matches": [
|
|
"https://example.com/*",
|
|
"https://www.example.com/*"
|
|
],
|
|
"exclude_matches": ["*://*/*business*"],
|
|
}
|
|
],
|
|
```
|
|
Para incluir ou excluir mais URLs, também é possível usar **`include_globs`** e **`exclude_globs`**.
|
|
|
|
Este é um exemplo de script de conteúdo que adicionará um botão de explicação à página quando [a API de armazenamento](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage) for usada para recuperar o valor `message` do armazenamento da extensão.
|
|
```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>
|
|
|
|
Uma mensagem é enviada para as páginas da extensão pelo script de conteúdo quando este botão é clicado, através da utilização da [**API runtime.sendMessage()**](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendMessage). Isso ocorre devido à limitação do script de conteúdo no acesso direto às APIs, sendo `storage` uma das poucas exceções. Para funcionalidades além dessas exceções, mensagens são enviadas para as páginas da extensão com as quais os scripts de conteúdo podem se comunicar.
|
|
|
|
{% hint style="warning" %}
|
|
Dependendo do navegador, as capacidades do script de conteúdo podem variar ligeiramente. Para navegadores baseados em Chromium, a lista de capacidades está disponível na [documentação dos desenvolvedores do Chrome](https://developer.chrome.com/docs/extensions/mv3/content_scripts/#capabilities), e para o Firefox, o [MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#webextension_apis) serve como fonte primária.\
|
|
Também é importante notar que os scripts de conteúdo têm a capacidade de se comunicar com scripts de plano de fundo, permitindo que realizem ações e transmitam respostas de volta.
|
|
{% endhint %}
|
|
|
|
Para visualizar e depurar scripts de conteúdo no Chrome, o menu de ferramentas para desenvolvedores do Chrome pode ser acessado em Opções > Mais ferramentas > Ferramentas do desenvolvedor OU pressionando Ctrl + Shift + I.
|
|
|
|
Ao exibir as ferramentas para desenvolvedores, a **aba Origem** deve ser clicada, seguida pela aba **Scripts de Conteúdo**. Isso permite a observação dos scripts de conteúdo em execução de várias extensões e a definição de pontos de interrupção para rastrear o fluxo de execução.
|
|
|
|
### Scripts de conteúdo injetados
|
|
|
|
{% hint style="success" %}
|
|
Observe que **Scripts de Conteúdo não são obrigatórios** pois também é possível **injetar scripts dinamicamente** e **injetá-los programaticamente** em páginas da web via **`tabs.executeScript`**. Isso, na verdade, fornece mais **controles granulares**.
|
|
{% endhint %}
|
|
|
|
Para a injeção programática de um script de conteúdo, a extensão deve ter [permissões de host](https://developer.chrome.com/docs/extensions/reference/permissions) para a página na qual os scripts serão injetados. Essas permissões podem ser garantidas tanto solicitando-as dentro do manifesto da extensão quanto temporariamente através de [**activeTab**](https://developer.chrome.com/docs/extensions/reference/manifest/activeTab).
|
|
|
|
#### Exemplo de extensão baseada em activeTab
|
|
|
|
{% code title="manifest.json" %}
|
|
```json
|
|
{
|
|
"name": "My extension",
|
|
...
|
|
"permissions": [
|
|
"activeTab",
|
|
"scripting"
|
|
],
|
|
"background": {
|
|
"service_worker": "background.js"
|
|
},
|
|
"action": {
|
|
"default_title": "Action Button"
|
|
}
|
|
}
|
|
```
|
|
{% endcode %}
|
|
|
|
* **Injetar um arquivo JS ao clicar:**
|
|
```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"]
|
|
});
|
|
});
|
|
```
|
|
* **Injetar uma função** ao clicar:
|
|
```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,
|
|
});
|
|
});
|
|
```
|
|
#### Exemplo com permissões 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" });
|
|
```
|
|
Para incluir ou excluir mais URLs, também é possível usar **`include_globs`** e **`exclude_globs`**.
|
|
|
|
### Scripts de Conteúdo `run_at`
|
|
|
|
O campo `run_at` controla **quando os arquivos JavaScript são injetados na página da web**. O valor preferido e padrão é `"document_idle"`.
|
|
|
|
Os valores possíveis são:
|
|
|
|
* **`document_idle`**: Sempre que possível
|
|
* **`document_start`**: Após quaisquer arquivos `css`, mas antes de qualquer outro DOM ser construído ou qualquer outro script ser executado.
|
|
* **`document_end`**: Imediatamente após o DOM estar completo, mas antes de subrecursos como imagens e frames serem carregados.
|
|
|
|
#### Via `manifest.json`
|
|
```json
|
|
{
|
|
"name": "My extension",
|
|
...
|
|
"content_scripts": [
|
|
{
|
|
"matches": ["https://*.example.com/*"],
|
|
"run_at": "document_idle",
|
|
"js": ["contentScript.js"]
|
|
}
|
|
],
|
|
...
|
|
}
|
|
|
|
```
|
|
Através de **`service-worker.js`**
|
|
```javascript
|
|
chrome.scripting.registerContentScripts([{
|
|
id : "test",
|
|
matches : [ "https://*.example.com/*" ],
|
|
runAt : "document_idle",
|
|
js : [ "contentScript.js" ],
|
|
}]);
|
|
```
|
|
### `background`
|
|
|
|
As mensagens enviadas pelos scripts de conteúdo são recebidas pela **página de fundo**, que desempenha um papel central na coordenação dos componentes da extensão. Notavelmente, a página de fundo persiste ao longo da vida da extensão, operando discretamente sem interação direta do usuário. Possui seu próprio Document Object Model (DOM), permitindo interações complexas e gerenciamento de estado.
|
|
|
|
**Pontos Chave**:
|
|
|
|
* **Papel da Página de Fundo:** Age como o centro nervoso da extensão, garantindo a comunicação e coordenação entre várias partes da extensão.
|
|
* **Persistência:** É uma entidade sempre presente, invisível para o usuário, mas fundamental para a funcionalidade da extensão.
|
|
* **Geração Automática:** Se não for explicitamente definida, o navegador criará automaticamente uma página de fundo. Esta página gerada automaticamente incluirá todos os scripts de fundo especificados no manifesto da extensão, garantindo a operação contínua das tarefas de fundo da extensão.
|
|
|
|
{% hint style="success" %}
|
|
A conveniência fornecida pelo navegador ao gerar automaticamente uma página de fundo (quando não declarada explicitamente) garante que todos os scripts de fundo necessários sejam integrados e operacionais, simplificando o processo de configuração da extensão.
|
|
{% endhint %}
|
|
|
|
Exemplo de script de fundo:
|
|
```js
|
|
chrome.runtime.onMessage.addListener((request, sender, sendResponse) =>
|
|
{
|
|
if (request == "explain")
|
|
{
|
|
chrome.tabs.create({ url: "https://example.net/explanation" });
|
|
}
|
|
})
|
|
```
|
|
Utiliza a [API runtime.onMessage](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage) para ouvir mensagens. Quando recebe uma mensagem `"explain"`, utiliza a [API tabs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs) para abrir uma página em uma nova aba.
|
|
|
|
Para depurar o script de segundo plano, você pode ir para os **detalhes da extensão e inspecionar o service worker**, isso abrirá as ferramentas de desenvolvedor com o script de segundo plano:
|
|
|
|
<figure><img src="https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/browser-extension-pentesting-methodology/broken-reference" alt=""><figcaption></figcaption></figure>
|
|
|
|
### Páginas de opções e outras
|
|
|
|
As extensões do navegador podem conter vários tipos de páginas:
|
|
|
|
* **Páginas de ação** são exibidas em um **menu suspenso quando o ícone da extensão é clicado**.
|
|
* Páginas que a extensão irá **carregar em uma nova aba**.
|
|
* **Páginas de opções**: Esta página é exibida sobre a extensão quando clicada. No manifesto anterior, no meu caso, consegui acessar esta página em `chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca` ou clicando em:
|
|
|
|
<figure><img src="../../.gitbook/assets/image (24).png" alt="" width="375"><figcaption></figcaption></figure>
|
|
|
|
Observe que essas páginas não são persistentes como as páginas de segundo plano, pois carregam conteúdo dinamicamente quando necessário. Apesar disso, elas compartilham certas capacidades com a página de segundo plano:
|
|
|
|
* **Comunicação com Scripts de Conteúdo:** Semelhante à página de segundo plano, essas páginas podem receber mensagens de scripts de conteúdo, facilitando a interação dentro da extensão.
|
|
* **Acesso a APIs Específicas da Extensão:** Essas páginas têm amplo acesso a APIs específicas da extensão, sujeitas às permissões definidas para a extensão.
|
|
|
|
### `permissions` e `host_permissions`
|
|
|
|
**`permissions`** e **`host_permissions`** são entradas do `manifest.json` que indicarão **quais permissões** a extensão do navegador possui (armazenamento, localização...) e em **quais páginas da web**.
|
|
|
|
Como as extensões do navegador podem ser tão **privilegiadas**, uma maliciosa ou comprometida poderia permitir ao atacante **diferentes meios de roubar informações sensíveis e espionar o usuário**.
|
|
|
|
Veja como essas configurações funcionam e como podem ser abusadas em:
|
|
|
|
{% 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`
|
|
|
|
Uma **política de segurança de conteúdo** também pode ser declarada dentro do `manifest.json`. Se houver uma definida, ela poderia ser **vulnerável**.
|
|
|
|
A configuração padrão para as páginas de extensão do navegador é bastante restritiva:
|
|
```bash
|
|
script-src 'self'; object-src 'self';
|
|
```
|
|
Para obter mais informações sobre CSP e possíveis formas de contorná-lo, verifique:
|
|
|
|
{% content-ref url="../content-security-policy-csp-bypass/" %}
|
|
[content-security-policy-csp-bypass](../content-security-policy-csp-bypass/)
|
|
{% endcontent-ref %}
|
|
|
|
### `web_accessible_resources`
|
|
|
|
para que uma página da web acesse uma página de uma Extensão do Navegador, uma página `.html`, por exemplo, essa página precisa ser mencionada no campo **`web_accessible_resources`** do `manifest.json`.\
|
|
Por exemplo:
|
|
```javascript
|
|
{
|
|
...
|
|
"web_accessible_resources": [
|
|
{
|
|
"resources": [ "images/*.png" ],
|
|
"matches": [ "https://example.com/*" ]
|
|
},
|
|
{
|
|
"resources": [ "fonts/*.woff" ],
|
|
"matches": [ "https://example.com/*" ]
|
|
}
|
|
],
|
|
...
|
|
}
|
|
```
|
|
Estas páginas são acessíveis em URLs como:
|
|
```
|
|
chrome-extension://<extension-id>/message.html
|
|
```
|
|
Em extensões públicas o **ID da extensão é acessível**:
|
|
|
|
<figure><img src="../../.gitbook/assets/image (1194).png" alt="" width="375"><figcaption></figcaption></figure>
|
|
|
|
No entanto, se o parâmetro `manifest.json` **`use_dynamic_url`** for usado, esse **ID pode ser dinâmico**.
|
|
|
|
{% hint style="success" %}
|
|
Observe que mesmo que uma página seja mencionada aqui, ela pode estar **protegida contra ClickJacking** graças à **Política de Segurança de Conteúdo**. Portanto, você também precisa verificar (seção frame-ancestors) antes de confirmar se um ataque de ClickJacking é possível.
|
|
{% endhint %}
|
|
|
|
Permitir o acesso a essas páginas torna essas páginas **potencialmente vulneráveis ao ClickJacking**:
|
|
|
|
{% content-ref url="browext-clickjacking.md" %}
|
|
[browext-clickjacking.md](browext-clickjacking.md)
|
|
{% endcontent-ref %}
|
|
|
|
{% hint style="success" %}
|
|
Permitir que essas páginas sejam carregadas apenas pela extensão e não por URLs aleatórios poderia prevenir ataques de ClickJacking.
|
|
{% endhint %}
|
|
|
|
{% hint style="danger" %}
|
|
Observe que as páginas de **`web_accessible_resources`** e outras páginas da extensão também são capazes de **contatar scripts de plano de fundo**. Portanto, se uma dessas páginas for vulnerável a **XSS**, poderia abrir uma vulnerabilidade maior.
|
|
|
|
Além disso, observe que você só pode abrir páginas indicadas em **`web_accessible_resources`** dentro de iframes, mas de uma nova guia é possível acessar qualquer página na extensão conhecendo o ID da extensão. Portanto, se um XSS for encontrado abusando dos mesmos parâmetros, ele poderia ser abusado mesmo que a página não esteja configurada em **`web_accessible_resources`**.
|
|
{% endhint %}
|
|
|
|
### `externally_connectable`
|
|
|
|
Conforme a [**documentação**](https://developer.chrome.com/docs/extensions/reference/manifest/externally-connectable), A propriedade de manifesto `"externally_connectable"` declara **quais extensões e páginas da web podem se conectar** à sua extensão via [runtime.connect](https://developer.chrome.com/docs/extensions/reference/runtime#method-connect) e [runtime.sendMessage](https://developer.chrome.com/docs/extensions/reference/runtime#method-sendMessage).
|
|
|
|
* Se a chave **`externally_connectable`** não for declarada no manifesto da sua extensão ou for declarada como **`"ids": ["*"]`**, **todas as extensões podem se conectar, mas nenhuma página da web pode se conectar**.
|
|
* Se **IDs específicos forem especificados**, como em `"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]`, **apenas essas aplicações** podem se conectar.
|
|
* Se **correspondências** forem especificadas, esses aplicativos da web poderão se conectar:
|
|
```json
|
|
"matches": [
|
|
"https://*.google.com/*",
|
|
"*://*.chromium.org/*",
|
|
```
|
|
* Se for especificado como vazio: **`"externally_connectable": {}`**, nenhum aplicativo ou site poderá se conectar.
|
|
|
|
Quanto menos extensões e URLs indicados aqui, menor será a superfície de ataque.
|
|
|
|
{% hint style="danger" %}
|
|
Se uma página da web vulnerável a XSS ou takeover for indicada em **`externally_connectable`**, um atacante poderá enviar mensagens diretamente para o script de fundo, contornando completamente o Content Script e sua CSP.
|
|
|
|
Portanto, este é um **bypass muito poderoso**.
|
|
|
|
Além disso, se o cliente instalar uma extensão maliciosa, mesmo que não seja permitido comunicar com a extensão vulnerável, ela poderá injetar dados de XSS em uma página da web permitida ou abusar das APIs **`WebRequest`** ou **`DeclarativeNetRequest`** para manipular solicitações em um domínio específico alterando a solicitação de uma página para um arquivo **JavaScript**. (Observe que a CSP na página alvo pode prevenir esses ataques). Essa ideia vem [**deste artigo**](https://www.darkrelay.com/post/opera-zero-day-rce-vulnerability).
|
|
{% endhint %}
|
|
|
|
## Resumo da comunicação
|
|
|
|
### Extensão <--> Aplicativo da Web
|
|
|
|
Para se comunicar entre o script de conteúdo e a página da web, geralmente são usadas mensagens post. Portanto, no aplicativo da web, geralmente você encontrará chamadas para a função **`window.postMessage`** e no script de conteúdo ouvintes como **`window.addEventListener`**. No entanto, observe que a extensão também pode **comunicar-se com o aplicativo da web enviando uma Post Message** (e, portanto, o web deve esperar por isso) ou apenas fazer o web carregar um novo script.
|
|
|
|
### Dentro da extensão
|
|
|
|
Normalmente, a função **`chrome.runtime.sendMessage`** é usada para enviar uma mensagem dentro da extensão (geralmente tratada pelo script `background`) e, para receber e lidar com ela, um ouvinte é declarado chamando **`chrome.runtime.onMessage.addListener`**.
|
|
|
|
Também é possível usar **`chrome.runtime.connect()`** para ter uma conexão persistente em vez de enviar mensagens únicas, é possível usá-lo para **enviar** e **receber** **mensagens** como no exemplo a seguir:
|
|
|
|
<details>
|
|
|
|
<summary><code>chrome.runtime.connect()</code> exemplo
|
|
```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>
|
|
|
|
Também é possível enviar mensagens de um script de fundo para um script de conteúdo localizado em uma guia específica chamando **`chrome.tabs.sendMessage`** onde você precisará indicar o **ID da guia** para enviar a mensagem.
|
|
|
|
### De `externally_connectable` permitido para a extensão
|
|
|
|
**Aplicativos da web e extensões de navegador externas permitidas** na configuração `externally_connectable` podem enviar solicitações usando:
|
|
```javascript
|
|
chrome.runtime.sendMessage(extensionId, ...
|
|
```
|
|
Onde for necessário mencionar o **ID da extensão**.
|
|
|
|
## Comunicação entre Web **↔︎** Script de Conteúdo
|
|
|
|
Os ambientes onde os **scripts de conteúdo** operam e onde as páginas hospedeiras existem estão **separados** um do outro, garantindo **isolamento**. Apesar desse isolamento, ambos têm a capacidade de interagir com o **Modelo de Objeto de Documento (DOM)** da página, um recurso compartilhado. Para que a página hospedeira se envolva na comunicação com o **script de conteúdo**, ou indiretamente com a extensão através do script de conteúdo, é necessário utilizar o **DOM** que é acessível por ambas as partes como canal de comunicação.
|
|
|
|
### Mensagens de Postagem
|
|
|
|
{% code title="script-de-conteudo.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 %}
|
|
|
|
Uma comunicação segura de Post Message deve verificar a autenticidade da mensagem recebida, isso pode ser feito verificando:
|
|
|
|
- **`event.isTrusted`**: Isso é True apenas se o evento foi acionado por uma ação do usuário
|
|
- O script de conteúdo pode esperar uma mensagem apenas se o usuário realizar alguma ação
|
|
- **domínio de origem**: pode esperar uma mensagem apenas de uma lista permitida de domínios.
|
|
- Se uma regex for usada, tenha muito cuidado
|
|
- **Fonte**: `received_message.source !== window` pode ser usado para verificar se a mensagem foi **da mesma janela** onde o Content Script está ouvindo.
|
|
|
|
As verificações anteriores, mesmo se realizadas, podem ser vulneráveis, então verifique na seguinte página **possíveis bypasses de Post Message**:
|
|
|
|
{% content-ref url="../postmessage-vulnerabilities/" %}
|
|
[postmessage-vulnerabilities](../postmessage-vulnerabilities/)
|
|
{% endcontent-ref %}
|
|
|
|
### Iframe
|
|
|
|
Outra possível forma de comunicação pode ser através de **URLs de Iframe**, você pode encontrar um exemplo em:
|
|
|
|
{% content-ref url="browext-xss-example.md" %}
|
|
[browext-xss-example.md](browext-xss-example.md)
|
|
{% endcontent-ref %}
|
|
|
|
### DOM
|
|
|
|
Isso não é "exatamente" uma forma de comunicação, mas a **web e o script de conteúdo terão acesso ao DOM da web**. Portanto, se o **script de conteúdo** estiver lendo algumas informações dele, **confiando no DOM da web**, a web poderia **modificar esses dados** (porque a web não deve ser confiável, ou porque a web é vulnerável a XSS) e **comprometer o Content Script**.
|
|
|
|
Você também pode encontrar um exemplo de **XSS baseado em DOM para comprometer uma extensão do navegador** em:
|
|
|
|
{% content-ref url="browext-xss-example.md" %}
|
|
[browext-xss-example.md](browext-xss-example.md)
|
|
{% endcontent-ref %}
|
|
|
|
## Comunicação do Script de Conteúdo **↔︎** Script de Fundo
|
|
|
|
Um Script de Conteúdo pode usar as funções [**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) para enviar uma mensagem **serializável em JSON** única.
|
|
|
|
Para lidar com a **resposta**, use a **Promise** retornada. No entanto, para compatibilidade com versões anteriores, ainda é possível passar um **callback** como último argumento.
|
|
|
|
Enviar uma solicitação de um **script de conteúdo** parece com isso:
|
|
```javascript
|
|
(async () => {
|
|
const response = await chrome.runtime.sendMessage({greeting: "hello"});
|
|
// do something with response here, not outside the function
|
|
console.log(response);
|
|
})();
|
|
```
|
|
Enviar uma solicitação da **extensão** (geralmente um **script de plano de fundo**). Exemplo de como enviar uma mensagem para o script de conteúdo na aba selecionada:
|
|
```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);
|
|
})();
|
|
```
|
|
No **lado receptor**, você precisa configurar um [**runtime.onMessage**](https://developer.chrome.com/docs/extensions/reference/runtime#event-onMessage) **ouvinte de evento** para lidar com a mensagem. Isso parece o mesmo em um script de conteúdo ou página de extensão.
|
|
```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"});
|
|
}
|
|
);
|
|
```
|
|
No exemplo destacado, **`sendResponse()`** foi executado de forma síncrona. Para modificar o manipulador de eventos `onMessage` para execução assíncrona de `sendResponse()`, é imperativo incorporar `return true;`.
|
|
|
|
Uma consideração importante é que em cenários onde várias páginas estão configuradas para receber eventos `onMessage`, **a primeira página a executar `sendResponse()`** para um evento específico será a única capaz de entregar a resposta efetivamente. Quaisquer respostas subsequentes ao mesmo evento não serão consideradas.
|
|
|
|
Ao criar novas extensões, a preferência deve ser para promessas em vez de callbacks. Em relação ao uso de callbacks, a função `sendResponse()` é considerada válida apenas se for executada diretamente no contexto síncrono, ou se o manipulador de eventos indicar uma operação assíncrona retornando `true`. Caso nenhum dos manipuladores retorne `true` ou se a função `sendResponse()` for removida da memória (coletada pelo garbage collector), o callback associado à função `sendMessage()` será acionado por padrão.
|
|
|
|
## Informações Sensíveis na Memória/Código/Área de Transferência
|
|
|
|
Se uma Extensão do Navegador armazena **informações sensíveis em sua memória**, isso poderá ser **dumped** (especialmente em máquinas Windows) e **procurado** por essas informações.
|
|
|
|
Portanto, a memória da Extensão do Navegador **não deve ser considerada segura** e **informações sensíveis** como credenciais ou frases mnemônicas **não devem ser armazenadas**.
|
|
|
|
Claro, **não coloque informações sensíveis no código**, pois elas serão **públicas**.
|
|
|
|
Para fazer dump da memória do navegador, você pode **fazer dump da memória do processo** ou ir para as **configurações** da extensão do navegador clicando em **`Inspect pop-up`** -> Na seção **`Memory`** -> **`Take a snaphost`** e **`CTRL+F`** para pesquisar dentro do snapshot por informações sensíveis.
|
|
|
|
Além disso, informações altamente sensíveis como chaves mnemônicas ou senhas **não devem ser permitidas de serem copiadas na área de transferência** (ou pelo menos removê-las da área de transferência em alguns segundos) porque então processos monitorando a área de transferência poderão obtê-las.
|
|
|
|
## Carregando uma Extensão no Navegador
|
|
|
|
1. **Baixe** a Extensão do Navegador e descompacte
|
|
2. Vá para **`chrome://extensions/`** e **habilite** o `Modo de Desenvolvedor`
|
|
3. Clique no botão **`Load unpacked`**
|
|
|
|
No **Firefox**, vá para **`about:debugging#/runtime/this-firefox`** e clique no botão **`Load Temporary Add-on`**.
|
|
|
|
## Obtendo o código-fonte da loja
|
|
|
|
O código-fonte de uma extensão do Chrome pode ser obtido por vários métodos. Abaixo estão explicações detalhadas e instruções para cada opção.
|
|
|
|
### Baixar Extensão como ZIP via Linha de Comando
|
|
|
|
O código-fonte de uma extensão do Chrome pode ser baixado como um arquivo ZIP usando a linha de comando. Isso envolve usar `curl` para buscar o arquivo ZIP de uma URL específica e depois extrair o conteúdo do arquivo ZIP para um diretório. Aqui estão os passos:
|
|
|
|
1. Substitua `"extension_id"` pelo ID real da extensão.
|
|
2. Execute os seguintes comandos:
|
|
```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"
|
|
```
|
|
### Utilize o site CRX Viewer
|
|
|
|
[https://robwu.nl/crxviewer/](https://robwu.nl/crxviewer/)
|
|
|
|
### Utilize a extensão CRX Viewer
|
|
|
|
Outro método conveniente é usar o Chrome Extension Source Viewer, que é um projeto de código aberto. Pode ser instalado na [Chrome Web Store](https://chrome.google.com/webstore/detail/chrome-extension-source-v/jifpbeccnghkjeaalbbjmodiffmgedin?hl=en). O código-fonte do visualizador está disponível em seu [repositório GitHub](https://github.com/Rob--W/crxviewer).
|
|
|
|
### Visualize o código-fonte da extensão instalada localmente
|
|
|
|
As extensões do Chrome instaladas localmente também podem ser inspecionadas. Veja como:
|
|
|
|
1. Acesse o diretório do perfil local do Chrome visitando `chrome://version/` e localizando o campo "Caminho do Perfil".
|
|
2. Navegue até a subpasta `Extensions/` dentro do diretório do perfil.
|
|
3. Esta pasta contém todas as extensões instaladas, geralmente com seu código-fonte em um formato legível.
|
|
|
|
Para identificar as extensões, você pode mapear seus IDs para nomes:
|
|
|
|
* Ative o Modo de Desenvolvedor na página `about:extensions` para ver os IDs de cada extensão.
|
|
* Dentro da pasta de cada extensão, o arquivo `manifest.json` contém um campo `name` legível, ajudando a identificar a extensão.
|
|
|
|
### Utilize um Arquivador de Arquivos ou Descompactador
|
|
|
|
Vá para a Chrome Web Store e baixe a extensão. O arquivo terá a extensão `.crx`. Altere a extensão do arquivo de `.crx` para `.zip`. Use qualquer arquivador de arquivos (como WinRAR, 7-Zip, etc.) para extrair o conteúdo do arquivo ZIP.
|
|
|
|
### Utilize o Modo Desenvolvedor no Chrome
|
|
|
|
Abra o Chrome e vá para `chrome://extensions/`. Ative o "Modo Desenvolvedor" no canto superior direito. Clique em "Carregar extensão sem compactação...". Navegue até o diretório da sua extensão. Isso não baixa o código-fonte, mas é útil para visualizar e modificar o código de uma extensão já baixada ou desenvolvida.
|
|
|
|
## Lista de Verificação de Auditoria de Segurança
|
|
|
|
Embora as Extensões do Navegador tenham uma **superfície de ataque limitada**, algumas delas podem conter **vulnerabilidades** ou **melhorias de fortalecimento potenciais**. As seguintes são as mais comuns:
|
|
|
|
* [ ] **Limite** o máximo possível as **`permissões`** solicitadas
|
|
* [ ] **Limite** o máximo possível as **`host_permissions`**
|
|
* [ ] Use uma **`content_security_policy`** **forte**
|
|
* [ ] **Limite** o máximo possível o **`externally_connectable`**, se nenhum for necessário e possível, não o deixe por padrão, especifique **`{}`**
|
|
* [ ] Se **URL vulnerável a XSS ou a takeover** for mencionado aqui, um atacante poderá **enviar mensagens diretamente para os scripts de segundo plano**. Um bypass muito poderoso.
|
|
* [ ] **Limite** o máximo possível os **`web_accessible_resources`**, mesmo vazio, se possível.
|
|
* [ ] Se **`web_accessible_resources`** não for nenhum, verifique o [**ClickJacking**](browext-clickjacking.md)
|
|
* [ ] Se houver **comunicação** da **extensão** para a **página da web**, [**verifique XSS**](browext-xss-example.md) **vulnerabilidades** causadas na comunicação.
|
|
* [ ] Se Post Messages forem usados, verifique [**vulnerabilidades de Post Message**](../postmessage-vulnerabilities/)**.**
|
|
* [ ] Se o **Script de Conteúdo acessar detalhes do DOM**, verifique se eles **não estão introduzindo um XSS** se forem **modificados** pela web
|
|
* [ ] Faça um destaque especial se essa comunicação também estiver envolvida na **comunicação do Script de Conteúdo -> Script de segundo plano**
|
|
* **Informações sensíveis não devem ser armazenadas** dentro do código da Extensão do Navegador
|
|
* **Informações sensíveis não devem ser armazenadas** na memória da Extensão do Navegador
|
|
|
|
## Ferramentas
|
|
|
|
### [**Tarnish**](https://thehackerblog.com/tarnish/)
|
|
|
|
* Extrai qualquer extensão do Chrome a partir de um link fornecido da Chrome Web Store.
|
|
* Visualizador de [**manifest.json**](https://developer.chrome.com/extensions/manifest): exibe simplesmente uma versão JSON formatada do manifesto da extensão.
|
|
* Análise de Impressão Digital: Detecção de [web\_accessible\_resources](https://developer.chrome.com/extensions/manifest/web\_accessible\_resources) e geração automática de JavaScript de impressão digital de extensão do Chrome.
|
|
* Análise Potencial de Clickjacking: Detecção de páginas HTML de extensão com a diretiva [web\_accessible\_resources](https://developer.chrome.com/extensions/manifest/web\_accessible\_resources) definida. Estas são potencialmente vulneráveis ao clickjacking, dependendo do propósito das páginas.
|
|
* Visualizador de Aviso(s) de Permissão: que mostra uma lista de todos os avisos de prompt de permissão do Chrome que serão exibidos ao usuário ao tentar instalar a extensão.
|
|
* Função(ões) Perigosa(s): mostra a localização de funções perigosas que poderiam ser potencialmente exploradas por um atacante (por exemplo, funções como innerHTML, chrome.tabs.executeScript).
|
|
* Ponto(s) de Entrada: mostra onde a extensão recebe entrada do usuário/externa. Isso é útil para entender a área de superfície de uma extensão e procurar pontos potenciais para enviar dados maliciosamente criados para a extensão.
|
|
* Tanto as Função(ões) Perigosa(s) quanto os scanners de Ponto(s) de Entrada têm o seguinte para seus alertas gerados:
|
|
* Trecho de código relevante e linha que causou o alerta.
|
|
* Descrição do problema.
|
|
* Um botão "Visualizar Arquivo" para visualizar o arquivo de origem completo contendo o código.
|
|
* O caminho do arquivo alertado.
|
|
* O URI completo da extensão do Chrome do arquivo alertado.
|
|
* O tipo de arquivo que é, como um script de Página de Fundo, Script de Conteúdo, Ação do Navegador, etc.
|
|
* Se a linha vulnerável estiver em um arquivo JavaScript, os caminhos de todas as páginas onde ele está incluído, bem como o status de [web\_accessible\_resource](https://developer.chrome.com/extensions/manifest/web\_accessible\_resources) dessas páginas.
|
|
* Analisador de Política de Segurança de Conteúdo (CSP) e verificador de bypass: Isso apontará fraquezas na CSP da sua extensão e também iluminará quaisquer maneiras potenciais de contornar sua CSP devido a CDNs na lista branca, etc.
|
|
* Bibliotecas Vulneráveis Conhecidas: Isso usa [Retire.js](https://retirejs.github.io/retire.js/) para verificar qualquer uso de bibliotecas JavaScript conhecidas como vulneráveis.
|
|
* Baixar extensão e versões formatadas.
|
|
* Baixar a extensão original.
|
|
* Baixar uma versão embelezada da extensão (HTML e JavaScript automaticamente embelezados).
|
|
* Armazenamento automático de resultados de varredura, executar uma varredura de extensão levará um bom tempo na primeira vez que você a executar. No entanto, na segunda vez, assumindo que a extensão não tenha sido atualizada, será quase instantâneo devido aos resultados serem armazenados em cache.
|
|
* URLs de Relatórios Linkáveis, facilmente vincule alguém a um relatório de extensão gerado pelo tarnish.
|
|
|
|
### [Neto](https://github.com/elevenpaths/neto)
|
|
|
|
O Projeto Neto é um pacote Python 3 concebido para analisar e desvendar recursos ocultos de plugins e extensões do navegador para navegadores conhecidos como Firefox e Chrome. Ele automatiza o processo de descompactar os arquivos empacotados para extrair esses recursos de recursos relevantes em uma extensão como `manifest.json`, pastas de localização ou arquivos de origem Javascript e HTML.
|
|
|
|
## Referências
|
|
|
|
* **Obrigado a** [**@naivenom**](https://twitter.com/naivenom) **pela ajuda com esta metodologia**
|
|
* [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)
|
|
|
|
<details>
|
|
|
|
<summary><strong>Aprenda hacking AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
|
|
|
Outras maneiras de apoiar o HackTricks:
|
|
* Se deseja ver a **sua empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF** Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
|
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
|
|
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
|
* **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
|
* **Compartilhe seus truques de hacking enviando PRs para os** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
|
|
|
|
</details>
|