Browser Extension Pentesting Methodology
基本信息
浏览器扩展是用 JavaScript 编写的,并由浏览器在后台加载。它有自己的 DOM,但可以与其他网站的 DOM 进行交互。这意味着它可能会危害其他网站的机密性、完整性和可用性(CIA)。
主要组件
扩展布局在可视化时效果最佳,由三个组件组成。让我们深入了解每个组件。
内容脚本
每个内容脚本可以直接访问 单个网页 的 DOM,因此暴露于 潜在的恶意输入。然而,内容脚本除了能够向扩展核心发送消息外,没有其他权限。
扩展核心
扩展核心包含大部分扩展权限/访问,但扩展核心只能通过 XMLHttpRequest 和内容脚本与网页内容进行交互。此外,扩展核心无法直接访问主机机器。
本地二进制
扩展允许一个本地二进制文件,可以 以用户的完全权限访问主机机器。 本地二进制通过 Flash 和其他浏览器插件使用的标准 Netscape 插件应用程序编程接口 (NPAPI) 与扩展核心进行交互。
边界
要获得用户的完全权限,攻击者必须说服扩展将恶意输入从内容脚本传递到扩展的核心,再从扩展的核心传递到本地二进制。
扩展的每个组件之间由 强保护边界 隔开。每个组件在 单独的操作系统进程 中运行。内容脚本和扩展核心在 沙箱进程 中运行,这些进程对大多数操作系统服务不可用。
此外,内容脚本通过 在单独的 JavaScript 堆中运行 与其关联的网页分开。内容脚本和网页可以 访问相同的底层 DOM,但两者 从不交换 JavaScript 指针,防止 JavaScript 功能的泄露。
manifest.json
manifest.json
Chrome 扩展只是一个带有 .crx 文件扩展名 的 ZIP 文件夹。扩展的核心是位于文件夹根部的 manifest.json
文件,该文件指定布局、权限和其他配置选项。
示例:
content_scripts
content_scripts
内容脚本在用户导航到匹配页面时加载,在我们的例子中,任何匹配**https://example.com/*
表达式且不匹配*://*/*/business*
正则表达式的页面。它们像页面自己的脚本**一样执行,并且对页面的文档对象模型 (DOM)具有任意访问权限。
为了包含或排除更多的 URL,您还可以使用 include_globs
和 exclude_globs
。
这是一个示例内容脚本,当使用 存储 API 从扩展的存储中检索 message
值时,将向页面添加一个解释按钮。
当点击此按钮时,通过利用runtime.sendMessage() API,内容脚本向扩展页面发送消息。这是由于内容脚本在直接访问API方面的限制,storage
是少数例外之一。对于超出这些例外的功能,消息被发送到扩展页面,内容脚本可以与之通信。
根据浏览器的不同,内容脚本的能力可能会略有不同。对于基于Chromium的浏览器,能力列表可在Chrome Developers documentation中找到,而对于Firefox,MDN是主要来源。 值得注意的是,内容脚本能够与后台脚本进行通信,使其能够执行操作并传递响应。
要在Chrome中查看和调试内容脚本,可以通过选项 > 更多工具 > 开发者工具访问Chrome开发者工具菜单,或按Ctrl + Shift + I。
当开发者工具显示后,点击源选项卡,然后点击内容脚本选项卡。这允许观察来自各种扩展的运行内容脚本,并设置断点以跟踪执行流程。
注入的内容脚本
请注意,内容脚本不是强制性的,也可以通过**tabs.executeScript
** 动态 注入脚本并在网页中以编程方式注入。这实际上提供了更细粒度的控制。
对于内容脚本的程序化注入,扩展需要对要注入脚本的页面具有主机权限。这些权限可以通过在扩展的清单中请求它们或通过activeTab临时获取。
示例 activeTab 基础扩展
点击时注入一个JS文件:
在点击时注入一个函数:
示例与脚本权限
为了包含或排除更多的 URL,您还可以使用 include_globs
和 exclude_globs
。
内容脚本 run_at
run_at
run_at
字段控制 JavaScript 文件何时注入到网页中。首选和默认值是 "document_idle"
。
可能的值有:
document_idle
:尽可能地document_start
:在任何css
文件之后,但在构建任何其他 DOM 或运行任何其他脚本之前。document_end
:在 DOM 完成后立即,但在子资源(如图像和框架)加载之前。
通过 manifest.json
manifest.json
通过 service-worker.js
background
background
由内容脚本发送的消息由背景页面接收,背景页面在协调扩展的组件中发挥着核心作用。值得注意的是,背景页面在扩展的整个生命周期中持续存在,默默运行而无需直接用户交互。它拥有自己的文档对象模型(DOM),能够实现复杂的交互和状态管理。
关键点:
背景页面角色: 作为扩展的神经中枢,确保扩展各部分之间的通信和协调。
持久性: 它是一个始终存在的实体,对用户不可见,但对扩展的功能至关重要。
自动生成: 如果未明确定义,浏览器将自动创建一个背景页面。这个自动生成的页面将包含扩展清单中指定的所有背景脚本,确保扩展的后台任务无缝运行。
浏览器在自动生成背景页面(当未明确声明时)所提供的便利,确保所有必要的背景脚本都被集成并正常运行,从而简化了扩展的设置过程。
示例背景脚本:
它使用 runtime.onMessage API 来监听消息。当接收到 "explain"
消息时,它使用 tabs API 在新标签页中打开一个页面。
要调试后台脚本,您可以转到 扩展详细信息并检查服务工作者, 这将打开带有后台脚本的开发者工具:
选项页面和其他
浏览器扩展可以包含各种类型的页面:
操作页面 在点击扩展图标时显示在 下拉菜单中。
扩展将 在新标签页中加载的页面。
选项页面:此页面在点击时显示在扩展顶部。在之前的清单中,我能够通过
chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca
访问此页面,或点击:
请注意,这些页面不像后台页面那样持久,因为它们根据需要动态加载内容。尽管如此,它们与后台页面共享某些功能:
与内容脚本的通信: 类似于后台页面,这些页面可以接收来自内容脚本的消息,促进扩展内的交互。
访问扩展特定的 API: 这些页面享有对扩展特定 API 的全面访问,受扩展定义的权限限制。
permissions
& host_permissions
permissions
& host_permissions
permissions
和 host_permissions
是 manifest.json
中的条目,指示 浏览器扩展具有哪些权限(存储、位置等)以及 在哪些网页上。
由于浏览器扩展可能具有如此 特权,恶意扩展或被攻击的扩展可能允许攻击者 以不同方式窃取敏感信息并监视用户。
检查这些设置如何工作以及它们如何被滥用:
BrowExt - permissions & host_permissionscontent_security_policy
content_security_policy
内容安全策略 也可以在 manifest.json
中声明。如果定义了内容安全策略,它可能是 脆弱的。
浏览器扩展页面的默认设置相当严格:
有关CSP和潜在绕过的更多信息,请查看:
Content Security Policy (CSP) Bypassweb_accessible_resources
web_accessible_resources
为了让网页访问浏览器扩展的页面,例如一个.html
页面,该页面需要在manifest.json
的**web_accessible_resources
**字段中提到。
例如:
这些页面可以通过以下URL访问:
在公共扩展中,extension-id 是可访问的:
不过,如果使用 manifest.json
参数 use_dynamic_url
,则该 id 可能是动态的。
请注意,即使此处提到某个页面,它也可能由于 内容安全策略 而 受到 ClickJacking 保护。因此,在确认 ClickJacking 攻击是否可能之前,您还需要检查它(frame-ancestors 部分)。
允许访问这些页面使这些页面 可能容易受到 ClickJacking 攻击:
BrowExt - ClickJacking仅允许这些页面由扩展加载,而不是由随机 URL 加载,可以防止 ClickJacking 攻击。
请注意,web_accessible_resources
中的页面和扩展的其他页面也能够 联系后台脚本。因此,如果这些页面中的一个容易受到 XSS 攻击,它可能会打开更大的漏洞。
此外,请注意,您只能在 iframe 中打开 web_accessible_resources
中指示的页面,但从新标签页可以访问扩展中的任何页面,只需知道扩展 ID。因此,如果发现 XSS 利用相同参数,即使页面未在 web_accessible_resources
中配置,也可能被利用。
externally_connectable
externally_connectable
根据 文档,"externally_connectable"
清单属性声明 哪些扩展和网页可以通过 runtime.connect 和 runtime.sendMessage 连接到您的扩展。
如果在扩展的清单中 未声明
externally_connectable
键或声明为"ids": ["*"]
,所有扩展都可以连接,但没有网页可以连接。如果指定了 特定 ID,如
"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
,只有这些应用程序可以连接。如果指定了 匹配项,这些网页应用程序将能够连接:
如果指定为空:
"externally_connectable": {}
,则没有应用程序或网页能够连接。
这里指示的扩展和URL越少,攻击面就越小。
如果在**externally_connectable
中指示了易受XSS或接管攻击的网页**,攻击者将能够直接向后台脚本发送消息,完全绕过内容脚本及其CSP。
因此,这是一个非常强大的绕过。
此外,如果客户端安装了一个恶意扩展,即使它不被允许与易受攻击的扩展通信,它也可能在允许的网页中注入XSS数据,或滥用**WebRequest
或DeclarativeNetRequest
** API来操纵目标域上的请求,改变页面对JavaScript文件的请求。(请注意,目标页面上的CSP可能会阻止这些攻击)。这个想法来自这篇文章。
通信总结
扩展 <--> WebApp
在内容脚本和网页之间,通常使用后续消息进行通信。因此,在网页应用程序中,您通常会找到对函数**window.postMessage
的调用,而在内容脚本中则有像window.addEventListener
这样的监听器。然而,请注意,扩展也可以通过发送Post Message与网页应用程序通信**(因此网页应该预期此情况),或者仅使网页加载一个新脚本。
在扩展内部
通常使用函数**chrome.runtime.sendMessage
在扩展内部发送消息(通常由background
脚本处理),为了接收和处理它,声明一个监听器调用chrome.runtime.onMessage.addListener
**。
也可以使用**chrome.runtime.connect()
来建立持久连接,而不是发送单个消息,可以使用它来发送和接收****消息**,如下例所示:
Last updated