4、逻辑漏洞之权限提升:Shareable接口滥用、JCRE权限模型缺陷、Firewall绕过技术
权限提升,说白了就是“以小博大”。
在JavaCard的世界里,Applet之间本来应该是老死不相往来的。JCRE(Java Card Runtime Environment)设计了一套防火墙机制,每个Applet都活在自己的小隔间里。但现实是,有些Applet需要互相通信,比如钱包Applet要调用安全模块Applet做签名验证。于是就有了Shareable接口——一个官方开的“后门”。
嗯,有后门就有人想钻空子。今天我们就聊聊这个。
4.1 Shareable接口:官方开的门,也是攻击者的路
Shareable接口的设计初衷是好的。它允许一个Applet(客户端)通过JCRE获取另一个Applet(服务端)的引用,然后调用服务端暴露的方法。流程大概是这样的:
- 客户端Applet调用
JCSystem.getAppletShareableInterface(),传入服务端AID。 - JCRE检查服务端Applet是否实现了Shareable接口。
- 如果实现了,JCRE调用服务端的
getShareableInterfaceObject()方法,返回一个Shareable对象。 - 客户端通过这个对象调用服务端的方法。
听起来很安全对吧?但问题出在哪儿呢?
问题在于:服务端Applet无法确认调用者是谁。
我在项目中遇到过这样一个案例:一个电子钱包Applet实现了Shareable接口,提供了 debit(short amount) 方法。设计者以为只有“可信”的Applet才能调用它。结果呢?一个恶意Applet直接通过 getAppletShareableInterface() 拿到了引用,然后疯狂扣款。
核心漏洞点:服务端Applet的 getShareableInterfaceObject() 方法通常不做调用者身份校验。它默认返回一个Shareable对象,谁拿到谁用。
代码示例:一个存在漏洞的服务端Applet
public class VulnerableWallet extends Applet implements Shareable {
private short balance;
public Shareable getShareableInterfaceObject(AID clientAID, byte parameter) {
// 漏洞:没有校验clientAID,直接返回this
return this;
}
public void debit(short amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
}
}
}
你想想看,如果这里加一行 if (!clientAID.equals(TRUSTED_AID)) return null;,攻击者就没辙了。但很多开发者嫌麻烦,或者觉得“没人会这么干”,结果就留下了隐患。
4.2 JCRE权限模型缺陷:谁给了你权力?
JavaCard的权限模型,说白了就是“谁在什么上下文中能干什么事”。每个Applet有自己的上下文(Context),JCRE也有自己的上下文。防火墙规则是这样的:
- 同一个上下文内的对象可以互相访问。
- 不同上下文的对象不能直接访问,必须通过Shareable接口。
- JCRE上下文拥有最高权限,可以访问所有对象。
听起来挺合理的。但缺陷在哪儿?
缺陷在于:JCRE上下文和Applet上下文的边界有时候是模糊的。
举个例子:JCRE内部有一些系统服务,比如APDU分发、事务管理。这些服务运行在JCRE上下文中。如果某个系统服务存在漏洞,攻击者就可以利用它来“借用”JCRE的权限。
我记得有一次分析一个JavaCard实现,发现它的 APDU.setIncomingAndReceive() 方法在内部会临时切换到JCRE上下文。如果这个方法在处理过程中抛出了异常,上下文可能没有正确恢复。嗯,这就给了攻击者可乘之机——在异常处理中插入恶意代码,让后续操作都运行在JCRE上下文中。
注意:JCRE权限模型依赖的是“上下文隔离”,而不是“用户身份认证”。一旦上下文被污染,整个安全模型就崩塌了。
4.3 Firewall绕过技术:翻墙的艺术
防火墙(Firewall)是JavaCard安全的核心。它拦截所有跨上下文的对象访问。但道高一尺,魔高一丈。攻击者总结出了几种经典的绕过方式:
4.3.1 全局数组(Global Array)滥用
JavaCard支持全局数组——在Applet安装时通过 makeTransientByteArray() 或 makeTransientShortArray() 创建的数组,可以被多个Applet共享访问。这本来是为了性能优化,但攻击者可以利用它来传递数据,绕过防火墙的检查。
我曾经见过一个案例:两个Applet通过全局数组交换APDU命令的响应数据。服务端Applet把敏感数据写进全局数组,客户端Applet直接读出来。防火墙?防火墙只检查对象引用,不检查数组内容。所以数据就这么“裸奔”出去了。
4.3.2 事务(Transaction)机制滥用
JavaCard的事务机制允许在事务中修改多个对象,要么全部成功,要么全部回滚。但事务的提交和回滚操作是在JCRE上下文中执行的。攻击者可以利用这一点:
- 在事务中修改一个跨上下文的对象引用。
- 利用事务回滚来“欺骗”防火墙,让防火墙以为对象还在原上下文中。
- 实际上对象已经被替换成了恶意对象。
说白了,就是利用事务的原子性来绕过防火墙的上下文检查。
4.3.3 类型混淆(Type Confusion)
这是最“高级”的一种绕过方式。攻击者通过精心构造的APDU命令,让JCRE错误地解析对象类型。比如把一个 byte[] 数组当成 Shareable 对象来使用。一旦类型混淆成功,攻击者就可以直接操作JCRE内部的数据结构。
我的建议:如果你在开发安全敏感的Applet,一定要在 getShareableInterfaceObject() 中做AID校验。不要偷懒。我曾经因为少写一行校验,在安全审计中被客户怼得哑口无言。
4.4 防御思路:堵住这些漏洞
说了这么多攻击手法,我们聊聊怎么防。我个人总结了几个要点:
| 攻击手法 | 防御措施 |
|---|---|
| Shareable接口滥用 | 在 getShareableInterfaceObject() 中校验调用者AID,只返回给可信Applet |
| JCRE权限模型缺陷 | 避免在异常处理中执行敏感操作;确保上下文切换是原子性的 |
| 全局数组滥用 | 尽量减少全局数组的使用;如果必须用,对数组内容进行加密 |
| 事务机制滥用 | 在事务中不要修改跨上下文的对象引用;对事务内的操作做完整性校验 |
| 类型混淆 | 严格校验APDU命令的格式;使用类型安全的API |
你可能会问:“这些防御措施够吗?”
说实话,不够。JavaCard的安全是一个系统工程,单靠几个补丁是堵不住的。但至少,把这些常见的坑填上,攻击者的路就窄了一大半。
一句话总结:权限提升的本质是“信任的滥用”。不要信任任何跨上下文的调用者,除非你明确验证了它的身份。
4.5 知识体系图:权限提升攻击全景
下面这张图展示了本章涉及的核心知识点和它们之间的关系。我习惯用这种图来梳理思路,一目了然。
这张图把Shareable接口滥用、JCRE权限模型缺陷、Firewall绕过技术三个攻击面串在了一起。你看,它们最终都指向同一个目标——权限提升。而防御的核心思路,就是“校验”和“隔离”。
好了,这一章的内容就到这里。记住,JavaCard的安全没有银弹,但把这些基础漏洞堵住,你的Applet就能挡住90%的攻击者。
公众号:蓝海资料掘金营,微信deep3321