ONE CLASSTO RULE THEM ALL 0-DAY DESERIALIZATION VULNERABILITIESIN ANDROID

Or Peles, Roee Hay IBM Security {orpeles,roeeh}@il..com

Abstract I. Introduction We present previously unknown high severity vulnera- bilities in Android. Android is the most popular mobile The first is in the Android Platform and with 78% of the worldwide smartphone sales to end Play Services. The Platform instance affects Android users in Q1 2015 [1]. 4.3-5.1, M (Preview 1) or 55% of Android devices Android apps are executed in a sandboxed envi- at the time of writing1. This vulnerability allows for ronment to protect both the system and the hosted arbitrary code execution in the context of many apps applications from malware [2]. The Android sandbox and services and results in elevation of privileges. In this relies on the kernel’s isolation facilities. While paper we also demonstrate a Proof-of-Concept exploit sandboxing is a central security feature, it comes at the against the Google Nexus 5 device, that achieves code expense of interoperability. In many common situations, execution inside the highly privileged system_server apps require the ability to interact. For example, the process, and then either replaces an existing arbitrary browser app should be capable of launching the Google application on the device with our own malware app Play app if the user points toward the Google Play or changes the device’s SELinux policy. For some other website. To recover interoperability, a key aspect of devices, we are also able to gain kernel code execution the Android architecture is Inter-App Communication by loading an arbitrary kernel module. We had respon- (IAC) , which enables modular design and reuse of sibly disclosed the vulnerability to Android Security functionality across apps and app components. The Team which tagged it as CVE-2015-3825 (internally Android IAC model is implemented as a message- as ANDROID-21437603/21583894) and patched An- passing system, where messages are encapsulated by Intent Intent droid 4.4 / 5.x / M and Google Play Services. objects. Through s, an app (or app component) can utilize functionality exposed by another For the sake of completeness we also made app (or app component), e.g. by passing a message a large-scale experiment over 32,701 of Android to the browser to render content or to a navigation applications, finding similar previously unknown app to display a location and provide directions to it. deserialization vulnerabilities, identified by For implementing IAC, including sending and receiving CVE-2015-2000/1/2/3/4/20, in 6 SDKs affecting Intents, Android uses a mechanism called Binder. As multiple apps. We responsibly (privately) contacted described thoroughly by [3],in the center of the Binder the SDKs’ vendors or code maintainers so they would mechanism is the Binder Linux driver, that transfers provide patches. Further analysis showed that many of messages between processes. Each such Inter-Process the SDKs were vulnerable due to weak code generated Communication (IPC) message is a ’transaction’. When by SWIG, an interoperability tool that connects C/C++ an application talks to a service, it does so using with a variety of languages, when fed with some bad proxy and stub methods that get translated to Binder configuration given by the developer. We therefore transactions under the hood, albeit appear like a local worked closely with the SWIG team to make sure function call to the developer. it would generate more robust code — patches are Due to its significance, much past research has been available. invested, from multiple angles, in IAC. The research varies from Testing [4, 5, 6], Verification [7], Prevention 1https://developer.android.com/about/dashboards [8, 9] and Offensive Security [10, 11, 12, 13, 14, 15, 16].

1 II. Serialization serious because oftentimes the inserted object is auto- matically deserialized, and later freed by the Garbage Intents may contain arbitrary data of arbitrary types Collector (GC), which calls the finalize method of via a provided Bundle2 object. For instance, an appli- the deserialized object. The finalize method may cation may provide another app with a String which switch into native code that may access non-transient can then be accessed via Bundle.getString(String pointers provided by the deserialized object, that the key) or through Intent.getStringExtra(String adversary controls. In current Android versions, any key). Moreover, a completely arbitrary object can be object put inside a Bundle can be initialized by a sent and later be accessed by the recipient via the victim app (or service) if the latter only uses (touches) Bundle.getObject(String key) method. In order a Bundle arriving from the attacker’s IAC. Using a to be able to send objects via IAC they must be Bundle is a very common behavior among apps.. serialized (or use the Parcelable interface explained Internally, when the Bundle is touched (e.g. by call- briefly below). The recipient needs to deserialize them ing getStringExtra() or similar), it unparcels it- upon instantiation. self - initializing (and instantiating) all of its val- General-purpose serialization of objects can be ues (even unused ones). These values may include achieved by implementing the Serializable interface Serializable and Parcelable objects, that will get in the object’s class. Object members which shall not deserialized (or unparcelled). Together with his dis- be serialized (for example, pointers used in native code) closure, Horn released a Proof-of-Concept (PoC) code can easily be declared by the developer by providing the crashing Android’s system_server which runs under transient modifier before each of such a member. By the system context. Horn’s PoC worked by provid- default, during deserialization, ObjectInputStream’s ing system_server with an evil, non-Serializable defaultReadObject method is called, receives the android.os.BinderProxy object, by inserting it class name of the object being deserialized from the into the setApplicationRestrictions’s method stream, and instantiates it, populating its fields that are Bundle parameter. While Horn’s PoC only crashed non-transient and non-static with the stream’s data. In system_server, it clearly demonstrated the problem, addition, developers can implement special methods in which indeed proved to be exploitable as a few months their classes, that will override the default serialization later Yaron Lavi and Nadav Markus released a write-up methods. These methods, covered by the Java Doc- [18] describing a fully working exploit. 3 umentation include readObject, readResolve and Despite the fact that CVE-2014-7911 has been writeReplace. patched, there can still be Serializable classes avail- In addition, Android provides another serialization able to applications that are dangerous to load if they facility through the Parcleable interface. Objects of can be controlled by the adversary. One prominent implementing classes can be placed inside a Parcel4 scenario happens if the developer had forgotten to add object which is designed as a high-performance IPC the transient modifier to a sensitive member (such as a transport. pointer). This game is asymmetric as one vulnerable class III. The General Android Problem that is available to the default Android class loader is enough for all apps (or one highly-privileged ser- In 2014, Jann Horn has disclosed a significant vulner- vice) to be compromised. Objects of such classes may cause damage in several ways, including automatic code ability [17] in Android. The vulnerability, identified as finalize CVE-2014-7911, was a serious flaw in the way An- execution of their method with deserialized ObjectInputStream params or by other methods (such as writeReplace droid derserialized objects via . or writeObject In Android versions earlier than 5.0, the deserializing ) that can be called implicitly . code did not verify that the received object is indeed Hypothetically, even in an ideal world where there serializable by making sure that its class implements aren’t such vulnerable classes available in the Android the Serializable interface. This allowed for inserting framework, such classes could be found in third-party arbitrary objects (available to the target’s class loader) frameworks (SDKs) or in specific apps - making a more into a target app or service. Things became more targeted attack. It is important to note that Bundle isn’t the only vec- 2http://developer.android.com/reference/android/- tor. Each code path that leads to Parcel’s readValue, os/Bundle. readParcelable or readSerializable will also in- 3http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html/ 4http://developer.android.com/reference/android/- stantiate whatever object is on the stream (that is os/Parcel.html loadable).

2 IV. Finding a Vulnerable Class VirtualMachine vm = f o r (ReferenceType ref : vm.allClasses()) We wanted to find a class available to any Android { app that both implements the Serializable interface, i f ( ! ( r e f i n s t a n c e o f ClassType)) { holds a native pointer as a member without declaring it continue ; to be transient, and also provides a finalize method } which accesses that pointer. The finalize method does ClassType cref = (ClassType)ref; not have to be implemented by the class itself, but rather boolean isSerializable = f a l s e ; f o r (InterfaceType iref : cref.allInterfaces()) by an ancestor class, accessing the pointer via a call to { an overidden method. i f ("java.io.Serializable".equals(iref .name())) { We automatically created a list of candidate classes isSerializable = true ; using the following mechanics. We first wrote a small break ; Activity } app with a single , and then ran it, waiting for } a debugger, using the following am command, under an i f (!isSerializable) continue ;

emulator running Android 4.2 through 5.1.1. boolean hasFinalize = f a l s e ; am start -D -n f o r (Method m : cref.methodsByName("finalize")) { We remotely attached our custom debugger to the String declaringClass = m.declaringType().name(); application through JDWP. On top of JDWP we ran i f (!"java.lang.Object".equals(declaringClass) && !"java.lang.Enum".equals(declaringClass)) a Java code that utilizes JDI as shown by Figure { IV.1. We ignored the Object’s and Enum’s finalize hasFinalize = true ; break ; implementations because they were simply empty func- } tions, creating a lot of uninteresting candidates. We } i f (!hasFinalize) continue ; printedout only classes which have at least one attacker- controllable field. A field is attacker-controllable if it is boolean h a s F i e l d = f a l s e ; f o r (Field f : cref.fields()) (1) non-transient (2) non-static (3) all of the classes { in the class hierarchy from the candidate class to the i f (f.isStatic()) continue ; i f (f.isTransient()) continue ; class that actually defines the field (can be the candidate class itself) are Serializable. (4) of a Serializable // isSerializable is our own implementation i f (isSerializable(f, cref)) type (or primitive) (5) no readObject / readResolve { implementation that prevents us from controlling it. h a s F i e l d = true ; th break ; Note that this code does not check for the 5 property } of our attacker-controllable definition, so it only yields } i f (!hasField) continue ; an upper bound, which we can verify manually. This code yields a couple of classes: System.out. println(cref.name()); } 1) java.util.regex.Pattern5 2) com.android.org.conscrypt- OpenSSLX509Certificate6 in Android 4.4 Figure IV.1. JDI code that finds candidate vulnerable classes and org.apache.harmony.xnet.provider- .jsse.OpenSSLX509Certificate7 in Android 4.3. We then analyzed the candidate classes by hand. The first class has an interesting finalize method which The more pedantic reader would notice that our accesses a native pointer, address, however, marked experiment was limited to the preloaded classes only. as transient, thus cannot be controlled by the adversary. In order to overcome that, we created a list of loadable We had this false positive because this class had an- classes by parsing the output of the oatdump tool other non-transient field which was not interesting. We over boot.art. This resulted in 13321 loadable classes therefore were left with the second candidate only. under our Android 5.1 build. One could then try to add them to /system/etc/preloaded-classes, and 5http://androidxref.com/5.1.0_r1/xref/libcore- /luni/src/main/java/java/util/regex/Pattern.java re-run our experiment. We decided to take a different 6http://androidxref.com/5.1.0_r1/xref/external- approach and write a small Android app, that loads the /conscrypt/src/main/java/org/conscrypt- classes using Java Reflection, and examines whether /OpenSSLX509Certificate.java they are candidate to be vulnerable, by the same criteria 7http://androidxref.com/4.3_r2.1/xref/libcore- /luni/src/main/java/org/apache/harmony/xnet/provider- defined above. We did not find any additional candi- /jsse/OpenSSLX509Certificate.java dates.

3 V. Attacking OpenSSLX509Certificate the feasibility of the attack. It does not include any exploit code. The exploit’s fundamental goal is to OpenSSLX509Certificate is Serializable since achieve code execution in an arbitrary app or service. it is a descendant of Certificate which is One significant candidate is a process with elevated Serializable. It also has a finalize method which privileges - Android’s system_server, which hosts calls a native function with its mContext mem- many core services such as Android’s Package Man- ber, which is a pointer of type long, as an argu- ager, Activity Manager and Power Manager services. ment. Since OpenSSLX509Certificate doesn’t imple- It runs under UID 1000 - Android’s system user. We ment any special deserialization methods (readObject attack system_server by inserting our objects into the or readResolve), and since mContext is attacker- setApplicationRestrictions method’s Bundle pa- controllable (as per our definition in Section IV), rameter, see [17]. After being able to run code in the the adversary can control it. Eventually, as ex- system_server process, we demonstrated three different plained in Section III, OpenSSLX509Certificate's goals the exploit can achieve: The first is replacing an finalize method will be invoked automatically application already on the target device with our own by the GC. The finalize method then invokes malware app. The second goal we achieved was com- NativeCrypto.X509_free with mContext as a pa- pletely bypassing SElinux, by changing and reloading rameter. Its execution ends with a decrement of *(int the SElinux policy. Third, on devices running kernels *)(mContext + 0x10). (In native code.) that were compiled with loadable modules support (not Constrained "Write What Where" in user-mode recent Google Nexus devices), we were also able to memory can be achieved by decrementing a positive leverage the exploit to gain arbitrary kernel code execu- WORD’s value one by one (also by accessing its tion. This was done by making our shellcode, running high/low HALFWORDs with unaligned addressing). inside system_server, load our own kernel module – Freeing of an arbitrary object could also be achieved, see Section VII-C. but there’s no need as we managed to create a fully functional exploit without that. A. Constrained “Write What Where” Note that instead of relying on the GC to call finalize, we could have abused the As we mentioned in Section V, we are able to OpenSSLX509Certificate’s writeReplace method, decrement the value of a positive integer by one. This that is inherited from Certificate. As explained is because our pointed object is believed to contain a in Section III, when implemented in a class, this reference counter of type signed integer at offset 0x10. method overrides the default method for serializing Thus every time NativeCrypto.X509_free is called, an object. The writeReplace method in our it gets decremented and the function returns (without case calls getEncoded, a method implemented by freeing anything). When the value reaches zero, the OpenSSLX509Certificate that leads to the invocation flow towards free continues, and may cause a crash of a native function (NativeCrypto.i2d_X509) with by dereferencing an unmapped pointer. our attacker-controlled parameter (mContext).Unlike Because the decrement doesn’t crash the remote app finalize, this method doesn’t depend on the (on a positive integer), we can re-run it multiple times, GC, but is triggered immediately when our decrementing the target WORD until it reaches the value OpenSSLX509Certificate object is serialized of 1. (at the other end). One way of abusing it would be In order to do it efficiently, we include many (0x500) sending an Intent with OpenSSLX509Certificate OpenSSLX509Certificate objects inside each trans- as an Intent Extra to an application that uses (touches) action’s Bundle, making the WORD’s value decrement the Intent’s Extras Bundle, and later serializes the faster. (Each Binder transaction is limited to 1MB in Bundle which will trigger a writeReplace call on size otherwise a TransactionTooLargeException is our deserialized object. thrown8.) In order to further improve the efficiency, to allow us to both target WORDs that initially are negative, and set WORDs with a negative value without VI. Proof-of-Concept Exploit crashing, we can also decrement from the middle of our target WORD (2 bytes aligned), lowering the value of In order to demonstrate the impact of such a vulnerabil- the upper half of our WORD to reach a desired value, ity, we developed and successfully tested a PoC exploit, or until our WORD’s MSB (sign-bit) is zeroed, so that running under Google Nexus 5 Hammerhead equipped we will later be able to operate on the target WORD with Android 5.1.1. The exploit can easily be ported to run on other devices running vulnerable Android 8http://developer.android.com/reference/android/os/- versions. This paper describes a PoC that demonstrates TransactionTooLargeException.html

4 directly and also decrement the lower HALFWORD. object, with bad contents in its byte array mem- In case the desired value is negative, after setting the ber inside the bundle. The byte array won’t be suc- lower HALFWORD, we can get back to the address+2 cessfully decoded as PKCS8, but will help us in WORD and set the higher HALFWORD to a negative later stage, see Section VI-H. OpenSSLECPrivateKey value. The ability to do this of course depends, again, implements the readObject method, that over- on the value of the WORD we decrement and of the rides the default deserialization method, and thus next adjacent HALFWORD. is called during object deserialization. This function Note that for the constrained “Write What Where” we calls the NativeCrypto.d2i_PKCS8_PRIV_KEY_INFO have to know the original value of the target WORD in function with the byte array we supplied. Our the remote process as well. This is possible thanks to supplied byte array makes the function call the the Zygote creation model, see Section VI-D. throwExceptionIfNecessary function (after failing to parse our byte array to a valid value), that eventually CRYPTO_THREADID_current B. Controlling the Program Counter (PC) leads to an invocation of , that directly calls our callback function . Now that we have the ability to control a value from A minor drawback we encountered of using the another process’s address space, we can use it to subvert id_callback function pointer is that its adjacent a target program’s logic, by changing authentication or HALFWORD is zeroed. This means that by decre- privilege states for example. In addition, we can try menting this function pointer, we are practically limited to achieve arbitrary code execution. Android, a Linux- to positive addresses [1,0x7 f f f f f f f ] . We practically based OS, has memory page permissions. Since we bypass this limit in Section VI-G. didn’t find any memory page that is both writable and executable, we thought we could modify a func- D. Bypassing Address Space Layout Randomization (.got tion’s address from the Global Offset Table (ASLR) section). Unfortunately for us, the shared libraries in memory were all compiled with the Relocation Read ASLR is a security mechanism whose purpose is to Only (RELRO) flag. This compile-time flag instructs the make it harder for attackers to build a reliable exploit. loader to resolve all symbols’ addresses immediately ASLR randomly arranges key data areas of a process, during the binary loading, and then set their memory including the base of the executable and the positions pages to read-only, making .got overwrite impossible. of the stack, heap and libraries. ASLR could have easily prevented us from gaining code execution by overriding a specific function pointer, because we wouldn’t have C. Writable Function Pointers known where the function pointer lies in memory, and Another approach for gaining code execution by not less important, what its initial value is, which is an controlling memory is by changing a writable function address of a function in the libjavacrypto module. pointer. In some cases, libraries let other apps hand Android’s Zygote Process Creation Model: In An- pointers of callback functions, which are invoked in droid, every application, and most of the service pro- specific places in the library’s code. For example, li- cesses are created by forking from a single process braries may allow an application to hand a callback named Zygote. The design was intended to improve for logging purposes, that will be invoked every time the responsiveness of applications at launch-time, but it the library needs to write to a log. These callbacks adversely affects the effectiveness of ASLR. The Zygote sometimes appear as global function pointers in the process is created among the first processes at boot time, library’s (writable) data section, making them a perfect and contains a full Dalvik or ART Virtual Machine target for achieving arbitrary code execution. instance with frequently used classes preloaded. Lee In our case, we found that libcrypto (the OpenSSL et al. [19] concluded that “all running apps inherit the library) offers this functionality which is used by lib- commonly used libraries from the Zygote process and javacrypto (conscrypt’s native library). libcrypto holds thus share the same virtual memory mappings of these the pointers as global variables in the data section, and libraries, which represent a total of 27 MB of executable thus they are writable. We found calls to the callback code in memory”. Other research also abused Zygote. throughout the code. For example, Kaplan et al. [13] leaked a random value Specifically, we chose to override the id_callback generated in early boot in order to reconstruct the Linux function pointer to point to our code. We then make Psuedo-Random Number Generator (PRNG) state. the target process reach a code path that invokes the Thanks to Zygote, by observing our own, malicious callback function. We do this again using the same trick process’s, memory we are able to realize the function of serializing an object that will be instantiated at the pointer’s address and value in the remote target pro- other end. This time we put an OpenSSLECPrivateKey cess’s memory. Both of these are addresses in libraries

5 that were forked from Zygote (even in system_server, layout of Android processes forked from Zygote, we which also forks from Zygote). noticed boot.oat (used by ART) has a large executable mapping around the 0x70000000 area. Since our con- fp E. Towards Code Execution trolled memory is pointed by (see Section VI-F) we searched for a gadget that directly jumps to a deref- Currently, using the function callback we decre- erenced value relative to fp. We haven’t found such mented, we have the ability to control the PC, i.e. to a gadget, but instead, found a gadget (G1, see Section execute code from an arbitrary address (constrained to VI-J) that takes fp[0], dereferences it 2 more times and a positive int value) in memory. As we don’t currently jumps to the resulting address. Since we control fp[0]’s have code instructions that will perform the tasks we value (the very first WORD in our byte array), and we want in the target process’s memory, at this stage we could make sure that the dereferenced pointer chain will manipulate memory and register values in order to all be at addresses whose adjacent HALFWORDs are prepare our own shellcode for execution. We then jump a positive short, allowing us to fully control the jump to it. We achieved this by passing the shellcode bytes address by our constrained decrement. We thus have to the target process, and by chaining multiple Return- to set 2 additional WORDs using the decrementation Oriented Programming (ROP) gadgets as explained in method described in Section VI-A before running the the next sections. In order to execute the chain of gadget. gadgets using returns, we placed the gadgets’ addresses on the (pivoted) stack and jumped to the first gadget. H. Stack Pivoting We used the Stack Pivot technique to achieve this (see Section VI-H). A common method for attackers to conveniently control program execution involves pointing the stack pointer to an attacker-controlled memory. This allows F. Reliably Locating our Shellcode in the Remote Pro- the attacker to prepare a call stack that includes the cess addresses of the desired ROP gadgets so that each For the Stack Pivot and later steps, we need to time a return instruction (pop {...,pc}) occurs, the have a memory buffer (for the shellcode) at a reliable next gadget runs. The second gadget we run (after location in the remote process’s memory. Traditionally, achieving unconstrained arbitrary address execution) is placing the shellcode in the target process’s memory G2 (Section VI-J). It changes the value of sp to a value is done by using a technique called Heap Spraying, relative to fp, and then returns. Thus from that point that basically involves filling the target process’s heap forwards, our controlled byte array (from Section VI-C.) memory with repetitions of the desired shellcode, in- becomes the program’s stack. creasing the probability that the shellcode will reside at an arbitrary address during the exploitation. In our case, I. Running Our Shellcode Despite SElinux though, the byte array that we fully control during the deserialization of the OpenSSLECPrivateKey object Security-Enhanced Linux (SElinux) is a security en- for triggering our code execution (see Section VI-C) hancement to Linux which allows fine-grained control happens to be directly pointed by the fp (r13) register over access control. It is comprised of kernel modifi- at the time our first gadget’s (see G1, Section VI-J) cations and user-space tools that have been added to opcode is reached. various Linux distributions. It was incorporated into Android in Android 4.3, in permissive mode (permission denials are logged but not enforced), and gradually G. Running Code from an Unconstrained Arbitrary moved to full enforcement in Android 5.0 [20]. SElinux Address assigns processes with a security domain (or type), The next adjacent HALFWORD of id_callback adding the ability to restrict specific processes’ from do- happens to be zero, meaning the value we can overwrite ing certain actions (regardless of the user running them). it with is limited. Due to the fact that id_callback’s The types’ restrictions are defined in .te files. SElinux value always happens to be above 0x7fffffff (it is set takes a secure white-list approach where everything is to the address of a function under libjavacrypto, disallowed, except for the specific rules defined for the which sits at high memory), we can practically change process. id_callback’s value to any positive integer. To over- We decided to run our own shellcode inside the come this limitation, and gain the ability to execute system_server process due to the amount of SELinux gadget at any user-space address, we wanted to find capabilities this process has. (Which is due to the a gadget residing at a positive integer address, that will fact that it hosts many system services.) Our shellcode let us jump to any address.. Observing the memory can then do many sensitive actions. The process is

6 subject to the restrictions of the system_server type running mmap(0x50000000, shellcode_size 9. A required step for running our shellcode, which + EXTRA_FOR_CACHE_EVICTION, PROT_READ we put as part of the OpenSSLECPrivateKey object’s | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | byte array, is to map it as an executable memory. MAP_ANONYMOUS | MAP_FIXED, 0, 0). Note that By default, such an action will be restricted because mmap’s prologue includes pushing the LR register to of SElinux, but as one can see, system_server.te the stack. In its epilogue it is popped from the stack includes the “allow system_server self:process and jumped into. Because we couldn’t easily find a execmem” rule, giving the system_server process the gadget that sets LR value, we used a small trick: we PROCESS__EXECMEM permission, which allows it to map don’t jump to mmap’s real beginning, but rather into anonymous memory as executable. We take advantage mmap just after the instruction that pushes LR. This way of this fact, and use our ROP chain (explained in the LR isn’t placed on the stack at all, and thus later in next section) to map a readable, writable and executable the epilogue, when mmap pops a value from the stack (rwx) memory location, copy our shellcode to that (which was meant to be the saved LR), it gets what we location, and run it from there. placed on the stack in advance, which is the address of We note that we had to overcome a caching problem. the next gadget. ARM has two separate memory caches types - one for (G5) Progress the Stack: pop {r0, r1, r2, r3, instructions and another for data [21]. When we first pc}. This gadget advances the stack pointer abit forward copied our code to the rwx memory area, it was written before jumping to next gadget, so we don’t have an to the data cache, and was not immediately flushed overlapping with the previous gadget’s mmap 5th and into memory. Thus when we jumped to the shellcode 6th parameters, which lie on the stack. location, the processor fetched instructions for execution (G6) Call memcpy and return to Shellcode: add directly from memory, while our shellcode was still r1, sp, #0x24c; pop {r0, r2, r5, r7, pc}. residing in the data cache. In order to overcome this, This gadget prepares r1 (memcpy’s first argument) we copy a large memory amount after our shellcode, to point to our shellcode in memory, and then filling the data cache. By doing so, we manage to evict calls memcpy(0x50000000, OUR_SHELLCODE, (flush) our shellcode from the data cache to memory. shellcode_size + EXTRA_FOR_CACHE_EVICTION). Note that we used the same trick as mentioned in the J. ROP Chain mmap gadget, for setting the return address to be our The series of of ROP gadgets we use is summarized shellcode location. here. The gadgets map a rwx memory area in (the K. The Shellcode unused) address 0x50000000, copy the shellcode there and jump to it. All the gadgets were found inside We compiled a shellcode written in C that uses libraries that are loaded by Zygote. They were found library functions to perform its actions. The shellcode either manually (in boot.oat, which isn’t a valid ELF is compiled with placeholders for the library functions, binary), or by using ROPGadget10. that are resolved (using the Zygote method, see Section (G1) Jump to an Arbitrary Address: mov r1, VI-D.) and changed by our application before triggering fp; ldr r0, [r1, #0]; ldr.w r0, [r0, #444]; the exploit (i.e. before the shellcode is sent). In Section ldr.w lr, [r0, #44]; blx lr. Found in boot.oat, VII we list some options for the shellcode. which is at a positive integer address . This gadget is used for jumping to an unconstrained arbitrary memory VII. Impact address by taking a value relative to fp and jumping to it. In this section we list a few options for a shellcode (G2) Stack Pivot: mov sp, fp, and return. targeting system_server. While this list is incomplete, (G3) Allocate Buffer on Stack: add.w sp, sp, it surely demonstrates the severity of the vulnerability. #0x420, and return. Used to allow more stack space before calling libc functions. It is needed since our A. Replacing Existing Applications byte array happens to be near the beginning of a page, The shellcode can replace any user app on the device and we don’t want the stack to grow down to an (residing in /data/app//base.apk) unmapped memory area. with arbitrary (malicious) app. It can then reboot the (G4) Map RWX memory: pop {r0, r1, device (so changes will take place immediately) by r2, r3, pc}. This gadget is used for setting the sys.powerctl property (by calling the libcutil’s property_set function). The malware 9https://android.googlesource.com/platform/external/sepolicy/+/android- 5.1.1_r6/system_server.te will have access to the original app’s data and will be 10https://github.com/JonathanSalwan/ROPgadget launched instead of the original app.

7 B. Completely Bypassing SElinux When this feature is supported, privileged processes can On Android, the SElinux policy can be updated load arbitrary modules into the kernel using a syscall, as by writing the policy configuration files to the long as the kernel was not compiled with module signa- CONFIG_MODULE_SIG /data/security/current directory, and setting ture verification ( ). As can be seen system_server the selinux.reload_policy property to 1. In the in the SElinux policy rules for the pro- system_server.te original SElinux policy that comes with Android cess ( , explained in Section VI-I), system_server 5.1.1 (and others), the only process that is allowed is not restricted from loading ker- allow system_server to write to files under the /data/security is the nel modules, thanks to the “ kernel:system module_request process we control, system_server. One can find this ” rule. allowance in the system_server.te file under the For security reasons, many Android kernels, in- macro selinux_manage_policy(system_server) cluding Google Nexus 5’s were not compiled with CONFIG_MODULES which gets transformed (definition in the te_macros , and hence this section is irrelevant to file) to allow permissions for directory, file or link them. Despite that, we have encountered other new pop- creation inside /data/security, and permission to ular up-to-date Android devices whose kernels do sup- CONFIG_MODULES CONFIG_MODULE_SIG set the selinux.reload_policy property. port (without ). In order to change the policy, we need to create For testing this basic idea (on our device), we con- the current directory inside /data/security, and ducted the following experiment: we replaced our Nexus write the policy files inside it. The policy consists 5 device’s kernel with a kernel we compiled from AOSP CONFIG_MODULES of the sepolicy binary file, and 6 textual files11: with support. We then used our ex- (1) selinux_version. (2) file_contexts. (3) ploit against it, with a shellcode that loads our kernel property_contexts. (4) seapp_contexts. (5) module (that we compiled in advance) into memory. service_contexts and (6) mac_permissions.xml. We were indeed able to verify the exploit’s success by printk In order to load the new policy, the contents of seeing our module’s ’s messages appear in the /data/security/current/selinux_version device’s dmesg (kernel messages) log. file must be equal to the contents of the /selinux_version file. This is not a difficult VIII. Finding Vulnerable Classes in SDKs task, since the latter just contains the current and Apps Android BUILD_FINGERPRINT value which can be ro.build.fingerprint retreived by reading the As mentioned in Section III, vulnerable classes can libcutils property_get property using ’ . be found in specific apps or frameworks, implying a mac_permissions.xml As for the file, we more restricted (targeted) attack. We therefore decided create a symbolic link to the original file in to analyze the 32,701 most downloaded and free An- /system/etc/security/mac_permissions.xml . droid apps in order to find such classes. Since using We simply create a symbolic link, because in contrast our aforementioned runtime technique to conduct this to the rest of the files, this file isn’t opened with experiment would take hours to complete, we decided O_NOFOLLOW the flag, and thus can follow links. As to use a different approach. We created a tool that runs for the contents of the rest of the files, we use files dexlib212 over the apps’ dex files. dexlib2 gives a generated in advance by either building a custom Reflection-like interface which allowed us to statically Android AOSP image (after changing the SELinux find classes that meet the criteria defined in section IV rules in the textual configuration as we like), or take (again without property 5) in mere 93 minutes. One the original files of the same Android build, but edit caveat of this approach is that dexlib2 is limited to sepolicy sepolicy-inject the binary file using the the classes defined in the given APK’s dex files, so our tool [22]. By taking the second approach, we ran our approach would have false negatives on classes which exploit and successfully changed sepolicy domains inherit from a Serializable Android SDK class or system_server shell_exec ( and ) to be permissive. from an Android SDK class that has a finalize execve sh We then ran a shell command with , that method. In order to compensate for that we created two we were not allowed to perform previously. caches. The first cache is of Serializable Android SDK classes with their attacker-controllable fields (see C. Kernel Code Execution Section IV), while the second is of SDK classes that finalize Linux kernels can be compiled with loadable modules contain a method. Both are based on classes boot.art support, by specifying the CONFIG_MODULES option. found in of our Android 5.1 build (using the technique explained in Section IV). We found a total of 11http://selinuxproject.org/page/NB_SEforAndroid_1- #Device_Policy_File_Locations 12https://github.com/JesusFreke/smali/tree/master/dexlib2

8 358 classes over 176 APKs that met our criteria. Our SWIGEXPORT void JNICALL Java_exampleJNI_delete_1Foo( analysis had quite a few interesting findings. JNIEnv ∗jenv, jclass jcls , jlong jarg1) { Foo ∗ arg1 = ( Foo ∗) 0 ; ( void ) j e n v ; ( void ) j c l s ; A. Vulnerable Classes Generated by SWIG (CVE-2015- arg1 = ∗( Foo ∗∗)&j a r g 1 ; 2000/1/3/4/20) delete arg1; } We witnessed several APKs with a Serializable implementing class that contained a non-transient long Figure VIII.3. Part of the JNI binding code member named swigCPtr. This immediately raised a red flag. Investigating further revealed a very simi- OpenSSLX509Certificate %typemap(javabase) Foo "Bar"; lar to situation, with the %typemap(javainterfaces) Foo "Baz" swigCPtr variable passed to native code. SWIG13 or ’Simplified Wrapper and Interface Gen- Figure VIII.4. SWIG interface with custom class extension and erator’ is an interoperability tool that connects C/C++ interface implementation code with a variety of high-level languages including Java. Running SWIG over a C++ class generates 2 additional components: A Java wrapper to be used by This means that if the developer explicitly chose Java apps, and a JNI interface that interconnects the to implement the Serializable interface, by us- wrapper to the original C++ code. For example, running ing SWIG’s javainterfaces typemap, or more com- SWIG over the very simple C++ code shown by Figure monly, implicitly and probably accidentally by extend- VIII.1 generates the Java wrapper class found in Figure ing a class, using SWIG’s javabase typemap, which is VIII.2 and the JNI binding code partially given by Serializable, the generated code would be vulnerable Figure VIII.3. to our attack since the generated swigCPtr would not be transient. It should be noted that the generated native c l a s s Foo code (Figure VIII.6) for a class with a virtual destructor { can be exploited more easily since the attacker can p u b l i c : Foo ( ) {} trivially control the PC due to the fact that its address is virtual ~Foo() {} fetched from the object’s provided vtable whose pointer }; (swigCPtr) the attacker fully controls. Therefore it does not require overwriting a callback pointer as opposed to Figure VIII.1. C++ code as an input to SWIG the technique shown in Section VI. As for non-virtual destructors, the flow reaches the global delete operator which reduces the problem to exploiting an arbitrary public class Foo { free. private long swigCPtr ; protected boolean swigCMemOwn ; The fact that SWIG can generate vulnerable code has ... an amplification potential. We indeed found multiple protected void finalize() { d e l e t e ( ) ; SDKs that included vulnerable SWIG-generated classes } which further amplified the problem. Among the vulner- public synchronized void d e l e t e ( ) { i f (swigCPtr != 0) { able SDKs were Jumio (CVE-2015-2000), MetaIO SDK i f ( swigCMemOwn ) { (CVE-2015-2001), PJSIP PJSUA2 (CVE-2015-2003), swigCMemOwn = f a l s e ; exampleJNI. delete_Foo(swigCPtr); GraceNote GNSDK (CVE-2015-2004) and MyScript } (CVE-2015-2020). A total of 18 APKs in our sample swigCPtr = 0; } set used these SDKs and ended-up to be vulnerable. super . d e l e t e ( ) ; We argue that the fact that the application can ac- } Serializable ... cidentally implement the interface, by } extending a Serializable class such as Exception, is the root cause of this issue, although we also encoun- Figure VIII.2. SWIG-generated Java wrapping class tered an explicit implementation of the Serializable interface. As shown by Figure VIII.5, it is possible to instruct SWIG to make the wrapping class extend another or B. ArcGis Runtime SDK for Android (CVE-2015-2002) implement a specific interface by having a special SWIG interface file (Figure VIII.4) . Similarly, ArcGis Runtime SDK for Android by esri contained a class with a attacker-controllable pointer 13http://www.swig.org/ which propagated to native code.

9 writeObject public class Foo extends Bar implements Baz { / methods, effectively making the vul- private long swigCPtr ; nerable class non-Serializable. The MetaIO SDK protected boolean swigCMemOwn ; ... was fixed as well, as it no longer implements the } Serializable interface.

Figure VIII.5. Result of using the custom SWIG interface file C. Patched SWIG Since the generated vulnerable code was due to bad Java_exampleJNI_delete_1Foo configuration given by the developer, we do not consider . text:000023A4 PUSH {R0−R2 , LR} es SWIG to be vulnerable. This is somewhat analogous . text:000023A6 MOVS R0, R2 . text:000023A8 STR R2, [SP,#0x10+var_10] to blaming a for buffer overflows. However, . text:000023AA STR R3, [SP,#0x10+var_C] even the most competent developers could miss the fact . text:000023AC CMP R2, #0 . text:000023AE BEQ locret_23B6 that they accidentallly extended a Serializable class. . text:000023B0 LDR R3, [R2] Therefore we decided to contact SWIG team which . text:000023B2 LDR R3, [R3,#4] . text:000023B4 BLX R3 released a more secure version. The patched version . text:000023B6 POP {R0−R2 , PC} generates the swigCPtr member with the transient modifier. Figure VIII.6. Compiled JNI code using the Android NDK tool-chain X. Discussion C. Google Play Services (ANDROID-2153894) While the patches fixed the specific instances that We also encountered the vulnerable we had found, we feel that a general problem de- OpenSSLX509Certificate class in the Google serves a general mitigation, reducing the impact of Play Services (GMS) APK. Google has tracked it with such serialization attacks. Since Bundles are very the above internal identifier and the same CVE as of common in Android’s Inter-Process Communication, the Android Platform instance. we suggest changing the Bundle’s default behavior that automatically instantiates all of its values (under IX. Mitigation BaseBundle.unparcel, that is invoked by any ’touch’ of the Bundle) to a lazy approach, i.e. retrieving We privately disclosed the vulnerabilities to the various only the values of keys it is asked for. Of course by vendors and code maintainers prior to the publication design the problem will still remain, but will depend of this paper. The disclosure timeline is summarized by more on specific developer’s code, so less apps will Table I. The following describes the various patches that be vulnerable if another vulnerable class is found, the vendors made to their vulnerable code. significantly narrowing the attack surface. In addition, further protection that prevents arbitrary readObject, A. Patched OpenSSLX509Certificate readReplace, writeObject or writeResolve meth- ods to be called can be achieved by deprecating the cur- Google has fixed the two rent getParcelable and getSerializable methods OpenSSLX509Certificate instances by adding the (of both Bundle and Parcel) and change the to transient modifier to the mContext member. Google include the class name of the expected objects. has also backported the patch to Android 4.4 (commit id Furthermore, mitigating exploitation is also possible. 0b9d6334acde7460502face82417de40e438a3f4), First, as explained in Section VI, ASLR is pretty much 5.0 and 5.1 (commit id de55e62f6c7ecd57d0- useless in Android if the attacker can launch malware. a91f2b497885c3bdc661d3). The patch is also [19] provides a secure replacement for the insecure available in Android M (build MPZ79M). Zygote implementation. In addition, as our PoC exploit overwrites a function pointer, pointer integrity mecha- B. Patched SDKs nisms are also possible. One might think that callback We reported the issues to the relevant vendors or pointers must be writable, because of their functionality, code maintainers. Jumio removed the vulnerable SWIG i.e. they have to be dynamically changed throughout classes. esri has patched the ArcGis Runtime SDK program lifetime. However, this does not have to be the by adding the transient modifier to the native pointer. case. One mechanism that solves this problem is keep- MyScript and GraceNote fixed their SDKs by adding ing the memory area that holds the function pointers to the transient modifier to the sensitive variables, PJSIP read only, and the memory will become writable by the patched PJSUA2 by by overriding the readObject callback setter functions just for the period of changing

10 Product Identifiers Report date Patched version(s) Android CVE-2015-3825 05/22/2015 Android M / 5.x / 4.4 ANDROID-21437603 Google Play Services CVE-2015-3825 06/01/2015 7.5.73 ANDROID-21583894 Jumio SDK CVE-2015-2000 06/11/2015 1.5.0 MetaIO SDK CVE-2015-2001 06/11/2015 6.0.2.1 esri ArcGis CVE-2015-2002 06/11/2015 10.2.6-2 MyScript CVE-2015-2020 06/16/2015 1.3 PJSIP PJSUA2 CVE-2015-2003 06/14/2015 SVN Changeset 5132 GraceNote GNSDK CVE-2015-2004 06/14/2015 1.1.7 SWIG - 06/11/2015 3.0.7 Table I DISCLOSURE LOG

the values. A different mitigation approach, that is Gradle and its 3rd-party plugin, Gradle Versions Plugin, discussed by Stefan Rattger [23] proposes to white- which notify the developer when a new version is list function pointer values to identify cases where the available for a used SDK, are a pretty good start. function pointers are being abused. Another interesting mitigation is treating fields as transient by default (i.e. an opt-in approach as opposed to the current opt-out XI. Acknowledgements one). As for the specific payloads we show in Section VII, disabling CONFIG_MODULES,or at least enabling We would like to thank the following teams and indi- CONFIG_MODULE_SIG as well, is a good practice. A viduals: more restrictive SELinux non-bypassable policy should • Google and the various SDK teams (Jumio / esri also be deployed. / MyScript / MetaIO / PJSIP / GraceNote) for the In Android 5.0, the WebView component was moved prompt responses and patching. This shows without to an updatable APK [24], decoupling it from the rest of doubt their commitment for security. the system. This had quite a few significant advantages • The SWIG team, and especially William S. Fulton, with respect to security. First, it allowed Google to for making SWIG more secure. release security patches much faster. Second, it tackled • Sagi Kedmi of IBM X-Force Application Security the Android fragmentation problem as patches could be Research Team for his help with the 32k apps backported for old Android versions more easily, and experiment. delivered to various devices all at once. We encourage Google to continue their efforts towards decoupling the vendors’ dependent code from the rest of the system, so References patches will be available much faster. Our case showed the significance of such a separation, as the Google Play [1] IDC. Smartphone OS Market Share, Q1 Services instance of OpenSSLX509Certificate was 2015, 2015. URL http://www.idc.com/prodserv/ updated, in multiple Android versions, 3 days after our smartphone-os-market-share.jsp. report. [2] William Enck, Machigar Ongtang, and Patrick As opposed to vulnerabilities found in final products, McDaniel. Understanding Android Security. IEEE such as operating systems or applications, where an Security and Privacy, 7(1):50–57, January 2009. automatic update mechanism is usually available, the ISSN 1540-7993. doi: 10.1109/MSP.2009.26. situation is by far worse for SDKs. One vulnerable SDK URL http://dx.doi.org/10.1109/MSP.2009.26. can affect dozens of apps whose developers are usually [3] Thorsten Schreiber. Android Binder: Android unaware of it, taking months to update. For example, a Interprocess Communication, October 2011. URL recent study [15] shows that a high severity vulnerability https://www.nds.rub.de/media/attachments/files/ [11] found in Apache Cordova for Android, although 2012/03/binder.pdf. been patched for months, still affects dozens of An- [4] Kun Yang, Jianwei Zhuge, Yongke Wang, Lujue droid apps which use Cordova. The situation is most Zhou, and Haixin Duan. IntentFuzzer: Detecting frustrating for apps which use orphan SDKs, ones that Capability Leaks of Android Applications. In no longer receive security updates. Developers should Proceedings of the 9th ACM Symposium on Infor- be aware that depending on 3rd-party SDKs has that mation, Computer and Communications Security, significant risk, prepare for alternatives, or choose their ASIA CCS ’14, pages 531–536, New York, NY, used SDKs wisely. Developers also deserve better tools - USA, 2014. ACM. ISBN 978-1-4503-2800-5. doi:

11 10.1145/2590296.2590316. URL http://doi.acm. 2013/12/android-collapses-into-fragments.pdf. org/10.1145/2590296.2590316. [13] David Kaplan, Sagi Kedmi, Roee Hay, and [5] Roee Hay, Omer Tripp, and Marco Pistoia. Avi Dayan. Attacking the Linux PRNG Dynamic Detection of Inter-application On Android. In 8th USENIX Workshop Communication Vulnerabilities in Android. on Offensive Technologies, WOOT ’14, San In Proc. ISSTA, pages 118–128. ACM, 2015. Diego, CA, USA, August 19, 2014., 2014. URL http://researcher.ibm.com/researcher/files/ URL https://www.usenix.org/conference/woot14/ us-otripp/issta15.pdf. workshop-program/presentation/kaplan. [6] Erika Chin, Adrienne Porter Felt, Kate Green- [14] Roee Hay and Or Peles. Remote Exploitation wood, and David Wagner. Analyzing Inter- of the Dropbox SDK for Android, March application Communication in Android. In Pro- 2015. URL http://www.slideshare.net/ibmsecurity/ ceedings of the 9th International Conference on remote-exploitation-of-the-dropbox-sdk-for-android. Mobile Systems, Applications, and Services, Mo- [15] David Kaplan and Roee Hay. IBM X-Force Threat biSys ’11, pages 239–252, New York, NY, USA, Intelligence Quarterly, 1Q 2015. Technical report, 2011. ACM. ISBN 978-1-4503-0643-0. doi: March 2015. URL http://ibm.co/1wEMKV3. 10.1145/1999995.2000018. URL http://doi.acm. [16] Takeshi Terada. Attacking Android browsers via org/10.1145/1999995.2000018. intent scheme URLs. 2014. URL http://www. [7] Long Lu, Zhichun Li, Zhenyu Wu, Wenke Lee, mbsd.jp/Whitepaper/IntentScheme.pdf. and Guofei Jiang. CHEX: Statically Vetting An- [17] Jann Horn. CVE-2014-7911: Android <5.0 Privi- droid Apps for Component Hijacking Vulnerabil- lege Escalation using ObjectInputStream, Novem- ities. In Proceedings of the 2012 ACM Confer- ber 2014. URL http://seclists.org/fulldisclosure/ ence on Computer and Communications Security, 2014/Nov/51. CCS ’12, pages 229–240, New York, NY, USA, [18] Yaron Lavi and Nadav Markus. CVE-2014-7911 2012. ACM. ISBN 978-1-4503-1651-4. doi: - A Deep Dive Analysis of Android System Ser- 10.1145/2382196.2382223. URL http://doi.acm. vice Vulnerability and Exploitation, January 2015. org/10.1145/2382196.2382223. URL http://bit.ly/1Q7pdzT. [8] David Kantola, Erika Chin, Warren He, and David [19] Byoungyoung Lee, Long Lu, Tielei Wang, Taesoo Wagner. Reducing Attack Surfaces for Intra- Kim, and Wenke Lee. From Zygote to Morula: application Communication in Android. In Pro- Fortifying Weakened ASLR on Android. In Pro- ceedings of the Second ACM Workshop on Security ceedings of the 2014 IEEE Symposium on Security and Privacy in Smartphones and Mobile Devices, and Privacy, SP ’14, pages 424–439, Washing- SPSM ’12, pages 69–80, New York, NY, USA, ton, DC, USA, 2014. IEEE Computer Society. 2012. ACM. ISBN 978-1-4503-1666-8. doi: ISBN 978-1-4799-4686-0. doi: 10.1109/SP.2014. 10.1145/2381934.2381948. URL http://doi.acm. 34. URL http://dx.doi.org/10.1109/SP.2014.34. org/10.1145/2381934.2381948. [20] Android. Security-Enhanced Linux in An- [9] William Enck, Peter Gilbert, Byung-Gon Chun, droid. URL http://source.android.com/devices/ Landon P. Cox, Jaeyeon Jung, Patrick McDaniel, tech/security/selinux/. and Anmol N. Sheth. TaintDroid: An Information- [21] Jacob Bramley. Caches and Self- flow Tracking System for Realtime Privacy Mon- Modifying Code, February 2010. URL itoring on Smartphones. In Proceedings of the http://community.arm.com/groups/processors/ 9th USENIX Conference on Operating Systems blog/2010/02/17/caches-and-self-modifying-code. Design and Implementation, OSDI’10, pages 1– [22] Michal Krenek. setools-android with 6, Berkeley, CA, USA, 2010. USENIX Asso- sepolicy-inject, December 2014. URL http: ciation. URL http://dl.acm.org/citation.cfm?id= //forum.xda-developers.com/android/software/ 1924943.1924971. setools-android-sepolicy-inject-t2977563. [10] Roee Hay. Overtaking Firefox Profiles, March [23] Stephen Rattger. PoC: Function Pointer Protection 2014. URL http://slidesha.re/1gqiyD3. in C Programs, August 2013. URL http://gcc.gnu. [11] David Kaplan and Roee Hay. Remote Exploitation org/ml/gcc/2013-08/msg00224.html/. of the Cordova Framework. Technical report, [24] TJ VanToll. What Android 5.0’s Auto-Updating 2014. URL http://www.slideshare.net/ibmsecurity/ WebView Means for Mobile Apps, November remote-exploitation-of-the-cordova-framework. 2014. URL http://bit.ly/1DqQ4RC. [12] Roee Hay. Android Collapses into Fragments, December 2013. URL https: //securityintelligence.com/wp-content/uploads/

12