Welcome to another Hack the Box walkthrough. In this blog post, I have demonstrated how I owned the Fries machine on Hack the Box. Hack The Box is a cybersecurity platform that helps you bridge knowledge gaps and prepares you for cyber security jobs.
About the Machine
Fries is a hard-difficulty Windows machine on Hack The Box that combines web enumeration, credential discovery, container abuse, NFS misconfiguration, Docker API exploitation, LDAP credential capture, Active Directory enumeration, gMSA abuse, and AD CS privilege escalation. The machine starts with a broad external attack surface, where Nmap enumeration reveals services such as SSH, DNS, HTTP/HTTPS, Kerberos, LDAP, SMB, WinRM, and Active Directory-related ports, confirming that the target is part of the fries.htb domain.
After adding the discovered hostnames to /etc/hosts, I performed time synchronization with the domain controller to avoid Kerberos-related issues later in the attack chain. The initial credentials provided with the machine did not work over SSH, so I shifted focus to web enumeration. Subdomain fuzzing revealed code.fries.htb, which hosted a Gitea instance. Using the provided credentials, I authenticated to Gitea and began reviewing repositories and commits.
During Gitea commit enumeration, I discovered sensitive information inside previous commits, including PostgreSQL database credentials, a secret key, and a reference to another internal subdomain: db-mgmt05.fries.htb. After resolving this hostname locally, I accessed the PgAdmin portal and authenticated using the machine-provided credentials. From there, I connected to the PostgreSQL server using the database password recovered from Gitea.
Inside PgAdmin, I performed database enumeration and confirmed that PostgreSQL had dangerous capabilities enabled. I used PostgreSQL file system enumeration with pg_ls_dir('/') to list the container’s root directory and then tested file read access using pg_read_file('/etc/passwd'). After confirming access, I created a command output table and used COPY FROM PROGRAM to test command execution by running id, which showed that commands were being executed as the postgres user.
With command execution confirmed, I used COPY FROM PROGRAM to obtain a reverse shell from the PostgreSQL container. I then upgraded the shell for better interactivity. In parallel, I also exploited an authenticated PgAdmin RCE vulnerability using Metasploit, which gave me a Meterpreter session as the pgadmin user. Post-exploitation enumeration inside the PgAdmin container exposed environment variables containing the PgAdmin default administrator credentials.
I reused the recovered password against a small list of possible SSH usernames and found valid SSH access as the svc user. After logging in, I enumerated local services and discovered an NFS export at /srv/web.fries.htb. I then established an internal network pivot using sshuttle, allowing my Kali machine to access internal services through the compromised host.
To interact with the NFS export from my machine, I installed the required FUSE and NFS tooling, configured /etc/fuse.conf to allow user_allow_other, and mounted the exported share locally. NFS share enumeration revealed directories such as certs, shared, and webroot. The certs directory contained CA and server certificate material, including the CA private key, which created a certificate abuse opportunity.
Using the exposed CA key, I generated and signed a new client certificate with CN=root. I then created an SSH local port forward to access the Docker API listening on 127.0.0.1:2376 on the target. After installing the Docker client locally, I authenticated to the Docker API using the forged certificate and listed the running containers. This confirmed access to containers including pwm, pgadmin4, web, postgres, and gitea.
I entered the PWM container and enumerated its configuration file, PwmConfiguration.xml. The configuration showed that PWM was using LDAP over LDAPS to communicate with dc01.fries.htb and referenced the service account svc_infra. I modified the LDAP server URL in the configuration to point to my attacker machine and started Responder on my VPN interface. When PWM attempted to authenticate, Responder captured the LDAP credentials for CN=svc_infra,CN=Users,DC=fries,DC=htb.
After validating the captured svc_infra credentials with LDAP, I used BloodHound to perform Active Directory enumeration. BloodHound revealed that svc_infra had ReadGMSAPassword permissions over the managed service account GMSA_CA_PROD$. Using bloodyAD, I retrieved the msDS-ManagedPassword attribute and extracted the NTLM hash for the gMSA account. I then authenticated over WinRM as GMSA_CA_PROD$, confirming that the account had remote access.
With the gMSA foothold, I moved into AD CS enumeration using Certipy. Certipy identified the domain certificate authority fries-DC01-CA and revealed vulnerable certificate configurations, including ESC7, ESC6, and ESC16-related weaknesses. I requested certificates through AD CS and eventually authenticated using the generated certificate material. Certipy returned the NTLM hash for the domain Administrator account.
Finally, I used Evil-WinRM with the Administrator NTLM hash to authenticate to the domain controller. This gave me full administrative access to the machine. From the Administrator desktop, I retrieved both root.txt and user.txt, completing the Fries machine. Overall, Fries demonstrates a realistic chained attack path involving web credential leakage, database command execution, container escape-style abuse, NFS certificate exposure, Docker API access, LDAP credential capture, gMSA password retrieval, and AD CS-based domain privilege escalation.
Protected Page
The first step in owning the Fries machine like I have always done in my previous writeups is to connect my Kali Linux terminal with Hack the Box server. To establish this connection, I ran the following command in the terminal:
Initial Access Information
After starting the Fries machine, I noted the assigned target IP address as 10.129.244.72. The machine information also provided an initial domain user account, which meant this box was intended to begin from an authenticated Active Directory enumeration path rather than a completely unauthenticated one.
I used these details as my starting point for the assessment. Since the account belonged to the fries.htb domain, my next steps were focused on validating the credentials and using them to enumerate SMB, LDAP, Kerberos, and other Active Directory services exposed on the target.
Nmap Enumeration
I started the enumeration by running an aggressive Nmap scan with default scripts and version detection against the target. The scan immediately revealed that the machine was not just a web server, but also exposed several Active Directory-related services, including Kerberos, LDAP, SMB, RPC, and WinRM.
From the output, I identified the domain as fries.htb and the host as DC01, which strongly indicated that the target was a Windows Domain Controller. The web service on port 80 redirected to http://fries.htb/, while port 443 exposed a certificate for pwm.fries.htb, giving me additional hostnames to add to my /etc/hosts file for further enumeration.
The presence of ports 88, 389, 445, 636, 3268, 3269, and 5985 suggested a typical Active Directory attack surface, so I focused my next steps on DNS, SMB, LDAP, Kerberos, and web-based enumeration. Nmap also reported a clock skew of around seven hours, which was important to keep in mind for Kerberos-related authentication later in the attack chain.
Hostname Resolution
After identifying the domain name and domain controller from the Nmap scan, I updated my local /etc/hosts file so the target hostnames would resolve correctly from my machine. This was necessary because the web server redirected to fries.htb, and Active Directory enumeration often depends on proper hostname resolution.
I added both fries.htb and dc01.fries.htb to point to the target IP address. With this in place, I could access the web application using its domain name and continue enumerating services that rely on DNS names instead of only using the raw IP address.
Time Synchronization
During the initial Nmap scan, I noticed a clock skew of about seven hours between my machine and the target. Since Kerberos authentication is very time-sensitive, I disabled automatic NTP synchronization on my machine and synced my clock directly with the domain controller.
The ntpdate output confirmed that my system time was stepped forward by roughly 25199 seconds. This ensured that Kerberos-based authentication and enumeration would not fail later due to time mismatch between my Kali machine and the Fries domain controller.
SSH Authentication Attempt
After syncing my system time with the domain controller, I attempted to authenticate over SSH using the provided domain credentials. Since port 22 was open from the Nmap scan, I wanted to quickly verify whether the initial account had direct shell access.
The SSH connection reached the target successfully and added the host key to my known hosts file, but the password authentication failed with Permission denied. This confirmed that the provided credentials were valid for another service path, but not for direct SSH access, so I moved on to enumerating other exposed services such as SMB, LDAP, Kerberos, and the web applications.
Subdomain Enumeration
Since the web service redirected to fries.htb, I continued by enumerating possible virtual hosts under the domain. I used ffuf with a large subdomain wordlist and filtered out 404 responses to focus only on valid hosts.
The scan discovered the code.fries.htb subdomain returning a 200 OK response. This confirmed that another web application was hosted on the target, so I added it to my local host resolution and moved on to exploring the newly discovered code virtual host.
Hostname Resolution
After discovering the code.fries.htb virtual host from the subdomain scan, I updated my local /etc/hosts file again so the hostname would resolve correctly from my machine. Without this entry, the browser and command-line tools would not be able to reach the correct virtual host.
I mapped code.fries.htb to the target IP address 10.129.244.72. With the new hostname resolved locally, I could now access the newly discovered web application and continue enumerating it for possible entry points.
Gitea Authentication
After adding code.fries.htb to my /etc/hosts file, I browsed to the newly discovered virtual host and found a self-hosted Gitea instance.
Since the machine had already provided valid domain credentials, I tested them against the Gitea login portal to see if password reuse or centralized authentication was in place.
I authenticated successfully as the user dale, which confirmed that the provided credentials were also valid for the Gitea web application. This gave me access to the internal dashboard and exposed a private repository named dale/fries.htb.
From the activity feed, I could see multiple commits pushed to the repository, including updates to README.md, .gitignore, docker-compose.yml, and run.py. This made the repository an important target for further enumeration because source code, configuration files, commit history, and deployment scripts often contain credentials, internal endpoints, or application logic that can be abused later.
At this point, I shifted my focus from basic service enumeration to source-code review. Since Gitea stores project history, I planned to inspect the repository files and commits carefully for leaked secrets, database credentials, hardcoded tokens, or references to other internal services running on the Fries machine.
Gitea Commit Enumeration
After authenticating to Gitea, I started reviewing the repository activity and commit history instead of only checking the latest files. This was important because sensitive data is often removed from the current source tree but still remains exposed in older commits.
I clicked on the 3e8ca66c0d commit, which was labeled as a .gitignore update, and inspected the changed files. Inside the commit diff, I found that a .env file had previously contained sensitive application configuration before being removed.
The exposed DATABASE_URL revealed PostgreSQL credentials for the root database user, along with the internal database host 172.18.0.3 and database name ps_db. I also found a hardcoded SECRET_KEY, which suggested the application may rely on this value for signing sessions, tokens, or other security-related functionality.
This was a useful finding because it gave me credentials that were not visible from the current repository files. From here, I planned to investigate whether the database service was reachable directly, through a container network, or by pivoting through the web application that used these leaked environment variables.
Gitea Commit Enumeration
I continued reviewing the Gitea commit history and opened the 47b29c411c commit to look for additional configuration details. This commit updated the README.md file and exposed useful information about how the backend database was expected to be managed.
From the configuration notes, I confirmed that the backend PostgreSQL database used the ps_db schema. More importantly, the commit referenced http://db-mgmt05.fries.htb, which revealed another internal subdomain.
This gave me a new target to enumerate next. Since the hostname was not part of my original /etc/hosts entries, I needed to add db-mgmt05.fries.htb locally before accessing the database management interface in the browser.
Hostname Resolution
After discovering the new database management hostname from the Gitea commit history, I added it to my local /etc/hosts file. This allowed my machine to resolve db-mgmt05.fries.htb directly to the target IP address.
I mapped db-mgmt05.fries.htb to 10.129.244.72 so I could access the database management interface from the browser. With this hostname configured, I was ready to enumerate the newly discovered web service and test whether the leaked PostgreSQL credentials could be reused there.
PgAdmin Authentication
After adding db-mgmt05.fries.htb to my /etc/hosts file, I browsed to the newly discovered hostname. The page loaded a PgAdmin login portal, which confirmed that the subdomain was being used as a PostgreSQL database management interface.
I authenticated successfully using the same credentials provided in the machine information. This confirmed that the initial domain account also had access to the PgAdmin web interface.
Once logged in, I landed on the PgAdmin dashboard as d.cooper@fries.htb, giving me a potential path to interact with the backend PostgreSQL environment. Since I had already recovered database credentials from the Gitea commit history, my next step was to inspect the available servers and determine whether I could connect to the ps_db database from inside PgAdmin.
PgAdmin Server Authentication
After logging into PgAdmin, I clicked on the Servers section to check whether any PostgreSQL servers were already configured. PgAdmin prompted me for the password of the root database user before allowing access to the saved server connection.
I reused the PostgreSQL password that I had previously discovered in the exposed .env file from the Gitea commit history. The authentication was successful, and PgAdmin expanded the fries.htb server entry.
This confirmed that the leaked database credentials were valid and provided direct access to the backend PostgreSQL server through the PgAdmin interface. With the server connection established, I could now enumerate the available databases, roles, schemas, and tables to look for sensitive application data or additional credentials.
Database Enumeration
After authenticating to the PostgreSQL server in PgAdmin, I expanded the fries.htb server tree to review the available objects. The server exposed several sections, including Databases, Login/Group Roles, and Tablespaces.
I expanded the Databases section and selected the postgres database to begin interactive enumeration. From there, I opened the Query Tool, which allowed me to run SQL queries directly against the database server and inspect its contents from within PgAdmin.
PostgreSQL File System Enumeration
After opening the PgAdmin Query Tool, I tested whether the PostgreSQL root user had access to server-side file system functions. I ran pg_ls_dir() against the root directory to check if PostgreSQL could list files and directories from the underlying container.
The query executed successfully and returned Linux filesystem directories such as etc, home, root, var, and tmp. The presence of .dockerenv and docker-entrypoint-initdb.d confirmed that the PostgreSQL service was running inside a Docker container.
This was an important finding because it showed that the database user had enough privileges to interact with the container filesystem. From here, I could continue testing PostgreSQL file-read capabilities and look for sensitive files, mounted volumes, or credentials inside the container.
PostgreSQL File Read
After confirming that PostgreSQL could list directories from the container filesystem, I tested whether the database user could also read local files. I used pg_read_file() against /etc/passwd as a quick proof that server-side file read was possible.
The query returned the root entry from /etc/passwd, confirming that PostgreSQL had permission to read files inside the container. This proved that the database access was not limited to normal SQL enumeration and could be abused for filesystem discovery.
PostgreSQL Command Table Setup
After confirming that the PostgreSQL user could interact with the container filesystem, I prepared a simple table to store command output. This was useful because PostgreSQL command execution techniques often require writing the result of an operation into a table before reading it back.
The query executed successfully and created the cmd_test table. This confirmed that I had enough database privileges to create objects inside the selected database.
With this table in place, I now had a controlled location to capture output from later PostgreSQL-based tests. This became the foundation for checking whether I could move from file read access toward command execution inside the database container.
PostgreSQL Command Execution Test
After creating the cmd_test table, I tested whether the PostgreSQL root user could execute operating system commands through the database. I used COPY ... FROM PROGRAM with the id command and stored the output inside the table.
The query returned COPY 1, which confirmed that the command executed successfully and one row was written into cmd_test. This showed that the PostgreSQL user had enough privileges to run system commands from inside the database container.
At this point, I had moved from database access to confirmed command execution within the PostgreSQL environment. The next step was to read back the table contents and verify which user context the command was running as.
PostgreSQL Command Output Verification
After creating the cmd_test table, I queried it to confirm whether command output had been captured successfully. This helped verify that the previous PostgreSQL-based execution test had written data back into the table.
The table returned the result of the id command, showing that the process was running as the postgres user inside the container. The output confirmed the context as uid=999(postgres) with membership in the postgres and ssl-cert groups.
This was an important checkpoint because it proved that I could execute commands through PostgreSQL and retrieve the output through SQL. From here, I could continue enumerating the container environment as the postgres user and look for paths to escape or pivot further.
Reverse Shell Via COPY FROM PROGRAM
After confirming that COPY FROM PROGRAM could execute commands as the postgres user, I moved from command-output testing to getting an interactive shell. I first started a Netcat listener on my attacking machine to catch the reverse connection.
With the listener running, I went back to the PostgreSQL Query Tool and used COPY FROM PROGRAM to execute a Bash reverse shell payload from the database container.
The payload executed successfully, and my Netcat listener received a connection back from the target. The shell dropped me inside the PostgreSQL container, confirming that I had moved from database access to an interactive command shell.
I ran whoami to confirm the current user context, and the output showed postgres. This confirmed that the reverse shell was running as the PostgreSQL service account inside the container, giving me a foothold for further container enumeration and potential privilege escalation.
Shell Stabilization
After receiving the reverse shell as the postgres user, I upgraded the basic shell to make it more interactive and easier to use. I first spawned a proper Bash session using script, while sending the output log to /dev/null.
Once the Bash session started, I suspended the Netcat session with Ctrl + Z so I could adjust my local terminal settings before bringing the shell back to the foreground.
Back on my local machine, I disabled terminal echo and resumed the suspended Netcat session. This helped make the reverse shell behave more like a normal TTY.
After returning to the shell, I reset the terminal type and exported the required environment variables for a cleaner interactive session.
Finally, I checked my terminal size and applied the same row and column values inside the shell. This made commands, text editing, and terminal output display correctly during further enumeration.
Authenticated RCE via pgAdmin
After confirming access to the pgAdmin portal and the PostgreSQL server, I searched for known issues affecting the pgAdmin version and found an authenticated RCE path through the query tool. Since I already had valid pgAdmin credentials and database credentials, I used Metasploit to automate the exploitation process.
The first attempt showed an error against one target, but Metasploit continued and correctly targeted 10.129.244.72. The module confirmed that pgAdmin version 9.1.0 was vulnerable, authenticated successfully, and initialized the SQL editor.
The 500 response was expected by the exploit module, and shortly after that, a Meterpreter session was opened successfully. I then listed the active sessions and interacted with the new session.
At this point, I had a working python/linux Meterpreter session as the pgadmin user inside the target environment. This confirmed that the authenticated pgAdmin RCE was successfully exploited and gave me a stronger foothold for further enumeration.
Post-Exploitation Enumeration
After getting the Meterpreter session, I first checked the current user context and then dropped into a system shell for deeper enumeration. The session confirmed that the exploit landed as the pgadmin user.
The id output showed that although the username was pgadmin, the process was running with group root, which was interesting for later privilege checks.
I then upgraded the shell using Python’s PTY module and listed the current /pgadmin4 directory to understand the application structure.
After confirming I was inside the pgAdmin application directory, I checked the environment variables for sensitive configuration values.
The environment output exposed important pgAdmin defaults, including PGADMIN_DEFAULT_EMAIL=admin@fries.htb and PGADMIN_DEFAULT_PASSWORD=Friesf00Ds2025!!. This gave me another credential pair to test during the next stage of enumeration.
Credential Reuse Enumeration
After finding the pgAdmin default password in the environment variables, I wanted to check if the same password was reused for any local SSH account. To do this, I created a small username list containing likely users discovered during enumeration.
I added common and target-specific usernames into the file, including service accounts and names already seen during the box.
Next, I used Hydra to test the discovered password against SSH on the target. This helped quickly confirm whether any of the usernames accepted the reused credential.
Hydra successfully identified a valid SSH login for the svc account using the password recovered from the pgAdmin environment.
This confirmed credential reuse between the pgAdmin container configuration and a real SSH user on the host. With valid SSH access as svc, I now had a more stable foothold for further enumeration and privilege escalation.
SSH Access
After Hydra confirmed that the svc account reused the pgAdmin password, I tested the credentials directly over SSH. This gave me a cleaner and more stable shell compared to the earlier reverse shell.
I accepted the host key prompt and authenticated using the recovered password.
The login was successful, and the system banner showed that I landed on an Ubuntu 22.04.5 host named web.
At this point, I had valid SSH access as the svc user. This provided a stable foothold on the target host for further local enumeration and privilege escalation.
NFS Enumeration
After gaining SSH access as svc, I began local enumeration from the user’s home directory and noticed a fries.htb entry. I then checked for locally exported NFS shares to see if any web or shared directories were exposed.
The showmount output revealed that /srv/web.fries.htb was exported to all clients. Listing the directory showed several interesting paths, including certs, shared, and webroot.
The permissions were especially important: shared was world-writable, webroot was owned by svc, and certs belonged to the infra managers group. This suggested the NFS export and web directory structure could be useful for further enumeration, file placement, or privilege escalation.
Internal Network Pivoting
After gaining stable SSH access as svc, I prepared to pivot through the host so I could reach any internal networks or services that were not directly exposed externally. I first checked that sshuttle was installed on my attacking machine.
The output showed that sshuttle was already installed, so I used the svc SSH credentials to create a transparent tunnel through the target.
I authenticated with the recovered password, and sshuttle returned Connected to server, confirming that the tunnel was active.
With this pivot in place, my machine could route traffic through the compromised host. This made it easier to enumerate internal services and network ranges from my local Kali machine as if I were positioned inside the target environment.
NFS Tooling Setup
After confirming that /srv/web.fries.htb was exported over NFS, I prepared my Kali machine to mount and interact with the share using FUSE-based NFS tooling. I first updated my package lists and installed the required development libraries for FUSE and Python support.
Next, I checked the NFS security tooling installation through pipx. The output showed that the tool was already installed, so I did not need to reinstall it.
I then created a local mount directory and attempted to mount the exported /srv/web.fries.htb share through the pivoted internal address 192.168.100.2.
The mount attempt failed because FUSE rejected the allow_other option. The error showed that user_allow_other was not enabled in /etc/fuse.conf.
This meant the NFS tooling was installed correctly, but my local FUSE configuration needed to be adjusted before the share could be mounted with write support.
NFS Mount Configuration
After the first FUSE mount failed because allow_other was not enabled, I updated my local FUSE configuration to permit that option. I used sed to uncomment user_allow_other inside /etc/fuse.conf, then verified that the setting was active.
Before retrying the mount, I cleaned up any stale mount state from the previous failed attempt using both fusermount3 and umount.
With the FUSE configuration fixed, I reran fuse_nfs against the exported /srv/web.fries.htb share over the internal interface.
This time, the tool returned a root file handle instead of an error, which indicated that the NFS export was successfully mounted through FUSE.
At this point, I had local access to the exported web directory through /tmp/nfs_mount, allowing me to enumerate and potentially write to the share from my Kali machine.
NFS Share Enumeration
After mounting the NFS export locally, I listed the contents of /tmp/nfs_mount to inspect the exposed web directory structure. The mounted share showed three main directories: certs, shared, and webroot.
The permissions were useful for understanding the attack surface. The shared directory was world-writable, while webroot appeared mapped to my local user because of the fake UID option used during the FUSE mount.
Next, I inspected the certs directory to see what certificate material was exposed through the share.
The directory contained several TLS-related files, including ca-key.pem, ca.pem, server-cert.pem, server-key.pem, and the OpenSSL configuration file. The presence of private key material inside the exported share was significant because these files could potentially be reused for service impersonation, trust abuse, or further certificate-based attacks later in the chain.
Certificate Abuse Preparation
After finding certificate material inside the exported NFS share, I copied the CA certificate and private key to my working directory for analysis. Since the CA key was exposed, I could use it to sign a new client certificate.
Next, I generated a new private key for a certificate with the common name root. This prepared the key material needed to create a client certificate.
I then created a certificate signing request using the generated private key and set the subject to CN=root.
Finally, I signed the request using the exposed CA certificate and CA private key from the NFS share.
The output confirmed that the certificate request was signed successfully for CN=root. This meant I now had a forged certificate trusted by the exposed CA, which could potentially be used to authenticate to services that trusted this certificate authority.
Docker Port Forwarding
After generating a trusted client certificate, I needed a way to reach the Docker API that appeared to be listening locally on the target. Since the service was bound to 127.0.0.1:2376, I created an SSH local port forward through the svc account.
I authenticated with the recovered svc password, and the SSH session opened successfully on the web host. This kept a tunnel active from my local machine to the target’s local Docker TLS port.
With the tunnel running, any connection I made to 127.0.0.1:2376 on my Kali machine would be forwarded to 127.0.0.1:2376 on the target. This prepared the next step, where I could test Docker API access using the forged certificate material.
Docker Client Setup
After forwarding the target’s local Docker TLS port to my machine, I needed a Docker client locally so I could interact with the remote Docker API through the tunnel. I first updated my Kali package lists.
Next, I installed the Docker package. During installation, Kali removed podman-docker and installed the required Docker components such as containerd, runc, docker-cli, and docker.io.
After the installation completed, I verified that the Docker client was available and checked the installed version.
The output confirmed that Docker was installed successfully.
Finally, I confirmed the Docker binary path to make sure the correct client was being used.
The binary was located at /usr/bin/docker, meaning my Kali machine was ready to connect to the forwarded Docker API using the certificate material recovered from the NFS share.
Docker API Enumeration
With the SSH tunnel active and the Docker client installed, I tested access to the remote Docker API using the forged client certificate signed by the exposed CA. I pointed Docker to my local forwarded port 127.0.0.1:2376 and supplied the CA, client certificate, and private key.
The command succeeded and listed running containers on the target, confirming that the forged certificate was trusted by the Docker daemon.
The output showed several important containers, including pwm, pgadmin4, web, postgres, and gitea. This confirmed full Docker API visibility and gave me a new attack path through container management.
At this stage, I could enumerate container details, inspect mounts, and potentially start a privileged container or access host-mounted paths depending on the Docker daemon permissions.
PWM Container Enumeration
After confirming Docker API access, I entered the pwm container to inspect its configuration files directly. Since this container was responsible for the PWM web application, I focused on PwmConfiguration.xml for LDAP-related settings.
Inside the container, I searched the PWM configuration for LDAP references to understand how the application communicated with Active Directory.
The output showed that PWM was configured to use LDAPS against the domain controller at ldaps://dc01.fries.htb:636. This confirmed that the application communicated directly with Active Directory over a secure LDAP channel.
More importantly, the configuration referenced an LDAP user object with the base CN=svc_infra,CN=Users,DC=fries,DC=htb. This suggested that svc_infra was likely the LDAP proxy or service account used by PWM.
At this stage, I identified a valuable service account target inside the PWM configuration. Since the application relied on LDAP authentication, my next focus was to inspect how the LDAP proxy credentials were stored or whether the LDAP connection could be abused to capture or relay authentication material.
LDAP Credential Capture
After identifying that PWM was configured to authenticate against LDAP, I located the main configuration file inside the container. I then modified the LDAP server URL so the application would attempt to connect back to my Kali machine instead of the real domain controller.
To confirm the change, I searched the configuration again and verified that the LDAP URL now pointed to my attacker IP on port 389.
The updated configuration showed the new LDAP endpoint as ldap://10.10.15.182:389, while still referencing the service account CN=svc_infra,CN=Users,DC=fries,DC=htb.
I also checked the running processes and confirmed that the PWM Java process was active, meaning the application could trigger a new LDAP connection using the modified configuration.
On my Kali machine, I started Responder on the VPN interface to listen for incoming LDAP authentication attempts.
Responder started successfully with the LDAP server enabled and listened on tun0. Shortly after the PWM application attempted to authenticate, Responder captured the LDAP bind credentials for the svc_infra account.
This confirmed that redirecting the PWM LDAP configuration forced the application to send its stored LDAP proxy credentials to my listener. With the svc_infra password recovered, I now had a new domain service account to test against Active Directory services.
LDAP Credential Validation
After capturing the svc_infra LDAP credentials from Responder, I validated them directly against the domain controller. I used netexec over LDAP to confirm whether the account could authenticate to Active Directory.
The output confirmed that the target was DC01 in the fries.htb domain and that LDAP signing was not enforced. More importantly, the login succeeded as fries.htb\svc_infra, proving that the captured password was valid.
At this point, I had a working domain service account. This gave me a new authenticated path for Active Directory enumeration and potential privilege escalation.
Active Directory Enumeration
After validating the svc_infra credentials, I used BloodHound CE collection to enumerate the Active Directory environment. I collected all available data and compressed the output into a zip file for import into BloodHound.
The tool identified the fries.htb domain and successfully authenticated using NTLM after Kerberos failed due to routing issues. It then connected to LDAP and collected domain objects.
The output showed 19 users, 54 groups, 2 computers, 2 GPOs, and 2 OUs, giving me enough data to map privilege relationships.
Although the web hostname failed to resolve during computer enumeration, the collection still completed successfully. I now had a BloodHound zip file ready for graph analysis and privilege escalation path discovery.
Active Directory Enumeration
After importing the BloodHound data, I searched for SVC_INFRA@FRIES.HTB to understand what privileges this account had inside the domain. The graph showed that svc_infra was a normal domain user, but it also had a direct permission path to the managed service account GMSA_CA_PROD$.
This ReadGMSAPassword edge was important because it meant svc_infra could retrieve the managed password for the GMSA_CA_PROD$ account. In a CTF attack path, this usually indicates a privilege escalation opportunity, since the gMSA account may have stronger permissions than the current user.
I confirmed the relationship using BloodHound path finding between SVC_INFRA@FRIES.HTB and GMSA_CA_PROD$@FRIES.HTB. This gave me a clear next step: extract the gMSA password material and continue enumeration as the managed service account.
Active Directory Enumeration
After BloodHound showed that svc_infra had ReadGMSAPassword over GMSA_CA_PROD$, I used bloodyAD to query the managed service account directly. This allowed me to retrieve the msDS-ManagedPassword attribute from Active Directory.
The output confirmed access to the gMSA object and returned the managed password material.
This was a key privilege escalation step because I now had the NTLM hash for GMSA_CA_PROD$. With this hash, I could authenticate as the managed service account and continue enumerating for higher-privileged paths.
Active Directory Enumeration
After extracting the NTLM hash for GMSA_CA_PROD$, I tested it against WinRM to see if the managed service account had remote access to the domain controller. I used Evil-WinRM with pass-the-hash authentication instead of needing the plaintext password.
The connection was established successfully and dropped me into a PowerShell session on the target.
This confirmed that the gMSA account could authenticate over WinRM. At this stage, I had interactive access to the Windows host as gMSA_CA_PROD$, giving me a stronger foothold for further domain enumeration and privilege escalation.
Active Directory Enumeration
After gaining access as GMSA_CA_PROD$, I moved into AD CS enumeration to check for vulnerable certificate templates. I used Certipy with the gMSA NTLM hash to authenticate against the domain controller.
Certipy discovered the certificate authority fries-DC01-CA, found 33 certificate templates, and identified 11 enabled templates.
The tool also retrieved the CA configuration successfully and saved the results for offline review.
This confirmed that AD CS was present in the environment. The generated Certipy output files became the next target for reviewing possible certificate-based privilege escalation paths.
Active Directory Enumeration
After reviewing the Certipy output, I identified multiple AD CS misconfigurations, including ESC7, ESC6, and ESC16. Since the environment allowed certificate abuse, I attempted to request a certificate while specifying the Administrator UPN and SID.
The request completed successfully and Certipy returned request ID 42. However, the issued certificate still mapped back to svc_infra, not Administrator.
This showed that the first certificate request did not impersonate Administrator as intended. Instead, it generated a valid certificate for svc_infra, meaning I needed to adjust the AD CS abuse path before attempting privilege escalation again.
AD CS Certificate Request
After the first certificate request saved the output as svc_infra.pfx, I repeated the request and specified the output name as administrator. The goal was to keep the generated certificate file clearly labeled for the intended impersonation attempt.
The request succeeded and Certipy saved the certificate and private key to administrator.pfx.
However, the issued certificate still showed the UPN and SID of svc_infra, meaning the CA did not honor the requested Administrator identity.
This confirmed that simply supplying the Administrator UPN and SID was not enough in this state. The generated administrator.pfx was only a renamed certificate for svc_infra, so I needed another AD CS abuse step to make the impersonation work properly.
Time Synchronization
Before continuing with Kerberos and certificate-based authentication, I synchronized my Kali machine’s clock with the domain controller. Time skew can cause Kerberos authentication and certificate operations to fail, so keeping the attacker machine aligned with the target was important.
The command successfully synced my system time with fries.htb at 10.129.244.72.
This confirmed that my local clock was adjusted to match the target domain environment. With the time skew fixed, I could continue testing Kerberos and AD CS authentication paths more reliably.
AD CS Authentication
After synchronizing my time with the domain controller, I tested the generated administrator.pfx certificate with Certipy authentication. I specified the Administrator username and the fries.htb domain to see how the certificate would map during PKINIT.
Certipy showed that the certificate contained the SAN UPN administrator@fries.htb, but the security extension SID still belonged to svc_infra.
Even though the certificate mapped to svc_infra for the TGT, Certipy was still able to retrieve the NT hash for administrator.
This was the key AD CS escalation result: I now had the Administrator NTLM hash. With this hash, I could authenticate as Administrator and obtain full control over the domain controller.
Administrator Access
After extracting the Administrator NTLM hash through the AD CS abuse path, I used Evil-WinRM to authenticate to the domain controller with pass-the-hash. This gave me an interactive PowerShell session as Administrator.
Once connected, I enumerated the Administrator profile and moved to the Desktop directory where the flags were stored.
Both root.txt and user.txt were present on the Administrator desktop, confirming full compromise of the machine.
The files returned the final flags, completing the box. At this point, the attack chain had progressed from web and container enumeration to AD CS abuse and full Administrator access.
Hurray!!! I got both root and user flag and with this the machine was officially pwned!
Subscribe to my YouTube channel and Follow me on: LinkedIn | Medium | Twitter | Boltech Twitter | Buy Me a Coffee. Found this walkthrough helpful? Buying me a coffee helps power the late nights spent writing technical walkthroughs and keeping them free for everyone ☕
Keywords:
Fries HTB Machine Write Up Season 10 Hack the Box
fries.htb machine
fries hackthebox machine solution
fries hack the box walkthrough
Fries HTB Walkthrough
fries machine complete htb solution pdf
Fries Hack the Box Write Up
Eloquia HTB Write Up
eloquia.htb machine season 10 hack the box solution
Eloquia HackTheBox WriteUp
Eloquia Hack the Box Walkthrough
Eloquia Hack the Box Write Up
helix.htb machine Hack the Box season 10 solution
Helix Hack the Box Walkthrough
Helix Hack the Box Write Up
Helix HTB Write Up
Silentium HTB Write Up
Silentium HTB Walkthrough
Silentium Hack the Box Walkthrough
Silentium HackTheBox Season 10 Machine
silentium.htb season 10 hack the box complete walkthrough
ping.htb pong.htb season 10 writeup
pingpong htb write up
Helix Machine Season 10 Write Up
HackTheBox Helix Machine Season 10 Walkthrough
Pterodactyl Hack the Box Write Up
Pterodactyl Hack the Box Walkthrough
pterodactyl.htb machine season 10 hackthebox machine solution
Pterodactyl HackTheBox Season 10 Writeup
SmartHire HTB Write Up
smarthire.htb machine season 10 HackTheBox
smarthire hack the box write up
smarthire hack the box walkthrough
SmartHire HTB Walkthrough
Hercules HTB Write Up
Hercules HTB Walkthrough
nanocorp.htb machine season 10 hack the box
Helix HTB Machine User & Root Flag












































































1 Comments
To current members, the password to access this encrypted page and other pages has been sent to your email address. If you haven't received it yet, reach out to me at isiaqibrahim.tr@gmail.com
ReplyDeleteNote: This write up includes the complete code blocks and commands. The password for each write up is different. I have sent the password to your inbox on Buy Me A Coffee.
Happy Hacking!!!😈