Repository navigation
Replies: 1 comment
|
翻译:制作一个恶意网站PoC,里面放 |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
当前默认
dsh web只监听127.0.0.1,直接从外部网页跨站 POST/api也会被现有 Origin / Fetch-Metadata / CORS 边界挡住;但 localhost Web 页面本身目前可以被任意站点放进 iframe。这会留下一个不同于直接 CSRF 的 UI-redress / clickjacking 入口:恶意网站不能读取 iframe DOM,但可以把默认
http://127.0.0.1:3080的真实 Harness UI 透明覆盖、裁剪或移动到诱饵控件下面,让用户的点击和键盘输入实际落在 Harness 页面里。Harness 当前又把多项高权限决策做成普通的页面内交互,例如:
Workspace Write切换到Full access;因此,用户在运行默认 Web UI 时访问恶意网页并被诱导完成这些交互,可能在自己看不到真实 Harness 页面语义的情况下:
danger-full-access;Allow once;这不是“恶意网页可以跨源读取 localhost”的问题,SOP 仍然有效;问题是 localhost 页面没有禁止被不可信顶层页面 frame,而真正的敏感操作由被 frame 的 localhost 页面自己以同源身份发送。
1. 默认地址是可预测的
127.0.0.1:3080当前 Web bundle 默认配置:
CLI 文档也明确写明默认服务地址:
因此恶意页面在默认配置下不需要先枚举随机端口。
2. 当前 index / static response 没有 anti-framing policy
packages/host/frontend-static/src/index.ts的 index 响应当前只写:当前 WebServer 也没有统一追加以下任一限制:
因此没有由 Harness 发出的浏览器级 frame 限制。
3. 真实 Chromium:跨站页面可以直接 iframe loopback 页面
我使用真实 Chromium 做了一个无害网络验证:
loopback target 实际收到:
{ "method": "GET", "host": "127.0.0.1:<loopback-port>", "secFetchSite": "cross-site", "secFetchMode": "navigate", "secFetchDest": "iframe" }也就是说,当前 Chromium 并不会因为目标是
127.0.0.1就阻止这种 iframe navigation;在没有frame-ancestors/X-Frame-Options的情况下,loopback 页面正常加载进了远程页面的 iframe。这个测试只加载一个写有普通文本的无害 localhost 页面,没有访问任何 Harness 数据。
4. 被 frame 的 localhost 页面自己调用
/api时仍然是 same-origin caller进一步在该 loopback iframe 页面内部执行一个无害的相对请求:
真实 Chromium 发到 loopback target 的请求是:
{ "method": "POST", "host": "127.0.0.1:<loopback-port>", "origin": "http://127.0.0.1:<loopback-port>", "secFetchSite": "same-origin", "secFetchMode": "cors", "contentType": "application/json" }因此虽然 顶层页面 是
evil.test,真正运行 Harness JS 的 iframe Document 仍然以自己的 localhost origin 调用/api。这也意味着当前
isTrustedApiRequest()的 Origin / Fetch-Metadata 检查不会因为顶层页面是恶意站点就拒绝这些请求:敏感 RPC 是被合法 localhost 页面自己发出的。5. Negative control:直接跨站 JSON POST 仍然会被浏览器预检挡住
为了区分 clickjacking 和普通 CSRF,我还测试了:
Chromium 对 loopback target 只发送了 CORS OPTIONS preflight,没有发送实际 POST;当 target 不允许 CORS 时,
fetch()以TypeError: Failed to fetch失败。所以这里不是通过 redirect 绕过项目现有 CSRF fence,而是另一条边界:
6. 项目自己的真实 Web e2e 已固定 Full access 是页面内可点击的敏感操作
当前仓库:
这个测试明确说明它启动 shipped Web composition,使用真实 Chromium,并走:
测试操作正是:
最后断言当前 Access mode 已经变成:
测试还专门确认这个确认框是当前页面
document.body中的普通 Web modal:也就是说它不是浏览器原生确认框、系统窗口或其他不能被父页面 clickjack 的可信 UI。
当前
PermissionSelect最后调用的是:而该 preset 会使当前 Session 进入:
7. approval 面板同样是页面内操作,而且项目 e2e 证明 Allow once 会让升级后的命令真实运行
另一个真实 Chromium 场景:
它创建真实 pending approval,然后在 Web 页面里点击:
随后断言:
并确认原本需要 escalation 的命令已经真实执行、文件被写入。
因此 clickjacking 的安全影响不局限于“误点一个无害按钮”;当前页面里存在实际承担权限提升 / approval 决策的 UI。
8. 为什么 SOP 不能解决 UI redress
父页面仍然不能:
这些都继续受 Same-Origin Policy 保护。
但 clickjacking 不要求读取 iframe。
攻击页面控制自己的 DOM 和 iframe 的:
因此可以在不同诱饵步骤中移动/裁剪同一个跨源 iframe,使用户的真实 pointer gesture 落到 Harness 的 Access、Full access、checkbox、Enable、approval 等固定 UI 位置上。
同理,在需要任务内容时,可以诱导用户把攻击页面展示的文本输入到获得焦点的隐藏 Composer;真正的键盘事件发生在 localhost Document 中,Composer 的普通 Enter 提交流程随后由 localhost UI 自己完成。
这里明确存在用户交互前提;本文不主张“访问恶意网页即无交互 RCE”。
9. 修复建议
建议首先在所有 Harness Web HTML 页面增加浏览器级 anti-framing policy,例如:
Content-Security-Policy: frame-ancestors 'none'若产品未来确实需要被特定 origin 嵌入,则应显式列出可信 frame ancestor,而不是保持任意 origin 可嵌入。
为了兼容较旧浏览器,也可以同时发送:
X-Frame-Options: DENY另外,Full access / approval 这类安全决策最好继续保持 Host 侧权限边界;前端风险确认不能在页面允许任意 framing 的情况下被视为不可伪造的“用户意图证明”。
总结
当前默认链条是:
现有 Origin、Fetch-Metadata 和 CORS 防护能够阻止恶意顶层页面直接跨站调用
/api,但它们不能代替frame-ancestors:被 clickjack 的合法 localhost 页面本身就是通过这些检查的可信请求来源。All reactions