Black Hat USA 2026:Bixby信任模型击穿
原创
Max Luo
Max Luo
白帽子罗棋琛
2026年10月12日 08:19
中国香港
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
一次点击如何击穿 Bixby 信任模型
Black Hat USA 2026 议题笔记:One Click to System — Exploiting Bixby's Trust Model for Full Device Compromise
用户在浏览器里点击一次,网页先进入 Samsung Members 的 WebView,再借应用间跳转进入 Samsung Account,随后调用只有少数系统应用持有权限的 Bixby,最终让 Settings 组件以 system 身份启动攻击者指定的 Activity。
这不是一个漏洞完成的越权,而是一条“权限借贷链”。Dimitrios Valsamaras 与 Ken Gannon 的公开课件把 Pwn2Own Ireland 2025 研究拆成两段:浏览器到 Bixby,以及 Bixby 到 Android system。前半段对应 Samsung Members 和 Samsung Account 的三个 CVE;后半段暴露的则是 Bixby Capsule 架构中的信任聚合问题。
图 1:研究对象是 Galaxy S25 上从一次网页点击到系统权限的完整调用链
本文依据课件和 Samsung 官方公告分析架构与修复方法,不提供可直接复现的 Intent URI、XSS 字符串、Bixby Action 参数或最终 RCE 载荷。
1、比赛约束反而让攻击模型更接近现实
研究面向 Pwn2Own Ireland 2025 的 Galaxy S25 Remote 类别。入口只能来自默认浏览器中的远程网页,攻击需满足比赛规定的交互与效果要求。课件最终展示的是一次点击链,而不是需要用户安装 APK、打开 USB 调试或预先授权 Accessibility 的实验室场景。
图 2:入口限定为浏览器内容,结果要求敏感信息泄露或远程代码执行
这种约束决定了研究路线:浏览器本身不一定需要内存破坏,只要能把一个攻击者控制的 URL 送进预装高权限应用,再利用应用之间的委托关系逐级提升调用身份即可。
课件将完整路线概括为三类组件:默认浏览器提供可远程触达的 browsable 入口;Bixby 负责跨应用编排;系统组件提供最终高权限动作。
图 3:第一段取得 Bixby 调用能力,第二段把 Bixby 的编排能力转换为系统组件调用
移动端攻击面盘点因此不能只列 exported=true 的 Activity。还应记录每个组件能以谁的身份打开 WebView、转发 Intent、调用签名权限和触达系统 Provider。
yaml
component_edge:source:external-browserdestination:preinstalled-app-activitytrigger:browsable-deep-linkattacker_controlled_fields:-data_uri-selected_extrasprivilege_transformation:before:untrusted_web_originafter:destination_app_uidsinks:-WebView.loadUrl-Intent.parseUri-startActivityreview_question:destination是否重新建立来源、目标和参数约束
2、第一跳:Deep Link 把网页数据带进预装应用
第一处问题是 Samsung Members 的 CVE-2025-21079。课件分析的版本为 5.5.00.13。Samsung 官方公告将其描述为输入验证不当:5.5.01.3 之前的版本可能让远程攻击者连接任意 URL,并以 Samsung Members 权限启动任意 Activity;触发需要用户交互。
图 4:一个 browsable Deep Link 同时打开攻击者站点,并把后续跳转放到 Samsung Members 身份下执行
课件展示的入口 Activity 根据 scheme、authority 和 path 路由 Deep Link,随后把原始 Intent extras 复制给 Fragment。Fragment 从参数中读取 URL,并在启用 JavaScript 的 WebView 中加载。
图 5:外部 Intent 参数未被收敛为受信模型,直接流向 WebView.loadUrl
安全实现不应在接收端沿用外部 Bundle,而是从允许字段构建新的内部对象:
kotlin
dataclassNewsRoute(val articleId: String) funparseExternalRoute(intent: Intent): NewsRoute? { if (intent.action != Intent.ACTION_VIEW) returnnullval uri = intent.data ?: returnnullif (uri.scheme != \"https\" || uri.host != \"members.example.invalid\") returnnullif (uri.pathSegments.size != 2 || uri.pathSegments[0] != \"news\") returnnullval articleId = uri.pathSegments[1] if (!articleId.matches(Regex(\"[A-Za-z0-9_-]{1,64}\"))) returnnullreturn NewsRoute(articleId) } funopenInternalArticle(context: Context, route: NewsRoute) { val intent = Intent(context, NewsDetailActivity::class.java) .putExtra(\"article_id\", route.articleId) context.startActivity(intent) }
重点不是换一种 URL 正则,而是取消“外部调用者决定内部要加载哪个 URL、携带哪些 extras”的能力。
3、302 重定向为何能越过表面上的 URL 检查
应用可能只在首次加载时检查 URL,却在 shouldOverrideUrlLoading() 中把后续跳转重新解析为 Intent。课件中的 WebViewClient 收到 302 后,将新 URL 交给 Intent.parseUri(),只检查目标包是否存在,随后调用 startActivity()。
图 6:URL 校验与 Intent 启动被拆成两段,重定向后的目标没有重新经过同等级验证
这是 WebView 审计里常见的断点:初始 URL、服务器跳转、客户端 JavaScript 导航、iframe、window.open() 和自定义 scheme 必须共享同一套策略。只检查第一跳相当于把策略委托给远端服务器。
kotlin
privateval allowedHosts = setOf(\"support.example.invalid\") overridefunshouldOverrideUrlLoading( view: WebView, request: WebResourceRequest ): Boolean { val uri = request.url val isAllowedHttps = uri.scheme == \"https\" && uri.host?.lowercase() in allowedHosts && request.isForMainFrame if (isAllowedHttps) returnfalse// 不从远程页面接受 intent:、file:、content: 或私有 scheme。 securityLogger.blockedNavigation(uri.toString(), request.hasGesture()) returntrue }
如果业务确实需要从 WebView 打开原生功能,应把网页动作映射为固定枚举,再显式构造 Intent;不要解析网页提供的完整 Intent 对象。
4、第二跳:XSS 与 Intent 重定向借用了 Samsung Account 身份
第二个应用是 Samsung Account。课件标出的两个问题分别为 CVE-2025-58486 和 CVE-2025-58487。Samsung 官方公告显示,二者均在 15.5.01.1 修复:前者是输入验证不当导致任意脚本执行,后者是授权不当导致以 Samsung Account 权限启动任意 Activity。
这两个问题看似是“本地中危”,放到链上却作用不同:Samsung Members 把远程网页送进 Samsung Account;脚本执行控制内部 WebView 导航;Intent 重定向则把攻击者选择的目标转换成 Samsung Account 发起的调用。
真正需要的不是第二个任意跳转本身,而是 Samsung Account 持有 Bixby 的签名级启动权限。换句话说,攻击链在寻找的不是代码执行,而是一枚具有正确调用者身份的“跳板 UID”。
图 7:Samsung Account 的价值在于它拥有调用 Bixby Capsule 的专用权限
企业移动安全团队可用设备侧采样确认版本与导出面:
bash
adb shell dumpsys package com.samsung.android.voc \\ | sed -n '/versionName=/p;/android.intent.category.BROWSABLE/,+12p' adb shell dumpsys package com.osp.app.signin \\ | sed -n '/versionName=/p;/requested permissions:/,/install permissions:/p' adb shell dumpsys package com.samsung.android.bixby.agent \\ | sed -n '/Permission \\[com.samsung.android.bixby.agent.permission.LAUNCH_BIXBY_VOICE\\]/,+12p'
这些命令适合经过授权的测试设备,不应把完整 dumpsys 输出上传到无控制的第三方平台,因为其中可能包含设备和账户相关信息。
5、浏览器到 Bixby 的九步链,本质是三次身份替换
课件把第一部分画成九步序列:浏览器访问攻击者页面;Samsung Members 加载攻击者 WebView;服务器以 302 让它启动 Samsung Account;Samsung Account 再访问攻击者地址;第二次 302 让它启动 Bixby。
图 8:同一份远程输入依次借用 Samsung Members 与 Samsung Account 的 UID,最终越过 Bixby 权限门槛
这条链可以抽象为权限传递图:
text
Web Origin --browsable link--> Samsung Members UID --WebView redirect--> Samsung Account UID --signature permission--> Bixby Agent UID --capsule dispatch--> Settings / system UID
审计时,每条边都要问四个问题:来源是否可伪造;参数是否可控;接收方是否用自己的权限代办;下游是否知道原始来源。只要中间组件丢失 provenance,下游看到的就始终是“受信系统应用发来的合法请求”。
可以在设计阶段维护机器可读的委托清单:
json
{\"delegation\":\"account-to-bixby\",\"caller_packages\":[\"com.osp.app.signin\"],\"required_permission\":\"LAUNCH_BIXBY_VOICE\",\"accepted_actions\":[\"account_help\",\"account_recovery\"],\"forbidden_capabilities\":[\"raw_intent_forwarding\",\"arbitrary_capsule_target\",\"background_system_activity_launch\"],\"provenance\":{\"original_source_uid_required\":true,\"web_origin_allowed\":false,\"nonce_bound_to_user_gesture\":true}}
6、Bixby Capsule 把“语音意图”转换成跨应用能力
Bixby 不只是语音 UI。它是编排层:解析用户意图,生成结构化数据,找到声明了相应 Action 的 Capsule Provider,再让目标应用执行真实操作。
图 9:应用向 Bixby 暴露 Action,Bixby 负责路由,目标应用负责真正的高权限工作
这种架构天然需要跨 UID。课件指出,所有 Capsule 的入口主要由一项 LAUNCH_BIXBY_VOICE 权限保护,Samsung Account 等少数系统应用持有它。问题是这项权限控制了“能否进入 Bixby”,却没有细分“能调用哪个 Provider、哪个 Action、哪些参数、以前台还是后台执行”。
图 10:粗粒度入口权限把大量下游能力归并为一个信任域
这违背最小权限。更合理的 Capability 设计应把授权绑定到具体动作:
protobuf
message CapsuleGrant { string caller_package = 1; bytes caller_signing_digest = 2; string provider_package = 3; string action_name = 4; repeatedstring allowed_parameter_names = 5; bool allow_background = 6; int64 expires_at_epoch_ms = 7; bytes request_nonce = 8; bool requires_visible_user_confirmation = 9; }
即使某个系统应用出现 Intent 重定向,它也只能调用被授予的少数动作,而不能继承整个 Bixby 生态的能力。
7、Settings Capsule 为什么会成为 system 级通用跳板
课件枚举了 Settings Capsule 的 276 个 Action,覆盖显示、会话、电源、通知、应用控制、网络、无障碍和 SystemUI。攻击者最终关注的不是名字看起来危险的“LaunchApplication”,而是一个用于跳转应用设置页的后台 Action。
图 11:一个 Provider 同时聚合了大量设置、通知、连接与任务控制能力
逆向显示,该 Action 从参数中取出一段包含 #Intent 的字符串,用 Intent.parseUri() 还原为 Intent,再把它封装后交给 BixbyTrampoline。
图 12:字符串在多层路由后重新获得 Intent 语义,来源约束已经丢失
Trampoline Activity 取出嵌套 Intent 并调用 startActivityForResult()。由于执行者属于系统设置组件,目标 Activity 看到的是 system 发起的请求。
图 13:通用 trampoline 把 Capsule 参数转换成了 system 身份的任意 Activity 启动能力
修复原则是禁止通用透传。Settings 应接受结构化的包名或设置页枚举,并在最终 sink 之前再次约束目标:
kotlin
funlaunchApprovedSettingsPage(context: Context, packageName: String) { require(packageName.matches(Regex(\"[a-zA-Z0-9_.]{1,180}\"))) val target = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.fromParts(\"package\", packageName, null) flags = Intent.FLAG_ACTIVITY_NEW_TASK } val resolved = context.packageManager.resolveActivity(target, 0) ?: throw IllegalArgumentException(\"no settings handler\") check(resolved.activityInfo.packageName == \"com.android.settings\") context.startActivity(target) }
不要接受 Intent Parcelable、intent: URI、显式 component、selector、ClipData 或调用者提供的 flags。
8、如何在代码库里批量找出同类委托链
单点 grep startActivity 会产生大量噪声。更有效的办法是从外部 Source 追到特权 Sink,并标记中间是否经过净化。
Source 包括 getIntent()、Deep Link data、WebView navigation、Binder/Provider 参数和外部 Parcelable;Sink 包括 Intent.parseUri()、startActivity*()、sendBroadcast()、bindService() 以及系统服务调用。
下面是一条适合先做粗筛的 Semgrep 规则,重点找“外部字符串解析为 Intent 后直接启动”的模式:
yaml
rules:-id:android-untrusted-intent-uri-forwardinglanguages: [java, kotlin] severity:ERRORmessage:外部字符串被解析为Intent并直接启动,需校验目标与清除危险字段patterns:-pattern-either:-pattern:| $I = Intent.parseUri($S, ...); ... $C.startActivity($I); -pattern:| $I = Intent.parseUri($S, ...) ... $C.startActivityForResult($I, ...) -pattern-not-inside:| $I = Intent.parseUri($S, ...); ... enforceAllowedIntent($I); ...
粗筛之后要人工检查数据流:URL 是否可能经过 30x;是否从一个 App 进入另一个 App;接收者是否持有调用者没有的签名权限;嵌套 Bundle/Parcelable 是否保留了原始 Intent。
Manifest 侧也要建立权限图。下面的 Python 片段读取 apkanalyzer manifest print 导出的 XML,列出可浏览 Activity 和自定义权限使用情况:
python
from pathlib import Path import sys import xml.etree.ElementTree as ET ANDROID = \"{http://schemas.android.com/apk/res/android}\" root = ET.parse(Path(sys.argv[1])).getroot() for activity in root.findall(\"./application/activity\"): name = activity.get(ANDROID + \"name\", \"\") exported = activity.get(ANDROID + \"exported\", \"false\") == \"true\" permission = activity.get(ANDROID + \"permission\", \"\") browsable = any( cat.get(ANDROID + \"name\") == \"android.intent.category.BROWSABLE\"for cat in activity.findall(\"./intent-filter/category\") ) if exported or browsable: print({\"activity\": name, \"browsable\": browsable, \"permission\": permission}) for use in root.findall(\"uses-permission\"): name = use.get(ANDROID + \"name\", \"\") if name andnot name.startswith(\"android.permission.\"): print({\"custom_permission_use\": name})
9、修复不能只补三个 CVE,还要拆掉权限放大器
Samsung 公告给出的修复版本是明确的:Samsung Members 5.5.01.3 及之后修复 CVE-2025-21079;Samsung Account 15.5.01.1 及之后修复 CVE-2025-58486 与 CVE-2025-58487。终端管理应检查应用版本,而不是只看 Android 安全补丁级别,因为这些组件可通过应用更新通道修复。
但版本升级只关掉已知入口。架构整改至少还应包含:
- WebView 的每次导航都执行同源和 scheme 策略;
- 外部 Intent 进入后立即转换为最小内部 DTO,不复制原始 extras;
- 禁止系统应用解析并转发任意
intent:URI; - 把 Bixby 权限拆分到 Provider/Action/参数粒度;
- 高风险后台 Action 强制可见确认和短期 nonce;
- Trampoline 重新检查原始 UID、签名、目标组件和调用场景;
- Settings 等高权限 Provider 不接受通用 Intent 对象;
- 在系统日志中保留原始调用者链,而非只记录最后一跳。
课件最终没有公开从“以 system 启动任意 Activity”到 RCE 的细节,只说明能够在演示中完成。这种克制很合理:架构结论已足够支撑修复,无需公开最后一段可武器化载荷。
图 14:公开材料止步于 system 身份的 Activity 启动能力,最终 RCE 仅作演示
10、移动平台安全团队的审计清单
这条链最容易造成误判的地方,是三个应用漏洞单独看并不都具备最高严重度;一旦进入预装系统应用的权限图,组合影响却可以达到完整设备失陷。
图 15:单一权限折叠了 Capsule 安全模型,问题根源在架构而非某个孤立输入点
建议按以下顺序开展审计:
- 枚举所有 browsable、exported Activity、Service、Receiver 与 Provider。
- 对每个入口追踪 URI、extras、Bundle、Parcelable、ClipData 和 selector 的完整数据流。
- 检查 WebView 初始 URL、302、JavaScript 导航和私有 scheme 是否使用统一策略。
- 列出持有 signature/privileged 权限的预装应用,并追踪它们的全部外部入口。
- 搜索
Intent.parseUri、嵌套 Intent、通用 trampoline 和不受限startActivity*。 - 建立“外部来源 → 中间 UID → 特权服务 → system sink”的跨 APK 调用图。
- 把粗粒度权限拆分为具体 Capability,不让一个入口令牌覆盖数百个动作。
- 对后台执行、通知读取、无障碍、网络开关和应用启动增加用户确认与场景绑定。
- 验证 Samsung Members 与 Samsung Account 已达到官方修复版本,并持续监测回归。
- 在漏洞定级时计算链式影响,不能把每个 CVE 当成互不相关的本地问题。
这项研究说明,移动系统的信任边界不是 APK 文件边界。预装应用、语音助手、账户服务和 Settings 共同组成一个能力网络。只要其中一个节点可以替外部数据“换身份”,另一个节点又把粗粒度权限转换为通用 Intent,单次点击就可能沿着合法接口一路到达系统权限。
资料来源
- Black Hat 官方 Session 页面
- Samsung Mobile Security 2025 应用安全公告
- NVD:CVE-2025-21079
- NVD:CVE-2025-58486
- NVD:CVE-2025-58487
原始会议材料(仓库内)
- 演讲课件 PDF
开源资料与原始议题 PDF
本文对应的 Markdown 原稿、Black Hat 原始议题 PDF 与配图已整理到 GitHub,可按文章编号查找和下载。
https://github.com/cybermaxluo/black-hat-usa-2026-talks
也可以点击文末“阅读原文”进入仓库。欢迎 Star、提交 Issue 或参与勘误。
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论