Browser Extension Pentesting Methodology
Last updated
Last updated
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Las extensiones de navegador están escritas en JavaScript y son cargadas por el navegador en segundo plano. Tienen su DOM pero pueden interactuar con los DOM de otros sitios. Esto significa que puede comprometer la confidencialidad, integridad y disponibilidad (CIA) de otros sitios.
Los diseños de las extensiones se ven mejor cuando se visualizan y constan de tres componentes. Veamos cada componente en profundidad.
Cada script de contenido tiene acceso directo al DOM de una única página web y está expuesto a entrada potencialmente maliciosa. Sin embargo, el script de contenido no contiene permisos aparte de la capacidad de enviar mensajes al 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.
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 plugins de Netscape estándar (NPAPI) utilizada por Flash y otros complementos de navegador.
Para obtener los privilegios completos del usuario, un atacante debe convencer a la extensión de pasar 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.
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 están separados 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, lo que previene la filtración de funcionalidad de JavaScript.
manifest.json
Una extensión de Chrome es solo una carpeta ZIP con una .crx file extension. El núcleo de la extensión es el manifest.json
archivo en la raíz de la carpeta, que especifica el diseño, permisos y otras opciones de configuración.
Ejemplo:
content_scripts
Los scripts de contenido se cargan cada vez que el usuario navega a una página que coincide, en nuestro caso, cualquier página que coincida con la expresión https://example.com/*
y que no coincida con la 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.
Para incluir o excluir más URLs, también es posible usar include_globs
y exclude_globs
.
Este es un ejemplo de script de contenido que añadirá un botón de explicación a la página cuando la API de almacenamiento para recuperar el valor de message
del almacenamiento de la extensión.
Un mensaje se envía 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 runtime.sendMessage() API. 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.
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, el MDN sirve como la fuente principal. También es notable que los scripts de contenido tienen la capacidad de comunicarse con los scripts de fondo, lo que les permite realizar acciones y retransmitir respuestas.
Para ver y depurar scripts de contenido en Chrome, se puede acceder al menú de herramientas de desarrollador de Chrome desde Opciones > Más herramientas > Herramientas de desarrollador O presionando Ctrl + Shift + I.
Una vez que se muestran las herramientas de desarrollador, se debe hacer clic en la pestaña Fuente, seguida de la pestaña Scripts de Contenido. 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.
Tenga en cuenta que los Scripts de Contenido no son obligatorios ya que también es posible inyectar dinámicamente scripts y inyectarlos programáticamente en páginas web a través de tabs.executeScript
. Esto en realidad proporciona un control más granular.
Para la inyección programática de un script de contenido, se requiere que la extensión tenga permisos de host para la página en la que se van a inyectar los scripts. Estos permisos pueden asegurarse ya sea solicitándolos dentro del manifiesto de la extensión o de manera temporal a través de activeTab.
Inyectar un archivo JS al hacer clic:
Inyectar una función al hacer clic:
Para incluir o excluir más URLs, también es posible usar include_globs
y exclude_globs
.
run_at
El campo run_at
controla cuándo se inyectan los archivos JavaScript en la página web. El valor preferido y predeterminado es "document_idle"
.
Los valores posibles son:
document_idle
: Siempre que sea posible
document_start
: Después de cualquier archivo de css
, 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 hayan cargado subrecursos como imágenes y marcos.
manifest.json
A través de service-worker.js
background
Los mensajes enviados por los scripts de contenido son recibidos por la página de fondo, que desempeña un papel central en la coordinación de los componentes de la extensión. Notablemente, 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 del estado.
Puntos Clave:
Rol de la Página de Fondo: Actúa como el centro neurálgico de la extensión, asegurando 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.
La conveniencia proporcionada por el navegador al generar automáticamente una página de fondo (cuando no se declara explícitamente) asegura que todos los scripts de fondo necesarios estén integrados y operativos, simplificando el proceso de configuración de la extensión.
Ejemplo de script de fondo:
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:
Las extensiones de navegador pueden contener varios tipos de páginas:
Las páginas de acción se muestran en un menú desplegable cuando se hace 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 en la parte superior de la extensión cuando se hace clic. En el manifiesto anterior, en mi caso, 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: Similar a 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 disfrutan de acceso completo a APIs específicas de la extensión, sujeto a los permisos definidos para la extensión.
permissions
& 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 de navegador pueden ser tan privilegiadas, una maliciosa o una que haya sido comprometida podría permitir al atacante diferentes medios para robar información sensible y espiar al usuario.
Consulta cómo funcionan estas configuraciones y cómo podrían ser abusadas en:
BrowExt - permissions & host_permissionscontent_security_policy
Una política de seguridad de contenido también puede declararse dentro del manifest.json
. Si hay una definida, podría ser vulnerable.
La configuración predeterminada para las páginas de extensiones de navegador es bastante restrictiva:
Para más información sobre CSP y posibles bypasses, consulta:
Content Security Policy (CSP) Bypassweb_accessible_resources
Para que una página web acceda a una página de una extensión de navegador, una página .html
por ejemplo, esta página debe mencionarse en el campo web_accessible_resources
del manifest.json
.
Por ejemplo:
Estas páginas son accesibles en URL como:
En las extensiones públicas, el extension-id es accesible:
Sin embargo, si se utiliza el parámetro use_dynamic_url
en manifest.json
, este id puede ser dinámico.
Ten en cuenta que incluso si una página se menciona aquí, podría estar protegida contra ClickJacking gracias a la Content Security Policy. Así que también necesitas verificarlo (sección frame-ancestors) antes de confirmar que un ataque de ClickJacking es posible.
El acceso a estas páginas hace que estas páginas sean potencialmente vulnerables a ClickJacking:
BrowExt - ClickJackingPermitir que estas páginas se carguen solo por la extensión y no por URLs aleatorias podría prevenir ataques de ClickJacking.
Ten en cuenta que las páginas de web_accessible_resources
y otras páginas de la extensión también son capaces de contactar scripts de fondo. Así que 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 explotado incluso si la página no está configurada en web_accessible_resources
.
externally_connectable
Según la documentación, la propiedad de 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 está declarada 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:
Si se especifica como vacío: "externally_connectable": {}
, ninguna aplicación o web podrá conectarse.
Cuantas menos extensiones y URLs se indiquen aquí, menor será la superficie de ataque.
Si una página web vulnerable a XSS o takeover se indica en externally_connectable
, un atacante podrá enviar mensajes directamente al script de fondo, eludiendo completamente 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 objetivo alterando la solicitud de una archivo JavaScript. (Tenga en cuenta que el CSP en la página objetivo podría prevenir estos ataques). Esta idea proviene de este informe.
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á llamadas a la función window.postMessage
y en el script de contenido oyentes como window.addEventListener
. Sin embargo, tenga en cuenta que la extensión también podría comunicarse con la aplicación web enviando un Post Message (y por lo tanto la web debería esperarlo) o simplemente hacer que la web cargue un nuevo script.
Generalmente 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:
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)