---
# System prepended metadata

title: Thoughts on pwn/tinyfs from TSG CTF 23

---

[toc]

# Overflow_in_MyFolder_name
The specified name is too short for the actual directory name allowed to input.
```c
#define NAME_MAX 0x20 - 1
```
```c
struct MyFolder {
    char name[NAME_MAX + 1];
    struct MyFolder* parent;
    struct MyFile* files[CONTENT_MAX];
    struct MyFolder* folders[CONTENT_MAX];
};
```
But it checks for path length `PATH_MAX = 0x30-1`
```c
    if (get_path_length(pwd) + strlen(name) > PATH_MAX) {
        printf("The length of path should be shorter than or equal to %d.\n", PATH_MAX);
        return;
    }
```

When now printing the name of the folder it will print out the pointer `MyFolder* parent` which points to the heap.

Using this we can also overwrite the first entry of the `files` array with an alphanumeric value.

# Check if heap address is in alphanumeric range
Now we can check whether all bytes of the heap base are inside alphanumeric range. "0"-"9" or "A"-"Z" or "a" - "z". We need to do this because we want to overflow the `files` array with a heap address. And we can only enter alphanumeric characters as a name.

We have to rerun the script until the heap base matches that condition.

This bruteforcing of the address and getting the alignment correct is probably the hardest / most annoying part of this exploit

# Place fake file struct pointer in `files` array
Using the overflow described in [here](#Overflow_in_MyFolder_name), we overwrite the first entry of files. Overflow such that it points somewhere into the `files` array.

# Edit our fake file struct
By writing the heap address into the first entry of the `files` array, we can now modify the content of our fake file struct.
To edit it, we need to use the command `mod ` and dont specify a name, since our fake file struct, has a blank name.
# Get arbitrary read
When editing we can now input every character, meaning we are not restricted to alphanumeric characters. To now read from a specific address `where` we need to write the address `where - 0x100` into the content of our fake file struct. 

If we now execute `ls` it will print all names of files it can find in the `files` array. Because our fake file struct is inside the `files` array, it will find the address `where - 0x100` and handles it as a `MyFile*` pointer. 

And since the name of a `MyFile*` is located at offset `+0x100` it will print the content at address `where - 0x100 + 0x100 = where`

# Get libc address into heap.
Now create 9 files and delete the first 8 files. This will fill the tcache (it can hold 7 items) and put one chunk into the unsorted bin. This will result in a libc pointer to the `main_arena` to land in our heap. We needed to allocate 9 chunks because otherwise the 8th byte would be directly next to the top chunk and would have therefore be merged with it, instead of putting it into the unsorted bin.
For more details on malloc internals visit [glibc wiki](https://sourceware.org/glibc/wiki/MallocInternals), or [heap-exploitation-tutorial](https://heap-exploitation.dhavalkapil.com/) or [how2heap](https://github.com/shellphish/how2heap)

# How to leak stack
We can use the arbitrary read to leak the libc address. Using the same arbitrary read, we can now leak the stack from libc address section. Libc contains a pointer to `environ` which is on the stack.

# How to write to a desired location
Getting arbitrary write is a bit tricky, because we can only write to a file if we specify its name. So if we make our fake file struct point to address `where` we need to specify the string located at `where + 0x100` when using the `mod` command.

Meaning if we want to write to `where` and `where + 0x100` contains an invalid name (something that contains a non alphanumeric character) then we cant write to that address.

# How I solved it
I made our fake file struct point to the return address on the stack. Luckily for us, the `return address + 0x100` contains the string "8" which means we can write to `return address` by doing `mod 8`.

Now we can write a ROP chain which executes `system("/bin/sh")` to the stack and trigger it by entering the command `exit`.

# Solve script
The solve script is very unstable, messy and wasnt meant to be published. But maybe its helpful to anyone.

Notes: I did not leak the stack from libc, instead I first leaked ld.so and then leaked stack from ld.so.

https://pastebin.com/ANm14gKd