.. | ||
browext-clickjacking.md | ||
browext-permissions-and-host_permissions.md | ||
browext-xss-example.md | ||
README.md |
Metodología de Pentesting de Extensiones del Navegador
Aprende a hackear AWS desde cero hasta convertirte en un experto con htARTE (HackTricks AWS Red Team Expert)!
Otras formas de apoyar a HackTricks:
- Si deseas ver tu empresa anunciada en HackTricks o descargar HackTricks en PDF Consulta los PLANES DE SUSCRIPCIÓN!
- Obtén merchandising oficial de PEASS & HackTricks
- Descubre La Familia PEASS, nuestra colección exclusiva de NFTs
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @carlospolopm.
- Comparte tus trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Información Básica
Las extensiones del navegador están escritas en JavaScript y se cargan por el navegador en segundo plano. Tiene su DOM pero puede interactuar con los DOM de otros sitios. Esto significa que puede comprometer la confidencialidad, integridad y disponibilidad de otros sitios (CIA).
Componentes Principales
Los diseños de las extensiones se ven mejor cuando se visualizan y constan de tres componentes. Veamos cada componente en detalle.
Scripts de Contenido
Cada script de contenido tiene acceso directo al DOM de una única página web y, por lo tanto, está expuesto a entradas potencialmente maliciosas. Sin embargo, el script de contenido no tiene permisos aparte de la capacidad de enviar mensajes al núcleo de la extensión.
Núcleo de la Extensión
El núcleo de la extensión contiene la mayoría de los privilegios/accesos de la extensión, pero el núcleo de la extensión solo puede interactuar con el contenido web a través de XMLHttpRequest y scripts de contenido. Además, el núcleo de la extensión no tiene acceso directo a la máquina host.
Binario Nativo
La extensión permite un binario nativo que puede acceder a la máquina host con los privilegios completos del usuario. El binario nativo interactúa con el núcleo de la extensión a través de la Interfaz de Programación de Aplicaciones de Plugin de Netscape estándar (NPAPI) utilizada por Flash y otros complementos del navegador.
Límites
{% hint style="danger" %} Para obtener los privilegios completos del usuario, un atacante debe convencer a la extensión de pasar una entrada maliciosa desde el script de contenido al núcleo de la extensión y desde el núcleo de la extensión al binario nativo. {% endhint %}
Cada componente de la extensión está separado entre sí por fuertes límites protectores. Cada componente se ejecuta en un proceso de sistema operativo separado. Los scripts de contenido y los núcleos de extensión se ejecutan en procesos de sandbox no disponibles para la mayoría de los servicios del sistema operativo.
Además, los scripts de contenido se separan de sus páginas web asociadas al ejecutarse en un montón de JavaScript separado. El script de contenido y la página web tienen acceso al mismo DOM subyacente, pero los dos nunca intercambian punteros de JavaScript, evitando la filtración de funcionalidades de JavaScript.
manifest.json
Una extensión de Chrome es simplemente una carpeta ZIP con una extensión de archivo .crx. El núcleo de la extensión es el archivo manifest.json
en la raíz de la carpeta, que especifica el diseño, los permisos y otras opciones de configuración.
Ejemplo:
{
"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
Los scripts de contenido se cargan cada vez que el usuario navega a una página coincidente, en nuestro caso cualquier página que coincida con la expresión https://example.com/*
y que no coincida con el regex *://*/*/business*
. Se ejecutan como los propios scripts de la página y tienen acceso arbitrario al Modelo de Objetos del Documento (DOM) de la página.
"content_scripts": [
{
"js": [
"script.js"
],
"matches": [
"https://example.com/*",
"https://www.example.com/*"
],
"exclude_matches": ["*://*/*business*"],
}
],
Para incluir o excluir más URLs también es posible utilizar include_globs
y exclude_globs
.
Este es un ejemplo de script de contenido que agregará un botón de explicación a la página cuando la API de almacenamiento para recuperar el valor message
del almacenamiento de la extensión.
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);
});
Un mensaje es enviado a las páginas de la extensión por el script de contenido cuando se hace clic en este botón, a través de la utilización de la API runtime.sendMessage(). Esto se debe a la limitación del script de contenido en el acceso directo a las APIs, siendo storage
una de las pocas excepciones. Para funcionalidades más allá de estas excepciones, se envían mensajes a las páginas de la extensión con las que los scripts de contenido pueden comunicarse.
{% hint style="warning" %}
Dependiendo del navegador, las capacidades del script de contenido pueden variar ligeramente. Para los navegadores basados en Chromium, la lista de capacidades está disponible en la documentación de Chrome Developers, y para Firefox, la MDN sirve como fuente principal.
También es importante tener en cuenta que los scripts de contenido tienen la capacidad de comunicarse con los scripts de fondo, lo que les permite realizar acciones y transmitir respuestas de vuelta.
{% endhint %}
Para ver y depurar scripts de contenido en Chrome, se puede acceder al menú de herramientas para desarrolladores de Chrome desde Opciones > Más herramientas > Herramientas para desarrolladores O presionando Ctrl + Shift + I.
Una vez que se muestren las herramientas para desarrolladores, se debe hacer clic en la pestaña Source, seguido por la pestaña Content Scripts. Esto permite observar los scripts de contenido en ejecución de varias extensiones y establecer puntos de interrupción para rastrear el flujo de ejecución.
Scripts de contenido inyectados
{% hint style="success" %}
Tenga en cuenta que los Scripts de Contenido no son obligatorios ya que también es posible inyectar scripts dinámicamente y inyectarlos programáticamente en páginas web a través de tabs.executeScript
. Esto proporciona en realidad un mayor control granular.
{% endhint %}
Para la inyección programática de un script de contenido, la extensión debe tener permisos de host para la página en la que se van a inyectar los scripts. Estos permisos pueden ser asegurados ya sea solicitándolos dentro del manifiesto de la extensión o de forma temporal a través de activeTab.
Ejemplo de extensión basada en activeTab
{% code title="manifest.json" %}
{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
{% endcode %}
- Inyectar un archivo JS al hacer clic:
// 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"]
});
});
- Inyectar una función al hacer clic:
//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,
});
});
Ejemplo con permisos de script
// 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" });
Scripts de Contenido run_at
El campo run_at
controla cuándo se inyectan archivos JavaScript en la página web. El valor preferido y predeterminado es "document_idle"
.
Los valores posibles son:
document_idle
: Siempre que sea posibledocument_start
: Después de cualquier archivocss
, pero antes de que se construya cualquier otro DOM o se ejecute cualquier otro script.document_end
: Inmediatamente después de que el DOM esté completo, pero antes de que se carguen subrecursos como imágenes y frames.
A través de manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.example.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}
A través de service-worker.js
chrome.scripting.registerContentScripts([{
id : "test",
matches : [ "https://*.example.com/*" ],
runAt : "document_idle",
js : [ "contentScript.js" ],
}]);
antecedentes
Los mensajes enviados por los scripts de contenido son recibidos por la página de fondo, la cual desempeña un papel central en la coordinación de los componentes de la extensión. Es importante destacar que la página de fondo persiste a lo largo de la vida de la extensión, operando discretamente sin interacción directa del usuario. Posee su propio Modelo de Objetos del Documento (DOM), lo que permite interacciones complejas y gestión de estado.
Puntos Clave:
- Rol de la Página de Fondo: Actúa como el centro nervioso de la extensión, garantizando la comunicación y coordinación entre las diversas partes de la extensión.
- Persistencia: Es una entidad siempre presente, invisible para el usuario pero integral para la funcionalidad de la extensión.
- Generación Automática: Si no se define explícitamente, el navegador creará automáticamente una página de fondo. Esta página generada automáticamente incluirá todos los scripts de fondo especificados en el manifiesto de la extensión, asegurando el funcionamiento sin problemas de las tareas de fondo de la extensión.
{% hint style="success" %} La conveniencia proporcionada por el navegador al generar automáticamente una página de fondo (cuando no se declara explícitamente) garantiza que todos los scripts de fondo necesarios estén integrados y operativos, agilizando el proceso de configuración de la extensión. {% endhint %}
Ejemplo de script de fondo:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) =>
{
if (request == "explain")
{
chrome.tabs.create({ url: "https://example.net/explanation" });
}
})
Utiliza la API runtime.onMessage para escuchar mensajes. Cuando se recibe un mensaje "explain"
, utiliza la API tabs para abrir una página en una nueva pestaña.
Para depurar el script de fondo, puedes ir a los detalles de la extensión e inspeccionar el service worker, esto abrirá las herramientas de desarrollo con el script de fondo:
Páginas de opciones y otras
Las extensiones del navegador pueden contener varios tipos de páginas:
- Las páginas de acción se muestran en un menú desplegable al hacer clic en el ícono de la extensión.
- Páginas que la extensión cargará en una nueva pestaña.
- Páginas de opciones: Esta página se muestra encima de la extensión al hacer clic. En el manifiesto anterior, pude acceder a esta página en
chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca
o haciendo clic en:
Ten en cuenta que estas páginas no son persistentes como las páginas de fondo, ya que cargan contenido dinámicamente según sea necesario. A pesar de esto, comparten ciertas capacidades con la página de fondo:
- Comunicación con Scripts de Contenido: Al igual que la página de fondo, estas páginas pueden recibir mensajes de scripts de contenido, facilitando la interacción dentro de la extensión.
- Acceso a APIs Específicas de la Extensión: Estas páginas tienen un amplio acceso a APIs específicas de la extensión, sujeto a los permisos definidos para la extensión.
permissions
y host_permissions
permissions
y host_permissions
son entradas del manifest.json
que indicarán qué permisos tiene la extensión del navegador (almacenamiento, ubicación...) y en qué páginas web.
Dado que las extensiones del navegador pueden ser tan privilegiadas, una maliciosa o comprometida podría permitir al atacante diferentes medios para robar información sensible y espiar al usuario.
Consulta cómo funcionan estos ajustes y cómo podrían ser abusados en:
{% content-ref url="browext-permissions-and-host_permissions.md" %} browext-permissions-and-host_permissions.md {% endcontent-ref %}
content_security_policy
Una política de seguridad de contenido también se puede declarar dentro del manifest.json
. Si está definida, podría ser vulnerable.
La configuración predeterminada para las páginas de extensiones del navegador es bastante restrictiva:
script-src 'self'; object-src 'self';
Para obtener más información sobre CSP y posibles bypass, consulta:
{% content-ref url="../content-security-policy-csp-bypass/" %} content-security-policy-csp-bypass {% endcontent-ref %}
web_accessible_resources
para que una página web pueda acceder a una página de una Extensión del Navegador, por ejemplo, una página .html
, esta página debe ser mencionada en el campo web_accessible_resources
del manifest.json
.
Por ejemplo:
{
...
"web_accessible_resources": [
{
"resources": [ "images/*.png" ],
"matches": [ "https://example.com/*" ]
},
{
"resources": [ "fonts/*.woff" ],
"matches": [ "https://example.com/*" ]
}
],
...
}
Estas páginas son accesibles en URL como:
chrome-extension://<extension-id>/message.html
En las extensiones públicas el identificador de extensión es accesible:
Sin embargo, si se utiliza el parámetro use_dynamic_url
en el archivo manifest.json
, este id puede ser dinámico.
{% hint style="success" %} Ten en cuenta que aunque se mencione una página aquí, esta podría estar protegida contra ClickJacking gracias a la Política de Seguridad de Contenido. Por lo tanto, también debes verificarlo (sección de frame-ancestors) antes de confirmar si es posible un ataque de ClickJacking. {% endhint %}
Permitir el acceso a estas páginas hace que estas sean potencialmente vulnerables al ClickJacking:
{% content-ref url="browext-clickjacking.md" %} browext-clickjacking.md {% endcontent-ref %}
{% hint style="success" %} Permitir que estas páginas se carguen solo por la extensión y no por URLs aleatorias podría prevenir ataques de ClickJacking. {% endhint %}
{% hint style="danger" %}
Ten en cuenta que las páginas de web_accessible_resources
y otras páginas de la extensión también pueden contactar a scripts de fondo. Por lo tanto, si una de estas páginas es vulnerable a XSS, podría abrir una vulnerabilidad mayor.
Además, ten en cuenta que solo puedes abrir páginas indicadas en web_accessible_resources
dentro de iframes, pero desde una nueva pestaña es posible acceder a cualquier página en la extensión conociendo el ID de la extensión. Por lo tanto, si se encuentra un XSS abusando de los mismos parámetros, podría ser abusado incluso si la página no está configurada en web_accessible_resources
.
{% endhint %}
externally_connectable
Según la documentación, la propiedad del manifiesto "externally_connectable"
declara qué extensiones y páginas web pueden conectarse a tu extensión a través de runtime.connect y runtime.sendMessage.
- Si la clave
externally_connectable
no está declarada en el manifiesto de tu extensión o se declara como"ids": ["*"]
, todas las extensiones pueden conectarse, pero ninguna página web puede conectarse. - Si se especifican IDs específicos, como en
"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
, solo esas aplicaciones pueden conectarse. - Si se especifican coincidencias, esas aplicaciones web podrán conectarse:
"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
- Si se especifica como vacío:
"externally_connectable": {}
, ninguna aplicación o página web podrá conectarse.
Cuanto menos extensiones y URLs se indiquen aquí, menor será la superficie de ataque.
{% hint style="danger" %}
Si una página web vulnerable a XSS o a una toma de control está indicada en externally_connectable
, un atacante podrá enviar mensajes directamente al script de fondo, evitando por completo el Content Script y su CSP.
Por lo tanto, este es un bypass muy poderoso.
Además, si el cliente instala una extensión maliciosa, incluso si no se le permite comunicarse con la extensión vulnerable, podría inyectar datos XSS en una página web permitida o abusar de las APIs WebRequest
o DeclarativeNetRequest
para manipular solicitudes en un dominio específico alterando la solicitud de una página para un archivo JavaScript. (Tenga en cuenta que el CSP en la página objetivo podría prevenir estos ataques). Esta idea proviene de este informe.
{% endhint %}
Resumen de la comunicación
Extensión <--> Aplicación web
Para comunicarse entre el script de contenido y la página web, generalmente se utilizan mensajes post. Por lo tanto, en la aplicación web generalmente encontrarás llamadas a la función window.postMessage
y en el script de contenido oyentes como window.addEventListener
. Sin embargo, la extensión también podría comunicarse con la aplicación web enviando un mensaje post (y por lo tanto la web debería esperarlo) o simplemente hacer que la web cargue un nuevo script.
Dentro de la extensión
Por lo general, se utiliza la función chrome.runtime.sendMessage
para enviar un mensaje dentro de la extensión (generalmente manejado por el script background
) y para recibirlo y manejarlo se declara un oyente llamando a chrome.runtime.onMessage.addListener
.
También es posible usar chrome.runtime.connect()
para tener una conexión persistente en lugar de enviar mensajes individuales, es posible usarlo para enviar y recibir mensajes como en el siguiente ejemplo:
Ejemplo de chrome.runtime.connect()
chrome.runtime.connect()
```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>
También es posible enviar mensajes desde un script de fondo a un script de contenido ubicado en una pestaña específica llamando a **`chrome.tabs.sendMessage`** donde deberás indicar el **ID de la pestaña** al que deseas enviar el mensaje.
### Desde `externally_connectable` permitido a la extensión
Las **aplicaciones web y extensiones de navegador externas permitidas** en la configuración `externally_connectable` pueden enviar solicitudes utilizando:
```javascript
chrome.runtime.sendMessage(extensionId, ...
Donde sea necesario mencionar el ID de la extensión.
Comunicación entre el Script de Contenido y la Web
Los entornos donde operan los scripts de contenido y donde existen las páginas anfitrionas están separados entre sí, asegurando aislamiento. A pesar de este aislamiento, ambos tienen la capacidad de interactuar con el Modelo de Objetos del Documento (DOM) de la página, un recurso compartido. Para que la página anfitriona se comunique con el script de contenido, o indirectamente con la extensión a través del script de contenido, es necesario utilizar el DOM al que ambas partes pueden acceder como canal de comunicación.
Mensajes de Publicación
{% code title="content-script.js" %}
// 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" %}
document.getElementById("theButton").addEventListener("click", () => {
window.postMessage(
{type : "FROM_PAGE", text : "Hello from the webpage!"}, "*");
}, false);
{% endcode %}
Una comunicación segura de Post Message debería verificar la autenticidad del mensaje recibido, esto se puede hacer verificando:
event.isTrusted
: Esto es Verdadero solo si el evento fue desencadenado por una acción del usuario.
- El script de contenido podría esperar un mensaje solo si el usuario realiza alguna acción.
- Dominio de origen: podría esperar un mensaje solo de una lista blanca de dominios.
- Si se usa una expresión regular, tenga mucho cuidado.
- Origen:
received_message.source !== window
se puede usar para verificar si el mensaje fue de la misma ventana donde el Script de Contenido está escuchando.
Las verificaciones anteriores, incluso si se realizan, podrían ser vulnerables, así que verifique en la siguiente página posibles bypasses de Post Message:
{% content-ref url="../postmessage-vulnerabilities/" %}
postmessage-vulnerabilities
{% endcontent-ref %}
Iframe
Otra posible forma de comunicación podría ser a través de URLs de Iframe, puedes encontrar un ejemplo en:
{% content-ref url="browext-xss-example.md" %}
browext-xss-example.md
{% endcontent-ref %}
DOM
Esto no es "exactamente" una forma de comunicación, pero la web y el script de contenido tendrán acceso al DOM web. Entonces, si el script de contenido está leyendo alguna información de él, confiando en el DOM web, la web podría modificar estos datos (porque la web no debería ser confiable, o porque la web es vulnerable a XSS) y comprometer el Script de Contenido.
También puedes encontrar un ejemplo de un XSS basado en DOM para comprometer una extensión del navegador en:
{% content-ref url="browext-xss-example.md" %}
browext-xss-example.md
{% endcontent-ref %}
Comunicación entre Script de Contenido ↔︎ Script de Fondo
Un Script de Contenido puede usar las funciones runtime.sendMessage() o tabs.sendMessage() para enviar un mensaje serializable en JSON de una sola vez.
Para manejar la respuesta, use la Promesa devuelta. Aunque, para compatibilidad con versiones anteriores, aún puede pasar un callback como último argumento.
Enviar una solicitud desde un script de contenido se ve así:
(async () => {
const response = await chrome.runtime.sendMessage({greeting: "hello"});
// do something with response here, not outside the function
console.log(response);
})();
Enviar una solicitud desde la extensión (generalmente un script de fondo). Ejemplo de cómo enviar un mensaje al script de contenido en la pestaña seleccionada:
// 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);
})();
En el extremo receptor, necesitas configurar un runtime.onMessage escuchador de eventos para manejar el mensaje. Esto se ve igual ya sea desde un script de contenido o una página de extensión.
// 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"});
}
);
En el ejemplo resaltado, sendResponse()
se ejecutó de forma síncrona. Para modificar el controlador de eventos onMessage
para la ejecución asíncrona de sendResponse()
, es imperativo incorporar return true;
.
Una consideración importante es que en escenarios donde múltiples páginas están configuradas para recibir eventos onMessage
, la primera página en ejecutar sendResponse()
para un evento específico será la única capaz de entregar la respuesta de manera efectiva. Cualquier respuesta posterior al mismo evento no será tomada en cuenta.
Al crear nuevas extensiones, la preferencia debería ser hacia las promesas en lugar de los callbacks. En cuanto al uso de callbacks, la función sendResponse()
se considera válida solo si se ejecuta directamente dentro del contexto síncrono, o si el controlador de eventos indica una operación asíncrona al devolver true
. Si ninguno de los controladores devuelve true
o si la función sendResponse()
es eliminada de la memoria (recolectada por el recolector de basura), el callback asociado con la función sendMessage()
se activará por defecto.
Información Sensible en Memoria/Código/Portapapeles
Si una Extensión del Navegador almacena información sensible dentro de su memoria, esta podría ser volcada (especialmente en máquinas Windows) y buscada para obtener esta información.
Por lo tanto, la memoria de la Extensión del Navegador no debería considerarse segura y la información sensible como credenciales o frases mnemónicas no deberían ser almacenadas.
Por supuesto, no coloques información sensible en el código, ya que será pública.
Para volcar la memoria del navegador podrías volcar la memoria del proceso o ir a la configuración de la extensión del navegador haciendo clic en Inspeccionar ventana emergente
-> En la sección Memoria
-> Tomar una captura
y CTRL+F
para buscar dentro de la captura información sensible.
Además, información altamente sensible como claves mnemónicas o contraseñas no deberían permitirse ser copiadas en el portapapeles (o al menos eliminarlas del portapapeles en unos pocos segundos) porque los procesos que monitorean el portapapeles podrán obtenerlas.
Cargando una Extensión en el Navegador
- Descarga la Extensión del Navegador y descomprímela
- Ve a
chrome://extensions/
y habilita el Modo desarrollador
- Haz clic en el botón
Cargar sin empaquetar
En Firefox ve a about:debugging#/runtime/this-firefox
y haz clic en el botón Cargar complemento temporal
.
Obteniendo el código fuente desde la tienda
El código fuente de una extensión de Chrome se puede obtener a través de varios métodos. A continuación se detallan explicaciones e instrucciones para cada opción.
Descargar Extensión como ZIP a través de la Línea de Comandos
El código fuente de una extensión de Chrome se puede descargar como un archivo ZIP usando la línea de comandos. Esto implica usar curl
para obtener el archivo ZIP desde una URL específica y luego extraer el contenido del archivo ZIP a un directorio. Aquí están los pasos:
- Reemplaza
"extension_id"
con el ID real de la extensión.
- Ejecuta los siguientes comandos:
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"
Utilizar el sitio web CRX Viewer
Utilizar la extensión CRX Viewer
Otro método conveniente es utilizar el Visor de Código Fuente de la Extensión de Chrome, que es un proyecto de código abierto. Se puede instalar desde la Chrome Web Store. El código fuente del visor está disponible en su repositorio de GitHub.
Ver el código fuente de una extensión instalada localmente
Las extensiones de Chrome instaladas localmente también se pueden inspeccionar. Así es cómo:
- Accede al directorio de perfil local de Chrome visitando
chrome://version/
y localizando el campo "Ruta del perfil".
- Navega a la subcarpeta
Extensions/
dentro del directorio del perfil.
- Esta carpeta contiene todas las extensiones instaladas, típicamente con su código fuente en un formato legible.
Para identificar las extensiones, puedes mapear sus IDs a nombres:
- Habilita el Modo Desarrollador en la página
about:extensions
para ver las IDs de cada extensión.
- Dentro de la carpeta de cada extensión, el archivo
manifest.json
contiene un campo name
legible, que te ayuda a identificar la extensión.
Utilizar un Archivador de Archivos o Desempaquetador
Ve a la Chrome Web Store y descarga la extensión. El archivo tendrá una extensión .crx
. Cambia la extensión del archivo de .crx
a .zip
. Utiliza cualquier archivador de archivos (como WinRAR, 7-Zip, etc.) para extraer el contenido del archivo ZIP.
Utilizar el Modo Desarrollador en Chrome
Abre Chrome y ve a chrome://extensions/
. Habilita "Modo desarrollador" en la esquina superior derecha. Haz clic en "Cargar extensión sin empaquetar...". Navega al directorio de tu extensión. Esto no descarga el código fuente, pero es útil para ver y modificar el código de una extensión ya descargada o desarrollada.
Lista de Verificación de Auditoría de Seguridad
Aunque las Extensiones del Navegador tienen una superficie de ataque limitada, algunas de ellas podrían contener vulnerabilidades o mejoras potenciales de endurecimiento. Las siguientes son las más comunes:
- Limitar tanto como sea posible las
permissions
solicitadas.
- Limitar tanto como sea posible las
host_permissions
.
- Utilizar una
content_security_policy
fuerte.
- Limitar tanto como sea posible el
externally_connectable
, si no se necesita ninguno y es posible, no dejarlo por defecto, especificar {}
.
- Si se menciona una URL vulnerable a XSS o a toma de control, un atacante podrá enviar mensajes directamente a los scripts de fondo. Un bypass muy poderoso.
- Limitar tanto como sea posible los
web_accessible_resources
, incluso vacío si es posible.
- Si
web_accessible_resources
no es ninguno, verificar ClickJacking.
- Si hay alguna comunicación desde la extensión a la página web, verificar XSS vulnerabilidades causadas en la comunicación.
- Si se utilizan Mensajes Post, verificar vulnerabilidades de Mensajes Post.
- Si el Script de Contenido accede a detalles del DOM, verificar que no estén introduciendo un XSS si son modificados por la web.
- Hacer un énfasis especial si esta comunicación también está involucrada en la comunicación del Script de Contenido -> Script de Fondo.
- La información sensible no debe ser almacenada dentro del código de la Extensión del Navegador.
- La información sensible no debe ser almacenada en la memoria de la Extensión del Navegador.
Herramientas
Tarnish
- Extrae cualquier extensión de Chrome desde un enlace proporcionado de la tienda web de Chrome.
- Visor de manifest.json: simplemente muestra una versión JSON embellecida del manifiesto de la extensión.
- Análisis de Huella Digital: Detección de web_accessible_resources y generación automática de JavaScript de huella digital de extensión de Chrome.
- Análisis Potencial de Clickjacking: Detección de páginas HTML de extensión con la directiva web_accessible_resources establecida. Estas son potencialmente vulnerables a clickjacking dependiendo del propósito de las páginas.
- Visor de Advertencias de Permisos: que muestra una lista de todas las advertencias de permisos de Chrome que se mostrarán al intentar instalar la extensión.
- Función(es) Peligrosa(s): muestra la ubicación de funciones peligrosas que podrían ser explotadas por un atacante (por ejemplo, funciones como innerHTML, chrome.tabs.executeScript).
- Punto(s) de Entrada: muestra dónde la extensión recibe entrada de usuario/externa. Esto es útil para comprender el área de superficie de una extensión y buscar puntos potenciales para enviar datos maliciosamente elaborados a la extensión.
- Tanto los escáneres de Función(es) Peligrosa(s) como de Punto(s) de Entrada tienen lo siguiente para sus alertas generadas:
- Fragmento de código relevante y línea que causó la alerta.
- Descripción del problema.
- Un botón "Ver Archivo" para ver el archivo fuente completo que contiene el código.
- La ruta del archivo alertado.
- La URI completa de la extensión de Chrome del archivo alertado.
- El tipo de archivo que es, como un script de Página de Fondo, Script de Contenido, Acción del Navegador, etc.
- Si la línea vulnerable está en un archivo JavaScript, las rutas de todas las páginas donde se incluye, así como el tipo de estas páginas y el estado de web_accessible_resource.
- Analizador y verificador de bypass de Política de Seguridad de Contenido (CSP): Esto señalará debilidades en la CSP de tu extensión e iluminará cualquier forma potencial de eludir tu CSP debido a CDNs en lista blanca, etc.
- Bibliotecas Vulnerables Conocidas: Utiliza Retire.js para verificar cualquier uso de bibliotecas JavaScript conocidas como vulnerables.
- Descargar extensión y versiones formateadas.
- Descargar la extensión original.
- Descargar una versión embellecida de la extensión (HTML y JavaScript auto embellecidos).
- Caché automático de resultados de escaneo, ejecutar un escaneo de extensión tomará una buena cantidad de tiempo la primera vez que lo ejecutes. Sin embargo, la segunda vez, asumiendo que la extensión no se haya actualizado, será casi instantánea debido a que los resultados están en caché.
- URLs de Informes Enlazables, enlaza fácilmente a alguien más a un informe de extensión generado por tarnish.
Neto
El Proyecto Neto es un paquete de Python 3 concebido para analizar y desentrañar características ocultas de complementos y extensiones de navegador para navegadores conocidos como Firefox y Chrome. Automatiza el proceso de descomprimir los archivos empaquetados para extraer estas características de recursos relevantes en una extensión como manifest.json
, carpetas de localización o archivos fuente de Javascript y HTML.
Referencias
- Gracias a @naivenom por la ayuda con esta metodología
- 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/24/attack-surface-of-extension-pages/
- https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/
- 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/mv2/background-pages
- https://thehackerblog.com/kicking-the-rims-a-guide-for-securely-writing-and-auditing-chrome-extensions/
- https://gist.github.com/LongJohnCoder/9ddf5735df3a4f2e9559665fb864eac0
Aprende hacking de AWS desde cero hasta experto con htARTE (HackTricks AWS Red Team Expert)!
Otras formas de apoyar a HackTricks:
- Si deseas ver tu empresa anunciada en HackTricks o descargar HackTricks en PDF ¡Consulta los PLANES DE SUSCRIPCIÓN!
- Obtén la merchandising oficial de PEASS & HackTricks
- Descubre La Familia PEASS, nuestra colección exclusiva de NFTs
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @carlospolopm.
- Comparte tus trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.