Browser Extension Pentesting Methodology

Reading time: 39 minutes

tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

基本信息

浏览器扩展是用 JavaScript 编写的,并在后台由浏览器加载。它具有自己的 DOM,但可以与其他网站的 DOM 进行交互。这意味着它可能会危害其他网站的机密性、完整性和可用性(CIA)。

主要组件

扩展布局在可视化时效果最佳,由三个组件组成。让我们深入了解每个组件。

http://webblaze.cs.berkeley.edu/papers/Extensions.pdf

内容脚本

每个内容脚本可以直接访问 单个网页 的 DOM,因此暴露于 潜在恶意输入。然而,内容脚本除了能够向扩展核心发送消息外,没有其他权限。

扩展核心

扩展核心包含大部分扩展权限/访问,但扩展核心只能通过 XMLHttpRequest 和内容脚本与网页内容进行交互。此外,扩展核心无法直接访问主机机器。

本地二进制

扩展允许一个本地二进制文件,可以 以用户的全部权限访问主机机器。 本地二进制通过标准的 Netscape 插件应用程序编程接口 (NPAPI) 与扩展核心进行交互,该接口被 Flash 和其他浏览器插件使用。

边界

caution

为了获得用户的全部权限,攻击者必须说服扩展将恶意输入从内容脚本传递到扩展核心,并从扩展核心传递到本地二进制。

扩展的每个组件之间由 强保护边界 隔开。每个组件在 单独的操作系统进程 中运行。内容脚本和扩展核心在 沙箱进程 中运行,这些进程对大多数操作系统服务不可用。

此外,内容脚本通过 在单独的 JavaScript 堆中运行 与其关联的网页分离。内容脚本和网页可以 访问相同的底层 DOM,但两者 从不交换 JavaScript 指针,防止 JavaScript 功能的泄露。

manifest.json

Chrome 扩展只是一个带有 .crx 文件扩展名 的 ZIP 文件夹。扩展的核心是位于文件夹根部的 manifest.json 文件,该文件指定布局、权限和其他配置选项。

示例:

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

内容脚本在用户导航到匹配页面加载,在我们的例子中,任何匹配**https://example.com/*表达式且不匹配*://*/*/business*正则表达式的页面。它们像页面自己的脚本一样**执行,并且可以任意访问页面的文档对象模型 (DOM)

json
"content_scripts": [
{
"js": [
"script.js"
],
"matches": [
"https://example.com/*",
"https://www.example.com/*"
],
"exclude_matches": ["*://*/*business*"],
}
],

为了包含或排除更多的 URL,还可以使用 include_globsexclude_globs

这是一个示例内容脚本,当使用 the storage API 从扩展的存储中检索 message 值时,将向页面添加一个解释按钮。

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)
})

当点击此按钮时,通过利用runtime.sendMessage() API,内容脚本向扩展页面发送消息。这是由于内容脚本在直接访问API方面的限制,storage是少数例外之一。对于超出这些例外的功能,消息被发送到扩展页面,内容脚本可以与之通信。

warning

根据浏览器的不同,内容脚本的能力可能会略有不同。对于基于Chromium的浏览器,能力列表可在Chrome Developers documentation中找到,而对于Firefox,MDN是主要来源。
还值得注意的是,内容脚本能够与后台脚本进行通信,使其能够执行操作并传递响应。

要在Chrome中查看和调试内容脚本,可以通过选项 > 更多工具 > 开发者工具访问Chrome开发者工具菜单,或按Ctrl + Shift + I。

当开发者工具显示后,点击选项卡,然后点击内容脚本选项卡。这允许观察来自各种扩展的运行内容脚本,并设置断点以跟踪执行流程。

注入的内容脚本

tip

请注意,内容脚本不是强制性的,因为也可以动态 注入脚本,并通过**tabs.executeScript在网页中程序化地注入它们。这实际上提供了更细粒度的控制**。

要程序化地注入内容脚本,扩展需要对要注入脚本的页面具有主机权限。这些权限可以通过在扩展的清单中请求它们或通过activeTab临时获得。

示例基于activeTab的扩展

manifest.json
{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
  • 点击时注入 JS 文件:
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"],
})
})
  • 在点击时注入一个函数:
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,
})
})

示例:带有脚本权限

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" })

为了包含或排除更多的 URL,还可以使用 include_globsexclude_globs

内容脚本 run_at

run_at 字段控制 JavaScript 文件何时注入到网页中。首选和默认值是 "document_idle"

可能的值有:

  • document_idle:尽可能地
  • document_start:在任何 css 文件之后,但在构建任何其他 DOM 或运行任何其他脚本之前。
  • document_end:在 DOM 完成后立即,但在子资源(如图像和框架)加载之前。

通过 manifest.json

json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.example.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}

通过 service-worker.js

javascript
chrome.scripting.registerContentScripts([
{
id: "test",
matches: ["https://*.example.com/*"],
runAt: "document_idle",
js: ["contentScript.js"],
},
])

background

由内容脚本发送的消息由背景页面接收,该页面在协调扩展的组件中发挥着核心作用。值得注意的是,背景页面在扩展的整个生命周期中持续存在,默默运行而无需直接用户交互。它拥有自己的文档对象模型(DOM),能够实现复杂的交互和状态管理。

关键点

  • 背景页面角色: 作为扩展的神经中枢,确保扩展各部分之间的通信和协调。
  • 持久性: 它是一个始终存在的实体,对用户不可见,但对扩展的功能至关重要。
  • 自动生成: 如果未明确定义,浏览器将自动创建一个背景页面。这个自动生成的页面将包含扩展清单中指定的所有背景脚本,确保扩展的后台任务无缝运行。

tip

浏览器在自动生成背景页面(当未明确声明时)所提供的便利,确保所有必要的背景脚本都被集成并正常运行,从而简化了扩展的设置过程。

示例背景脚本:

js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request == "explain") {
chrome.tabs.create({ url: "https://example.net/explanation" })
}
})

它使用 runtime.onMessage API 来监听消息。当接收到 "explain" 消息时,它使用 tabs API 在新标签页中打开一个页面。

要调试后台脚本,您可以进入 扩展详细信息并检查服务工作者, 这将打开带有后台脚本的开发者工具:

选项页面和其他

浏览器扩展可以包含各种类型的页面:

  • 操作页面 在点击扩展图标时显示在 下拉菜单中
  • 扩展将 在新标签页中加载的页面
  • 选项页面:此页面在点击时显示在扩展顶部。在之前的清单中,我能够通过 chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca 访问此页面,或点击:

请注意,这些页面不像后台页面那样持久,因为它们根据需要动态加载内容。尽管如此,它们与后台页面共享某些功能:

  • 与内容脚本的通信: 类似于后台页面,这些页面可以接收来自内容脚本的消息,促进扩展内的交互。
  • 访问扩展特定的 API: 这些页面享有对扩展特定 API 的全面访问,受扩展定义的权限限制。

permissions & host_permissions

permissionshost_permissionsmanifest.json 中的条目,指示 浏览器扩展具有哪些权限(存储、位置等)以及 在哪些网页上

由于浏览器扩展可能具有 特权,恶意扩展或被攻陷的扩展可能允许攻击者 以不同方式窃取敏感信息并监视用户

检查这些设置如何工作以及它们可能如何被滥用:

BrowExt - permissions & host_permissions

content_security_policy

内容安全策略 也可以在 manifest.json 中声明。如果定义了内容安全策略,它可能是 脆弱的

浏览器扩展页面的默认设置相当严格:

bash
script-src 'self'; object-src 'self';

有关CSP和潜在绕过的更多信息,请查看:

Content Security Policy (CSP) Bypass

web_accessible_resources

为了让网页访问浏览器扩展的页面,例如一个.html页面,该页面需要在manifest.json的**web_accessible_resources**字段中提到。
例如:

javascript
{
...
"web_accessible_resources": [
{
"resources": [ "images/*.png" ],
"matches": [ "https://example.com/*" ]
},
{
"resources": [ "fonts/*.woff" ],
"matches": [ "https://example.com/*" ]
}
],
...
}

这些页面可以通过以下 URL 访问:

chrome-extension://<extension-id>/message.html

在公共扩展中,extension-id 是可访问的

不过,如果使用了 manifest.json 参数 use_dynamic_url,则该 id 可能是动态的

tip

请注意,即使这里提到的页面可能会由于 内容安全策略受到 ClickJacking 保护。因此,在确认 ClickJacking 攻击是否可能之前,您还需要检查它(frame-ancestors 部分)。

允许访问这些页面使这些页面 可能容易受到 ClickJacking 攻击

BrowExt - ClickJacking

tip

仅允许这些页面由扩展加载,而不是由随机 URL 加载,可以防止 ClickJacking 攻击。

caution

请注意,web_accessible_resources 中的页面和扩展的其他页面也能够 联系后台脚本。因此,如果这些页面中的一个容易受到 XSS 攻击,可能会导致更大的漏洞。

此外,请注意,您只能在 iframes 中打开 web_accessible_resources 中指示的页面,但从新标签页可以访问扩展中的任何页面,只需知道扩展 ID。因此,如果发现 XSS 利用相同的参数,即使页面未在 web_accessible_resources 中配置,也可能被利用。

externally_connectable

根据 docs"externally_connectable" 清单属性声明 哪些扩展和网页可以通过 runtime.connectruntime.sendMessage 连接到您的扩展。

  • 如果在扩展的清单中 未声明 externally_connectable 键,或者声明为 "ids": ["*"]所有扩展都可以连接,但没有网页可以连接
  • 如果 指定了特定的 ID,如 "ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]只有这些应用程序 可以连接。
  • 如果 指定了匹配项,这些网页应用将能够连接:
json
"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
  • 如果指定为空:"externally_connectable": {},则没有应用程序或网页能够连接。

这里指示的扩展和URL越少攻击面就越小

caution

如果网页易受XSS或接管攻击,并在**externally_connectable中指示,攻击者将能够直接向后台脚本发送消息**,完全绕过内容脚本及其CSP。

因此,这是一个非常强大的绕过

此外,如果客户端安装了恶意扩展,即使它不被允许与易受攻击的扩展通信,它也可能在允许的网页中注入XSS数据,或滥用**WebRequestDeclarativeNetRequest** API来操纵目标域上的请求,改变页面对JavaScript文件的请求。(请注意,目标页面上的CSP可能会阻止这些攻击)。这个想法来自这篇文章

通信摘要

扩展 <--> WebApp

在内容脚本和网页之间,通常使用后续消息进行通信。因此,在Web应用程序中,您通常会发现对函数**window.postMessage的调用,而在内容脚本中则有像window.addEventListener这样的监听器。然而,请注意,扩展也可以通过发送Post Message与Web应用程序通信**(因此网页应该预期此情况),或者仅使网页加载一个新脚本。

在扩展内部

通常使用函数**chrome.runtime.sendMessage在扩展内部发送消息(通常由background脚本处理),为了接收和处理它,声明一个监听器调用chrome.runtime.onMessage.addListener**。

也可以使用**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
})

也可以通过调用 chrome.tabs.sendMessage 从后台脚本向位于特定标签页的内容脚本发送消息,您需要指明要发送消息的 标签页 ID

从允许的 externally_connectable 到扩展

externally_connectable 配置中允许的 Web 应用程序和外部浏览器扩展 可以使用以下方式发送请求:

javascript
chrome.runtime.sendMessage(extensionId, ...

在需要提及扩展 ID的地方。

本地消息传递

后台脚本可以与系统内的二进制文件进行通信,如果这种通信没有得到妥善保护,可能会容易受到诸如 RCE 等关键漏洞的影响稍后会详细介绍

javascript
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)

Web ↔︎ Content Script Communication

内容脚本操作的环境与主页面存在的环境是分开的,确保了隔离。尽管存在这种隔离,双方都能够与页面的文档对象模型 (DOM) 进行交互,这是一个共享资源。为了使主页面能够与内容脚本进行通信,或通过内容脚本间接与扩展进行通信,必须利用双方都可以访问的DOM作为通信通道。

Post Messages

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
)
example.js
document.getElementById("theButton").addEventListener(
"click",
() => {
window.postMessage(
{ type: "FROM_PAGE", text: "Hello from the webpage!" },
"*"
)
},
false
)

安全的 Post Message 通信应检查接收到消息的真实性,可以通过以下方式进行检查:

  • event.isTrusted:仅当事件由用户操作触发时为 True
  • 内容脚本可能仅在用户执行某些操作时才会期待消息
  • origin domain:可能仅允许白名单中的域名期待消息。
  • 如果使用正则表达式,请非常小心
  • Sourcereceived_message.source !== window 可用于检查消息是否来自 同一窗口,内容脚本正在监听。

即使执行了上述检查,仍可能存在漏洞,因此请检查以下页面 潜在的 Post Message 绕过

PostMessage Vulnerabilities

Iframe

另一种可能的通信方式可能是通过 Iframe URLs,您可以在以下位置找到示例:

BrowExt - XSS Example

DOM

这并不是“确切的”通信方式,但 网页和内容脚本将可以访问网页 DOM。因此,如果 内容脚本 从中读取某些信息,信任网页 DOM,网页可能会 修改这些数据(因为网页不应被信任,或者因为网页易受 XSS 攻击)并 危害内容脚本

您还可以在以下位置找到 基于 DOM 的 XSS 以危害浏览器扩展 的示例:

BrowExt - XSS Example

内容脚本 ↔︎ 后台脚本通信

内容脚本可以使用 runtime.sendMessage() tabs.sendMessage() 发送 一次性 JSON 可序列化 消息。

要处理 响应,请使用返回的 Promise。尽管为了向后兼容,您仍然可以将 回调 作为最后一个参数传递。

内容脚本 发送请求的方式如下:

javascript
;(async () => {
const response = await chrome.runtime.sendMessage({ greeting: "hello" })
// do something with response here, not outside the function
console.log(response)
})()

扩展(通常是后台脚本)发送请求。向选定标签页中的内容脚本发送消息的示例:

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)
})()

接收端,您需要设置一个runtime.onMessage 事件监听器来处理消息。这在内容脚本或扩展页面中看起来是一样的。

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" })
})

在突出显示的示例中,sendResponse() 是以同步方式执行的。要修改 onMessage 事件处理程序以实现 sendResponse() 的异步执行,必须加入 return true;

一个重要的考虑是,在多个页面设置为接收 onMessage 事件的情况下,第一个执行 sendResponse() 的页面将是唯一能够有效传递响应的页面。对同一事件的任何后续响应将不被考虑。

在创建新扩展时,应该优先使用 promises 而不是回调。关于回调的使用,只有在同步上下文中直接执行 sendResponse() 函数,或者事件处理程序通过返回 true 表示异步操作时,sendResponse() 函数才被视为有效。如果没有任何处理程序返回 true,或者 sendResponse() 函数从内存中移除(被垃圾回收),则与 sendMessage() 函数关联的回调将默认被触发。

Native Messaging

浏览器扩展还允许通过 stdin 与系统中的 二进制文件 进行通信。应用程序必须安装一个 json 来指示这一点,格式如下:

json
{
"name": "com.my_company.my_application",
"description": "My Application",
"path": "C:\\Program Files\\My Application\\chrome_native_messaging_host.exe",
"type": "stdio",
"allowed_origins": ["chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/"]
}

name 是传递给 runtime.connectNative()runtime.sendNativeMessage() 的字符串,用于从浏览器扩展的后台脚本与应用程序进行通信。path 是二进制文件的路径,只有 1 种有效的 type,即 stdio(使用 stdin 和 stdout),allowed_origins 指示可以访问它的扩展(不能使用通配符)。

Chrome/Chromium 会在某些 Windows 注册表和 macOS 和 Linux 的某些路径中搜索此 json(更多信息请参见 docs)。

tip

浏览器扩展还需要声明 nativeMessaing 权限,以便能够使用此通信。

这就是一些后台脚本代码向本地应用程序发送消息的样子:

javascript
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)

这篇博客文章中,提出了一种利用本机消息的脆弱模式:

  1. 浏览器扩展对内容脚本有一个通配符模式。
  2. 内容脚本使用sendMessagepostMessage消息传递给后台脚本。
  3. 后台脚本使用sendNativeMessage将消息传递给本机应用程序。
  4. 本机应用程序以危险的方式处理消息,导致代码执行。

其中解释了如何从任何页面通过浏览器扩展实现RCE的示例。

内存/代码/剪贴板中的敏感信息

如果浏览器扩展在内存中存储敏感信息,则可能会被转储(特别是在Windows机器上)并搜索这些信息。

因此,浏览器扩展的内存不应被视为安全,并且敏感信息如凭据或助记短语不应存储

当然,不要在代码中放置敏感信息,因为它将是公开的

要从浏览器转储内存,可以转储进程内存,或者进入浏览器扩展的设置,点击**Inspect pop-up** -> 在**Memory部分 -> Take a snapshot,然后使用CTRL+F**在快照中搜索敏感信息。

此外,像助记密钥或密码这样的高度敏感信息不应允许复制到剪贴板(或至少在几秒钟内将其从剪贴板中移除),因为监控剪贴板的进程将能够获取它们。

在浏览器中加载扩展

  1. 下载浏览器扩展并解压
  2. 转到**chrome://extensions/启用**开发者模式
  3. 点击**加载已解压的扩展**按钮

Firefox中,转到**about:debugging#/runtime/this-firefox并点击加载临时附加组件**按钮。

从商店获取源代码

Chrome扩展的源代码可以通过多种方法获得。以下是每个选项的详细说明和指示。

通过命令行将扩展下载为ZIP

Chrome扩展的源代码可以通过命令行下载为ZIP文件。这涉及使用curl从特定URL获取ZIP文件,然后将ZIP文件的内容提取到一个目录中。以下是步骤:

  1. "extension_id"替换为扩展的实际ID。
  2. 执行以下命令:
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"

使用 CRX Viewer 网站

https://robwu.nl/crxviewer/

使用 CRX Viewer 扩展

另一种方便的方法是使用 Chrome 扩展源查看器,这是一个开源项目。可以从 Chrome Web Store 安装。查看器的源代码可在其 GitHub repository 中找到。

查看本地安装的扩展的源代码

本地安装的 Chrome 扩展也可以被检查。方法如下:

  1. 通过访问 chrome://version/ 并找到“Profile Path”字段来访问您的 Chrome 本地配置文件目录。
  2. 在配置文件目录中导航到 Extensions/ 子文件夹。
  3. 该文件夹包含所有已安装的扩展,通常其源代码以可读格式存放。

要识别扩展,您可以将它们的 ID 映射到名称:

  • about:extensions 页面上启用开发者模式,以查看每个扩展的 ID。
  • 在每个扩展的文件夹中,manifest.json 文件包含一个可读的 name 字段,帮助您识别扩展。

使用文件归档程序或解压缩工具

前往 Chrome Web Store 下载扩展。文件将具有 .crx 扩展名。将文件扩展名从 .crx 更改为 .zip。使用任何文件归档程序(如 WinRAR、7-Zip 等)提取 ZIP 文件的内容。

在 Chrome 中使用开发者模式

打开 Chrome 并转到 chrome://extensions/。在右上角启用“开发者模式”。点击“加载已解压的扩展...”。导航到您的扩展目录。这不会下载源代码,但对于查看和修改已下载或开发的扩展的代码非常有用。

Chrome 扩展清单数据集

为了尝试发现易受攻击的浏览器扩展,您可以使用 https://github.com/palant/chrome-extension-manifests-dataset 并检查它们的清单文件以寻找潜在的脆弱迹象。例如,检查用户超过 25000 的扩展,content_scripts 和权限 nativeMessaing

bash
# Query example from https://spaceraccoon.dev/universal-code-execution-browser-extensions/
node query.js -f "metadata.user_count > 250000" "manifest.content_scripts?.length > 0 && manifest.permissions?.includes('nativeMessaging')"

安全审计检查表

尽管浏览器扩展具有有限的攻击面,但其中一些可能包含漏洞潜在的加固改进。以下是最常见的:

  • 尽可能限制请求的**permissions**
  • 尽可能限制****host_permissions
  • 使用的**content_security_policy**
  • 尽可能限制****externally_connectable,如果不需要且可能,请不要默认留空,指定**{}**
  • 如果这里提到的URL易受XSS或接管攻击,攻击者将能够直接向后台脚本发送消息。非常强大的绕过方式。
  • 尽可能限制****web_accessible_resources,甚至如果可能的话留空。
  • 如果**web_accessible_resources**不为空,请检查ClickJacking
  • 如果有任何通信发生在扩展网页之间,检查XSS 漏洞
  • 如果使用了Post Messages,请检查Post Message漏洞
  • 如果内容脚本访问DOM细节,请检查它们是否在被网页修改引入XSS
  • 如果此通信也涉及内容脚本 -> 后台脚本通信,请特别强调。
  • 如果后台脚本通过本地消息传递进行通信,请检查通信是否安全且经过清理。
  • 敏感信息不应存储在浏览器扩展代码中。
  • 敏感信息不应存储在浏览器扩展内存中。
  • 敏感信息不应存储文件系统中未受保护

浏览器扩展风险

  • 应用程序https://crxaminer.tech/分析一些数据,例如浏览器扩展请求的权限,以提供使用浏览器扩展的风险级别。

工具

Tarnish

  • 从提供的Chrome网上应用店链接中提取任何Chrome扩展。
  • manifest.json 查看器:简单地显示扩展的manifest的JSON美化版本。
  • 指纹分析:检测web_accessible_resources并自动生成Chrome扩展指纹JavaScript。
  • 潜在Clickjacking分析:检测设置了web_accessible_resources指令的扩展HTML页面。这些页面可能易受Clickjacking攻击,具体取决于页面的目的。
  • 权限警告查看器:显示用户尝试安装扩展时将显示的所有Chrome权限提示警告的列表。
  • 危险函数:显示可能被攻击者利用的危险函数的位置(例如,innerHTML、chrome.tabs.executeScript等函数)。
  • 入口点:显示扩展接收用户/外部输入的位置。这对于理解扩展的表面区域和寻找潜在的恶意数据发送点非常有用。
  • 危险函数和入口点扫描器生成的警报包含以下内容:
    • 相关代码片段和导致警报的行。
    • 问题描述。
    • “查看文件”按钮以查看包含代码的完整源文件。
    • 警报文件的路径。
    • 警报文件的完整Chrome扩展URI。
    • 文件类型,例如后台页面脚本、内容脚本、浏览器操作等。
    • 如果易受攻击的行在JavaScript文件中,包含该行的所有页面的路径以及这些页面的类型和web_accessible_resource状态。
  • 内容安全策略(CSP)分析器和绕过检查器:这将指出扩展CSP中的弱点,并将揭示由于白名单CDN等可能绕过CSP的任何潜在方式。
  • 已知漏洞库:使用Retire.js检查是否使用了已知的易受攻击的JavaScript库。
  • 下载扩展和格式化版本。
  • 下载原始扩展。
  • 下载美化版本的扩展(自动美化的HTML和JavaScript)。
  • 扫描结果的自动缓存,第一次运行扩展扫描将花费相当长的时间。然而,第二次运行时,假设扩展没有更新,将几乎是瞬时的,因为结果已被缓存。
  • 可链接的报告URL,轻松将其他人链接到由Tarnish生成的扩展报告。

Neto

项目Neto是一个Python 3包,旨在分析和揭示Firefox和Chrome等知名浏览器的浏览器插件和扩展的隐藏功能。它自动解压打包文件,以从扩展中的相关资源(如manifest.json、本地化文件夹或JavaScript和HTML源文件)中提取这些功能。

参考文献

tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks