Page cover

Cheese CTF

Inspired by the great cheese talk of THM!

Room Link

This work by Manav G Krishna is licensed under CC BY-NC 4.0

Machine IP: 10.10.94.254

Hosts file entry: echo '10.10.94.254 cheese.thm' | sudo tee -a /etc/hosts

Nmap Scan:

Our traditional scan method shows that tons of ports are open.

We can now better the Nmap command using the --top-ports switch, like so:

By specifying a value of 20 for the --top-ports switch, Nmap scanned for the top 20 most commonly used ports. Let us start by checking out these web-related ports - 80, 8080.

Enumeration

Checking out port 8080

We get this command:

Let us decode the base64 content from it:

Command:

The command just decodes a base64 string to execute Perl code that prints PWNED five times, retrieves and prints the current working directory, and displays a message about uploading your home directory.

Nothing of interest here. Let us now move on to check out port 80.

Checking out port 80:

We can now check out the Login option.

The first approach to consider when coming across a login page like this is to check if it's vulnerable to SQL Injection.

Exploitation

Intercepting the Login request in Burp:

Testing for SQL Injection:

We can try a basic UNION command to determine the possible number of columns.

The payload that worked:

This means we have 3 columns.

Upon sending this request we get a 302 status code in the response for a redirection.

Once Follow redirection is selected, we successfully get redirected to the Admin Panel:

As expected we indeed have 3 columns - Orders, Messages & Users.

The endpoint being /secret-script.php having a URL parameter named file, like so - /secret-script.php?file=

We may have a potential LFI (Local File Inclusion) vulnerability here. Before diving deeper, let's see if SQLMap can uncover any valuable information.

Running SQLMap:

The request file:

Command:

It found the /secret-script.php endpoint.

And we also got a password hash for a user named comte. Attempting to crack this hash did not yield any results.

Also, the resource paths (orders.html, messages.html, users.html) could be fetched via directory busting:

Command:

The users.html path:

The messages.html path:

The orders.html path:

Now let us get back to the possible LFI on the file parameter. As we have noticed any valid file that is present on the server gets fetched when passed as a value for that parameter. This can be abused to potentially read files sensitive files on the server.

Trying to read /etc/passwd file:

And we indeed have a successful LFI.

We now know that the comte user that we had come across before in the SQLMap output is a user on the machine. At this point, we have to find a way to convert the LFI that we currently have to a RCE (Remote Code Execution).

LFI to RCE:

The above method is what leads us to achieve RCE.

We can first try out the example shown to generate a phpinfo() chain.

Command:

Now the payload that it generated has to be passed as a value for the file parameter:

We get the phpinfo() page. So we now have a successful RCE.

Foothold

Now we can use a PHP reverse shell as the chain in the command.

The IP specified in the payload is the tun0 interface IP.

Setting up a listener on port 443:

Command:

The reverse shell command is passed as an argument for the --chain switch by enclosing it within PHP tags.

We have got a connection as www-data.

Upgrading the current shell a little.

Commands:

Lateral Movement

Checking out the /home directory:

We get the user flag in comte's home directory but we (www-data) as others have no permissions at all on the flag file. Reading the file is not possible at this point.

We can now get inside the .ssh directory:

We as others, have both read and write permissions (rw-) on the authorized_keys file. We can now generate a ssh key pair and the public key can be placed within this file.

Command:

The public key:

Placing it on the target machine:

Now we can SSH in as comte:

Command:

Now we can fetch the user flag:

Privilege Escalation

We can now check for comte's sudo rights/privs:

We are allowed to run a few commands related to a systemd timer unit file named exploit.timer, as any user without us being prompted to enter a password. This is our way to get to root.

Timers are files that control .service files or events. So we might later end up finding a .service file that would be of importance.

Let us first find the location of the exploit.timer file.

Command:

Checking out the file and it's permissions:

The timer file's owner and group are both root. Since we (comte) fall under others, we have read, write & execute permissions (rwx) on the file.

We can now try to start the exploit.timer based on the sudoers entry.

It failed saying there is a bad setting within the file and it tells us to run systemctl status exploit.timer to find out more about the issue. Let us go ahead and do the same.

Upon running the command we notice that this timer unit file is set to trigger a .service file named exploit.service. We have indeed found the file that we had talked about above.

Again, let us start by finding where this .service file is located.

Command:

It is located within the same directory as the exploit.timer file.

Checking out the file:

When the service gets started due to it getting triggered by running the exploit.timer, the command that will be run is this:

It copies the xxd utility to the /opt directory and sets the SUID bit on it. Since the exploit.timer file will be run with sudo privileges, the root-owned xxd binray gets copied without any permission issues and will have the bit set and this would lead to an easy privilege escalation.

The /opt directory is currently empty without any files.

Now let us get back to the error in the exploit.timer file. It had occurred because no value was set for the OnBootSec directive and it expects one. This directive is meant to specify a duration after boot to start the timer.

The value that we specify doesn't affect our approach at all because if we remember we can start the exploit.timer file manually with sudo privileges. So it will end up triggering the exploit.service immediately.

For the sake of specifying a value for the OnBootSec directive, let us set it to 30 mins:

Now the systemd daemon needs to be reloaded for the changes to take effect.

Command:

Now let us start the exploit.timer.

Command:

All that is left to be checked now is the /opt directory. If everything worked as intended we would be having the root-owned xxd binary in there having the SUID bit set.

And we have it. Since the SUID bit is set, the binary when used will run only with the permissions of the owner, that being root in this case.

This leaves us with a simple xxd privilege escalation:

GTFOBins

We have to first set the LFILE variable to read a particular file, in this case, we can directly read the root.txt file:

We now have the root flag.

Room solved!!

Profile Link

Last updated