背景内容
在分析iOS平台上与沙盒逃逸有关的攻击面时,我们在iCloud钥匙串同步功能的OTR实现中发现了一个严重的安全漏洞。
iCloud钥匙串同步功能允许用户以一种安全的方式跨设备共享自己的密码。该协议与其他跨设备密码共享机制(例如谷歌Chrome的密码同步功能)相比,安全性有显著的提升,因为它所采用的端到端加密使用了设备绑定型(device-specific)密钥,而这种加密方式能够显著提升iCloud钥匙串同步机制的安全性,即使用户的密码被盗或者iCloud后台服务器受到攻击,用户的安全也能够得到有效的保障。
但是,我们此次所发现的这个漏洞破坏了这种端到端加密的安全性,并有可能允许潜在的攻击者窃取用户的钥匙串信息。在这篇文章中,我们将给大家详细描述这个漏洞。
iCloud钥匙串同步技术概览
iCloud钥匙串最早与iOS7被引入,该功能允许用户跨设备共享自己的密码和信用卡数据。除此之外,iCloud钥匙串同步功能还可以让用户轻松地在设备间安全同步隐私信息,而且iCloud钥匙串恢复机制还可以在用户遗失了设备后,帮助他们恢复iCloud钥匙串数据。
为了提升安全性,iCloud钥匙串同步功能在交换钥匙串对象时采用了端到端加密,这样就可以保证只有参与钥匙串交换的双方设备才可以解密这些信息。加密过程依赖于一个同步识别密钥(每台设备只有一个),共享信息的明文数据以及加密密钥都不会暴露给iCloud。这也就意味着,即使你可以无限制地访问iCloud后台服务器或iCloud通信数据,你也无法解密出钥匙串数据。
数据的传输是通过iCloud键值存储(与每一个iCloud账户单独绑定)实现的,苹果应用和第三方应用都可以使用键值存储来为注册了iCLoud服务的用户同步数据。应用程序只能访问当前用户标识所允许的键值存储数据,而iCloud系统服务控制着应用与键值存储服务器之间的通信连接。与iCloud键值存储的直接通信要求用户提供密码凭证或iCLoud认证令牌。
注:钥匙串同步存储数据所使用的识别符为com.apple.security.cloudkeychainproxy3。
交换信息
iCloud钥匙串同步功能使用了一个自定义的开源OTR实现,这种OTR(Off-The-Record)信息协议具有不可否认性和前向安全性等特征。
为了接收或发送OTR数据,一台设备必须是“signed-syncing-circle”中的一部分,并存储在iCloud KVS之中。除了与每一台设备相关的元数据之外,其中还包含有每台设备所对应的公共同步身份密钥。
系统采用了CTR模式的AES-128对数据进行加密,并且使用了ECDH认证密钥交换算法。认证过程需要用到每个节点的身份密钥,并且使用了ECDSA签名算法(SHA-256)。
由于两台设备间的加密是成对的,因此一台设备在向另一台设备(必须是“signed-syncing-circle”中的一部分)传输新的OTR信息或交换钥匙串数据时,必须要发起OTR会话协商。iCloud KVS中的信息属性必须指定OTR信息的发送方和接收方,这样才能保证正确的信息接收设备可以正常处理消息的内容。
这里需要注意的是,默认情况下并非每一个钥匙串对象都会被同步,此时只有iCloud钥匙串同步功能的kSecAttrSynchronizable属性中所设置的那些钥匙串对象才会进行同步,其中包括系统WiFI密码和Safari凭证(例如信用卡卡号)。
加入“signed-syncing-circle”(签名同步环)
iOS安全指南对其的描述如下:
“signed-syncing-circle”可以用来构建一个由多台受信任设备所组成的一个组(Group)。其中,每一台设备都要生成其自己的同步身份密钥对(椭圆曲线密钥),私钥存储在钥匙串的‘kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate’属性之中,所以只有当设备解锁后才可以访问。注:“signed-syncing-circle”的签名需要每台设备的同步身份私钥和用户的iCloud密钥。
为了让一台新设备加入到“signed-syncing-circle”之中,circle中现存的设备成员必须接受应用发出的ticket并将请求成员的公钥添加到circle之中。这个ticket必须通过用户的iCloud密钥进行签名,而请求过程同样需要用户输入自己的iCloud密码。这就意味着,用户需要在请求设备以及circle中已存在的设备上进行交互操作,并通过用户当前的iCloud密码来验证这些设备的真实性和有效性。
钥匙串同步漏洞
我们所发现的这个漏洞存在于OTR的签名认证程序中。由于系统没有对错误进行适当的处理,攻击者将有可能绕过这种签名验证机制。
源代码:Security-57740.31.2/OSX/sec/Security/SecOTRSessionAKE.c
static OSStatus SecVerifySignatureAndMac(SecOTRSessionRefsession,
bool usePrimes,
const uint8_t **signatureAndMacBytes,
size_t *signatureAndMacSize)
{
OSStatus result = errSecDecode;
…
result = ReadLong(signatureAndMacBytes, signatureAndMacSize,&xbSize); [1]
require_noerr(result, exit);
require_action(xbSize > 4, exit, result = errSecDecode);
require_action(xbSize exit,result = errSecDecode);
uint8_t signatureMac[CCSHA256_OUTPUT_SIZE];
cchmac(ccsha256_di(), sizeof(m2), m2, xbSize + 4,encSigDataBlobStart, signatureMac);
require(xbSize + kSHA256HMAC160Bytes exit); [2]
…
exit:
bzero(m1, sizeof(m1));
bzero(m2, sizeof(m2));
bzero(c, sizeof(c));
return result;
}
我们可以看到代码中标注了【1】的那一行,当程序成功从进来的握手信息中提取出了4个字节的数据时,返回代码被设置为了‘errSecSuccess’。然后看【2】的那一行,如果传入的信息长度太短以至于无法保存HMAC数据,那么函数将会退出运行。然而,返回代码会错误地认为签名认证已经成功了。这将允许攻击者伪造一个能够成功协商密钥的OTR信息,然后绕过现有的签名验证机制。
影响
考虑到OTR在实现加密时采用的是临时密钥,所以这个漏洞也就意味着攻击者在接收秘密信息时不用再去进行OTR会话协商了。虽然攻击者无法利用这个漏洞加入到“signedsyncing circle”之中,但他们可以冒充circle内的任何一个节点,并且在钥匙串对象同步的过程中拦截钥匙串数据。
篇尾语
我个人认为,我们应该重新审视一下密码的安全性问题了。在过去的几年里,很多在事件应急响应团队或政府执法部门工作的技术人员已经见过了很多由密码重用所带来的密码安全问题,但攻击者现在的技术已经不仅仅是通过钓鱼网站来窃取密码这么简单了,因此保障密码的安全才会变得如此的重要。但是我们应该注意一点,由于未来可能出现的安全风险是我们无法预料到的,而根据目前的情况来看,密码也许已经不是我们保护敏感数据时的首选方案了。
更新:就在不久之前我们被告知,我们已经得到了在2017年BlackHat黑客大会上讨论“iCloud钥匙串窃取”这一主题的机会,希望感兴趣的同学能够及时关注。
|