Browser Extension Pentesting Methodology
Reading time: 38 minutes
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
基本信息
Browser extensions are written in JavaScript and loaded by the browser in the background. It has its DOM but can interact with other sites' DOMs. This means that it may compromise other sites' confidentiality, integrity, and availability (CIA).
主要组件
Extension layouts look best when visualised and consists of three components. Let’s look at each component in depth.
内容脚本
Each content script has direct access to the DOM of a single web page and is thereby exposed to potentially malicious input. However, the content script contains no permissions other than the ability to send messages to the extension core.
扩展核心
The extension core contains most of the extension privileges/access, but the extension core can only interact with web content via XMLHttpRequest and content scripts. Also, the extension core does not have direct access to the host machine.
本地二进制
The extension allows a native binary that can access the host machine with the user’s full privileges. The native binary interacts with the extension core through the standard Netscape Plugin Application Programming Interface (NPAPI) used by Flash and other browser plug-ins.
边界
caution
To obtain the user's full privileges, an attacker must convince the extension to pass malicious input from the content script to the extension's core and from the extension's core to the native binary.
Each component of the extension is separated from each other by strong protective boundaries. Each component runs in a separate operating system process. Content scripts and extension cores run in sandbox processes unavailable to most operating system services.
Moreover, content scripts separate from their associated web pages by running in a separate JavaScript heap. The content script and web page have access to the same underlying DOM, but the two never exchange JavaScript pointers, preventing the leaking of JavaScript functionality.
manifest.json
A Chrome extension is just a ZIP folder with a .crx file extension. The extension's core is the manifest.json
file at the root of the folder, which specifies layout, permissions, and other configuration options.
Example:
{
"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)。
"content_scripts": [
{
"js": [
"script.js"
],
"matches": [
"https://example.com/*",
"https://www.example.com/*"
],
"exclude_matches": ["*://*/*business*"],
}
],
为了包含或排除更多的 URL,还可以使用 include_globs
和 exclude_globs
。
这是一个示例内容脚本,当使用 the storage API 从扩展的存储中检索 message
值时,将向页面添加一个解释按钮。
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的扩展
{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
- 点击时注入 JS 文件:
// 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"],
})
})
- 在点击时注入一个函数:
//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,
})
})
示例:具有脚本权限
// 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_globs
和 exclude_globs
。
内容脚本 run_at
run_at
字段控制 JavaScript 文件何时注入到网页中。首选和默认值是 "document_idle"
。
可能的值有:
document_idle
:尽可能地document_start
:在任何来自css
的文件之后,但在构建任何其他 DOM 或运行任何其他脚本之前。document_end
:在 DOM 完成后立即,但在子资源(如图像和框架)加载之前。
通过 manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.example.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}
通过 service-worker.js
chrome.scripting.registerContentScripts([
{
id: "test",
matches: ["https://*.example.com/*"],
runAt: "document_idle",
js: ["contentScript.js"],
},
])
background
由内容脚本发送的消息由背景页面接收,该页面在协调扩展的组件中发挥着核心作用。值得注意的是,背景页面在扩展的整个生命周期中持续存在,默默运行而无需直接用户交互。它拥有自己的文档对象模型(DOM),能够实现复杂的交互和状态管理。
关键点:
- 背景页面角色: 作为扩展的神经中枢,确保扩展各部分之间的通信和协调。
- 持久性: 它是一个始终存在的实体,对用户不可见,但对扩展的功能至关重要。
- 自动生成: 如果未明确定义,浏览器将自动创建一个背景页面。这个自动生成的页面将包含扩展清单中指定的所有背景脚本,确保扩展的后台任务无缝运行。
tip
浏览器在自动生成背景页面(当未明确声明时)所提供的便利,确保所有必要的背景脚本都被集成并正常运行,从而简化了扩展的设置过程。
示例背景脚本:
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
permissions
和 host_permissions
是 manifest.json
中的条目,指示 浏览器扩展具有哪些权限(存储、位置等)以及 在哪些网页上。
由于浏览器扩展可能具有如此 特权,恶意扩展或被攻击的扩展可能允许攻击者 以不同方式窃取敏感信息并监视用户。
检查这些设置如何工作以及如何被滥用:
BrowExt - permissions & host_permissions
content_security_policy
内容安全策略 也可以在 manifest.json
中声明。如果定义了内容安全策略,它可能是 脆弱的。
浏览器扩展页面的默认设置相当严格:
script-src 'self'; object-src 'self';
有关CSP和潜在绕过的更多信息,请查看:
Content Security Policy (CSP) Bypass
web_accessible_resources
为了让网页访问浏览器扩展的页面,例如一个.html
页面,该页面需要在manifest.json
的**web_accessible_resources
**字段中提到。
例如:
{
...
"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 攻击:
tip
仅允许这些页面由扩展加载,而不是由随机 URL 加载,可以防止 ClickJacking 攻击。
caution
请注意,web_accessible_resources
中的页面和扩展的其他页面也能够 联系后台脚本。因此,如果这些页面中的一个容易受到 XSS 攻击,它可能会打开更大的漏洞。
此外,请注意,您只能在 iframe 中打开 web_accessible_resources
中指示的页面,但从新标签页可以访问扩展中的任何页面,只需知道扩展 ID。因此,如果发现 XSS 利用相同参数,即使页面未在 web_accessible_resources
中配置,也可能被利用。
externally_connectable
根据 docs,"externally_connectable"
清单属性声明 哪些扩展和网页可以通过 runtime.connect 和 runtime.sendMessage 连接到您的扩展。
- 如果在扩展的清单中 未声明
externally_connectable
键或声明为"ids": ["*"]
,所有扩展都可以连接,但没有网页可以连接。 - 如果 指定了特定 ID,如
"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
,只有这些应用程序 可以连接。 - 如果 指定了匹配项,这些网络应用程序将能够连接:
"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
- 如果指定为空:
"externally_connectable": {}
,则没有应用程序或网页能够连接。
这里指示的扩展和网址越少,攻击面就越小。
caution
如果网页易受XSS或接管攻击并在**externally_connectable
中指示,攻击者将能够直接向后台脚本发送消息**,完全绕过内容脚本及其CSP。
因此,这是一个非常强大的绕过。
此外,如果客户端安装了恶意扩展,即使它不被允许与易受攻击的扩展通信,它也可能在允许的网页中注入XSS数据或滥用**WebRequest
或DeclarativeNetRequest
** 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()
示例
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 应用和外部浏览器扩展可以使用以下方式发送请求:
chrome.runtime.sendMessage(extensionId, ...
在需要提及 extension ID 的地方。
Native Messaging
背景脚本可以与系统内的二进制文件进行通信,如果这种通信没有得到妥善保护,可能会 容易受到诸如 RCEs 的关键漏洞。 More on this later。
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
Web ↔︎ Content Script Communication
内容脚本 操作的环境与主机页面存在的环境是 分开的,确保了 隔离。尽管存在这种隔离,双方都能够与页面的 文档对象模型 (DOM) 进行交互,这是一个共享资源。为了使主机页面能够与 内容脚本 进行通信,或通过内容脚本间接与扩展进行通信,必须利用双方都可以访问的 DOM 作为通信通道。
Post Messages
// 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
)
document.getElementById("theButton").addEventListener(
"click",
() => {
window.postMessage(
{ type: "FROM_PAGE", text: "Hello from the webpage!" },
"*"
)
},
false
)
安全的 Post Message 通信应检查接收到消息的真实性,这可以通过以下方式进行检查:
event.isTrusted
:仅当事件是由用户操作触发时,此值为 True- 内容脚本可能仅在用户执行某些操作时才会期待消息
- origin domain:可能仅允许白名单中的域名发送消息。
- 如果使用正则表达式,请非常小心
- Source:
received_message.source !== window
可用于检查消息是否来自 同一窗口,即内容脚本正在监听的窗口。
即使执行了上述检查,仍可能存在漏洞,因此请查看以下页面 潜在的 Post Message 绕过:
Iframe
另一种可能的通信方式可能是通过 Iframe URLs,您可以在以下位置找到示例:
DOM
这并不是“确切的”通信方式,但 网页和内容脚本将可以访问网页 DOM。因此,如果 内容脚本 从中读取某些信息,信任网页 DOM,网页可能会 修改这些数据(因为网页不应被信任,或因为网页易受 XSS 攻击)并 危害内容脚本。
您还可以在以下位置找到 基于 DOM 的 XSS 以危害浏览器扩展 的示例:
内容脚本 ↔︎ 背景脚本通信
内容脚本可以使用 runtime.sendMessage() 或 tabs.sendMessage() 发送 一次性 JSON 可序列化 消息。
要处理 响应,请使用返回的 Promise。尽管为了向后兼容,您仍然可以将 回调 作为最后一个参数传递。
从 内容脚本 发送请求的方式如下:
;(async () => {
const response = await chrome.runtime.sendMessage({ greeting: "hello" })
// do something with response here, not outside the function
console.log(response)
})()
从扩展(通常是后台脚本)发送请求。向选定标签页中的内容脚本发送消息的示例:
// 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 事件监听器来处理消息。这在内容脚本或扩展页面中看起来是一样的。
// 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 来指示这一点,格式如下:
{
"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
权限,以便能够使用此通信。
这就是一些后台脚本代码向本地应用程序发送消息的样子:
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
在这篇博客文章中,提出了一种利用本机消息的脆弱模式:
- 浏览器扩展对内容脚本有一个通配符模式。
- 内容脚本使用
sendMessage
将postMessage
消息传递给后台脚本。 - 后台脚本使用
sendNativeMessage
将消息传递给本机应用程序。 - 本机应用程序以危险的方式处理消息,导致代码执行。
在其中,解释了如何从任何页面利用浏览器扩展进行RCE的示例。
内存/代码/剪贴板中的敏感信息
如果浏览器扩展将敏感信息存储在其内存中,则可能会被转储(特别是在Windows机器上)并搜索这些信息。
因此,浏览器扩展的内存不应被视为安全,并且敏感信息如凭据或助记短语不应存储。
当然,不要在代码中放置敏感信息,因为它将是公开的。
要从浏览器转储内存,您可以转储进程内存,或者转到浏览器扩展的设置,点击**Inspect pop-up
** -> 在**Memory
部分 -> Take a snapshot
,然后使用CTRL+F
**在快照中搜索敏感信息。
此外,像助记密钥或密码这样的高度敏感信息不应允许复制到剪贴板(或者至少在几秒钟内将其从剪贴板中移除),因为这样监控剪贴板的进程将能够获取它们。
在浏览器中加载扩展
- 下载浏览器扩展并解压
- 转到**
chrome://extensions/
并启用**开发者模式
- 点击**
加载已解压的扩展
**按钮
在Firefox中,您转到**about:debugging#/runtime/this-firefox
并点击加载临时附加组件
**按钮。
从商店获取源代码
Chrome扩展的源代码可以通过多种方法获得。以下是每个选项的详细说明和指令。
通过命令行下载扩展为ZIP
Chrome扩展的源代码可以通过命令行下载为ZIP文件。这涉及使用curl
从特定URL获取ZIP文件,然后将ZIP文件的内容提取到一个目录中。以下是步骤:
- 将
"extension_id"
替换为扩展的实际ID。 - 执行以下命令:
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 网站
使用 CRX Viewer 扩展
另一种方便的方法是使用 Chrome 扩展源查看器,这是一个开源项目。可以从 Chrome Web Store 安装。查看器的源代码可在其 GitHub repository 中找到。
查看本地安装扩展的源代码
本地安装的 Chrome 扩展也可以被检查。方法如下:
- 通过访问
chrome://version/
并找到“Profile Path”字段来访问您的 Chrome 本地配置文件目录。 - 在配置文件目录中导航到
Extensions/
子文件夹。 - 该文件夹包含所有已安装的扩展,通常以可读格式存放其源代码。
要识别扩展,您可以将它们的 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
:
# 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源文件)中提取这些功能。
参考文献
- 感谢 @naivenom 对本方法的帮助
- 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
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。