The little lotus just showed its sharp corners

0 x00 review


Cve-2014-7911 is a vulnerability worthy of android security researchers to learn, the cause and utilization of the vulnerability involves Java serialization, Android Binder IPC communication, ROP, Stack Pivot, Heap Spray and many aspects of knowledge. This article detailed drops.wooyun.org/mobile/6082 and Crash bug POC are analyzed. Based on the existing EXP of Retme and Secauo, this paper continues to write the vulnerability utilization part on their shoulders. The ultimate goal is to use this vulnerability to execute the code with system authority. Because the level is limited, please criticize and correct.

Let me start with a review. Mentioned earlier, the use of Java reflection and Binder inter-process communication mechanism, introduced into a cannot be serialized to system_server malicious objects, because the Java. IO. ObjectInputStream did not check whether the input object instance is the actual serializable, So when the object instance is deserialized by ObjectInputStream, type obfuscation occurs and the object’s Field is treated as a pointer to be handled by native code, giving the attacker control. As follows,

If (* (* (mOrgue + 4)) = = 1) {refs (mOrgue + 4) r2 = = * * (* (*) (refs + 8) + 12) BLX r2} -- -- -- -- - > access controlCopy the code

MOrgue is under the attacker’s control. After dereference of Pointers, mOrgue finally jumps to the address under the attacker’s control with the permission of SYSTEM_server (UID =1000) to execute the code, so as to realize the rights lifting from the common user to the system user.

0x01 Dalvik-heap Spray


In order to enable the above BLX R2 instruction to reliably and stably jump to the code that the attacker can control, heap injection technology is needed to pre-deploy a large number of Spray Buffer in dalvik-heap of system_server memory space, in which the weight lifting code and a large number of addresses pointing to the weight lifting code are placed. There are two issues involved.

  1. How do I pass controllable strings into the Dalvik-heap space of syseTEM_server?
  2. How do you lay out these controllable strings in the Dalvik-heap so that the code executes stably every time a vulnerability is exploited?

For the first question, we know that System_server provides most of the system services to the Android system, and that there are specific ways to pass String to system_server through these services, System_server also stores these strings in the Dalvik-heap and does not destroy them until GC. For example, the registerReceiver method in android.content.context below

public Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler)
Copy the code

Where broadcastPermission is String. After calling this method, the String Buffer will reside in the system_server process space. See the specific call chain

ContextWrapper.registerReceiver->ContextImpl.registerReceiver->ContextImpl.registerReceiverInternal->ActivityManagerProx y.registerReceiver->ActivityManagerService.registerReceiverCopy the code

The invocation chain shows that may be passed from one app Context binder IPC across processes call system_server ActivityManagerService. RegisterReceiver method, Notice that ActivityManagerService resides in the system_server process space. Let’s look again at the registerReceiver method of ActivityManagerService

public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId) { enforceNotIsolatedCaller("registerReceiver"); int callingUid; int callingPid; synchronized(this) { ...... ReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder()); . BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId); // Allocate memory to dalvik-heap rl.add(bf); . return sticky; }}Copy the code

Note that the above new will allocate memory in the dalvik-heap of the system_server process, and the passed String Buffer, or permission, will reside in the system_server process space. Thus, the problem of passing in the first string is solved by calling some system Api.

Let’s look at the second question: How do I lay out these controllable strings in the Dalvik-heap so that I can execute the code stably every time the vulnerability is exploited?

According to the previous statement, the attacker’s controllable mOrgue needs to point to a readable memory region, This can be done by simply pointing to the address region of the passed registerReceiver method permission parameter String Buffer and placing an ROP Gadget in the String Buffer. However, the offset address of the String Buffer allocated by system_server in its Dalvik-heap is unknown, and mOrgue may not be able to hit the memory allocated for the String Buffer in the heap. In order to improve the hit ratio, a large amount of String Buffer needs to be allocated to the Dalvik-heap, which is called Heap Spray. Heap Spray can be completed by repeatedly calling the registerReceiver method to allocate a large amount of String Buffer. However, the address of the String Buffer is different each time the registerReceiver method is called to allocate memory, which requires the construction of a special heap ejection layout with decaying pointer values, as shown in the figure.

As shown in the figure, each chunk allocated in the heap contains Relative Address chunk and Gadget_buffer. The goal is to have the controlled STATIC_ADDRESS (mOrgue) in Relative Address Chunk, where [STATIC_ADDRESS]=GADGET_BUFFER. The simple idea is to place GADGET_BUFFER in each chunk’s relative Address chunk. However, since GADGET_BUFFER is different in each chunk and cannot be known in advance before it is passed to the system_server across processes, So this idea is not feasible.

Note that GADGET_BUFFER = the address of the bottom of the heap + Gadget_buffer_offset(the offset of GADGET_BUFFER relative to the bottom of the heap). If STATIC_ADDRESS= the address at the bottom of the heap, GADGET_BUFFER = STATIC_ADRRESS+Gadget_buffer_offset. For four-byte alignment, STATIC_ADDRESS= bottom heap address +4N (N=1,2…) GADGET_BUFFER = STATIC_ADDRESS + gadget_buffer_offset-4n. Therefore, in the Relative Address Chunk area of each Chunk, Enter STATIC_ADDRESS+Gadget_buffer_offset, STATIC_ADDRESS+Gadget_buffer_offset-4,… , STATIC_ADDRESS + Gadget_buffer_offset – 4 n. Thus, given a STATIC_ADDRESS, as long as it falls into the Relative Addresses Chunk range assigned by system_Server on the Dalvik Heap (to increase this probability, 1 is required). The Relative Address Chunk of each Chunk is much larger than the Gadget Buffer. [STATIC_ADDRESS]=GADGET_BUFFER and [STATIC_ADDRESS+4N]= gadget_buffer-4n (this condition will be used later when gadgets are deployed).

With this layout, go back to the assembly code and lay out the Gadget_Buffer.

ldr     r4, [r0, #4]   # r0=STATIC_ADDRESS-->r4=[STATIC_ADDRESS+4]=GADGET_BUFFER-4
mov     r6, r1
mov     r0, r4  # r0=GADGET_BUFFER-4
blx     <android_atomic_dec ()>
Copy the code

After calling android_atomic_dec

cmp     r0, #1          # r0 = [GADGET_BUFFER-4]
bne.n   d1ea
ldr     r0, [r4, #8]    # r0 = [GADGET_BUFFER-4+8] = [GADGET_BUFFER+4]
mov     r1, r6
ldr     r3, [r0, #0]    # r3 =[[GADGET_BUFFER+4]] = [STATIC_ADDRESS+12] = GADGET_BUFFER-12
ldr     r2, [r3, #12]   # r2 = [GADGET_BUFFER -12 +12] = [GADGET_BUFFER]
blx     r2       
Copy the code

First, in order to enter BLX R2, r0 must be equal to 1, i.e. [GADGET_BUFFER-4]=1; Second, [GADGET_BUFFER+4] must be a valid and readable address. To facilitate subsequent layout, we set [GADGET_BUFFER+4]=STATIC_ADDRESS+12. R2 =[STATIC_ADDRESS+12]= [GADGET_BUFFER +12]=[GADGET_BUFFER] The program will jump to the GADGET_BUFFER, so you can place the ROP Gadget1 address there. At this point, the second problem of stable code execution is solved with a special layout of heap injection.

0x02 ROP Chain


Since Android uses DEP, the memory on the Dalvik-heap cannot be used for execution, so ROP technology must be used to make the PC jump to a sequence of legal instructions (gadgets) from which shellcode can be “pieced together”. Here we will use the ROP Gadget to call the System function to execute the code.

Using ROPGadget, search on base modules loaded by Zygote (e.g. Libbc. So, libwebviewchromium.so, libdvm.so) and use arm code as thumb code to add more candidate instruction sequences.

To call the system function, we need to control the R0 register, which points to our prearranged command line string as an argument. The Stack Pivot technique is used to point the top Stack pointer SP to the data in the controlled Dalvik-heap heap, which makes it easy to control PC registers and place data on the Stack. using

ROPgadget --thumb --binary libwebviewchromium.so
Copy the code

You can find the following Gadget

Gadget1

Prepare for Stack Pivot

in libwebviewchromium.so

70a93c:       682f            ldr     r7, [r5, #0]  #r5=STATIC_ADDRESS, r7=[STATIC_ADDRESS]=GADGET_BUFFER
70a93e:       4628            mov     r0, r5       #r0=STATIC_ADDRESS
70a940:       68b9            ldr     r1, [r7, #8] #r1=[GADGET_BUFFER+8]
70a942:       4788            blx     r1
Copy the code

or

4fed02:       4628            mov     r0, r5           #r5 = STATIC_ADDRESS
4fed04:       682f            ldr     r7, [r5, #0]     #r7 = [STATIC_ADDRESS] = GADGET_BUFFER
4fed06:       f8d4 8048       ldr.w   r8, [r4, #72]   ; 0x48
4fed0a:       68b9            ldr     r1, [r7, #8]     #r1 = [GADGET_BUFFER+8]
4fed0c:       4788            blx     r1
Copy the code

Therefore, the GADGET_BUFFER+8 address needs to point to the second Gadget

Gadget2

Stack Pivot

in libdvm.so

664c4:       f107 0708       add.w   r7, r7, #8   #r7=r7+8=GADGET_BUFFER+8
664c8:       46bd            mov     sp, r7       #sp=GADGET_BUFFER+8
664ca:       bdb0            pop     {r4, r5, r7, pc}
# r4=[GADGET_BUFFER+8],r5=[GADGET_BUFFER+12],r7=[GADGET_BUFFER+16],pc=[GADGET_BUFFER+20], sp=GADGET_BUFFER+24
Copy the code

As you can see, after pointing SP to controllable data in the heap, you can control the PC later. Here, we pre-write the address of the system function [GADGET_BUFFER+12]. Why do you need to transition from Gadget1 to Gadget2? In fact, you have no choice but to use ROPGadget to search the base module grep “mov sp,r” under /system/lib. Only mov sp,r7 is found, so you can only use this transition method.

Next, fill in the address of Gadget3 at GADGET_BUFFER+20

Gadget3

in libwebviewchromium.so

30c4b8:       4668            mov     r0, sp   #r0=GADGET_BUFFER+24
30c4ba:       47a8            blx     r5       #r5=[GADGET_BUFFER+12]=system_addr
Copy the code

Therefore, just put the arguments of the system function into GADGET_BUFFER+24 that r0 points to in advance, and you will eventually execute any code with system_server privileges.

The final chunk layout is shown below.

Finally, there is another detail to be considered in constructing ROP Chain. ARM has two modes: Thumb and ARM mode. Gadgets we used are all in Thumb mode, so the lowest address of each should be added by 1.

0x03 ASLR


Android has enabled ASLR (Address randomization) since 4.1. The address space of any application itself changes every time it runs. But in Android, the attacker and system_server are fork by zygote process, so the attacker and system_server share the same base module and dalvik-heap. As long as you only use basic modules like libc and libdvm when using Dalvik Heapspray and building ROP gadgets, there is no need to worry about address randomization. Parsing the attacker’s own /proc/ /maps file reveals the base address of the loaded base module. As shown in figure,

The POC based on the above Gadgets can be found at github.com/heeeeen/CVE… After the command is executed, a pwned. TXT file is generated in the /data directory as the system user.

0 x04 repair


See android.googlesource.com/platform/li… , involving related to deserialize ObjectInputStream. Java, ObjectStreamClass. Java, ObjectStreamConstants. Java, SerializationTest. Java files, etc. Three main tests were added:

  1. Check that the deserialized class still meets the requirements for serialization;
  2. Check whether the deserialized class type is consistent with the type information (enum, serialIZABLE, externalIZABLE) held in stream.
  3. In some cases, the static initialization of the class is delayed until the contents of the serialized stream are checked.

0 x05 reference

1. researchcenter.paloaltonetworks.com/2015/01/cve…

2. github.com/retme7/cve-…

3. github.com/retme7/my-s…

4. secauo.com/cve-2014-79…