Machine / Machines

HTB Fries — Complete Walkthrough (Hard/Windows)

The provided <email redacted> / D4LE11maan!! credentials worked on pgAdmin (form-encoded POST to /authenticate/login). pgAdmin 9.1.0 is vulnerable to Python eval() injection in the query tool download endpoint. Exploitation flow: 1. Login → get CSRF

HardPublished 2026-02-10Sanitized local writeup

Scenario

HTB Fries — Complete Walkthrough (Hard/Windows) attack path

The provided / D4LE11maan!! credentials worked on pgAdmin (form-encoded POST to /authenticate/login). pgAdmin 9.1.0 is vulnerable to Python eval() injection in the query tool download endpoint. Exploitation flow: 1. Login → get CSRF

Objective

Machine walkthrough focused on Machines evidence, validation, and reusable operator lessons.

HTB Fries — Complete Walkthrough (Hard/Windows) sanitized attack graph

Walkthrough flow

01

Phase 2: Initial Foothold — pgAdmin

02

Phase 3: Credential Discovery via Gitea

03

Phase 4: SSH to Docker Host

04

Phase 5: NFS GID Spoofing → Docker TLS Certs

05

Phase 6: Docker TLS → PWM Config

Source coverage

High source coverage

Status: complete. This article is generated from 7 sanitized Markdown sources and keeps raw flags, credentials, keys, cookies, and reusable secrets out of the rendered blog.

100% coverage
Evidence verdict

High confidence: the page is reconstructed from a primary walkthrough plus multiple supporting notes or evidence sources. Treat the chain as source-backed, while still checking the listed source files for sensitive values.

  • <TARGET>-Fries/walkthrough.md
  • HTB/<TARGET>-Fries/notes.md
  • HTB/<TARGET>-Fries/attack-map.md
  • HTB/<TARGET>-Fries/session-resume.md
  • HTB/<TARGET>-Fries/custom-exploit-notes.md
  • HTB/<TARGET>-Fries/dead-ends.md
  • HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/machine__<TARGET>-Fries__notes.md.b02a6e77f5.md

Technical Walkthrough

HTB Fries — Complete Walkthrough (Hard/Windows)

Machine Info

  • Name: Fries
  • Difficulty: Hard
  • OS: Windows (DC) + Linux (Docker Host)
  • IP: <TARGET>
  • Domain: fries.htb
  • Creators: ruycr4ft, kavigihan
  • Date: 2026-05-10

Flags

  • User: <hash redacted>/root/user.txt on Linux Docker host
  • Root: <hash redacted>C:\Users\Administrator\Desktop\root.txt on DC01

Phase 2: Initial Foothold — pgAdmin <secret redacted>

pgAdmin Authentication

The provided <email redacted> / D4LE11maan!! credentials worked on pgAdmin (form-encoded POST to /authenticate/login).

<secret redacted>: Authenticated RCE

pgAdmin 9.1.0 is vulnerable to Python eval() injection in the query tool download endpoint.

Exploitation flow:

  1. Login → get CSRF token
  2. Register attacker-controlled PostgreSQL server (Pwnbox)
  3. Connect pgAdmin to it
  4. Initialize SQL editor session (/sqleditor/initialize/sqleditor/{trans_id}/{sgid}/{sid}/{did})
  5. Execute any SQL query via /sqleditor/query_tool/start/{trans_id}
  6. Exploit: POST to /sqleditor/query_tool/download/{trans_id} with query_commited containing Python code

Key finding: eval() executes but the download endpoint discards the return value and serves cached SQL results. Blind RCE confirmed via reverse shell callback.

Shell on pgAdmin Container

  • uid=5050(pgadmin) gid=0(root) at <TARGET>

Phase 3: Credential Discovery via Gitea

Gitea Access

dale / D4LE11maan!! authenticated to Gitea. Found private repo dale/fries.htb.

Git History Secret Leak

Commit 3e8ca66 ("gitignore update") deleted .env which was present in initial commit be59cce:

text
<secret redacted>=postgresql://root:PsqLR00tpaSS11@<TARGET>:5432/ps_db

Lesson: Always check git history for removed sensitive files. .gitignore addition ≠ secret removal from history.

Phase 4: SSH to Docker Host

Password Reuse

<secret redacted>=<redacted> (from pgAdmin container env) worked for SSH:

text
ssh svc@<TARGET>  # password: <redacted>

Host Identity

  • Hostname: web
  • IP: <TARGET> (proxy) + <TARGET> (Docker bridge gateway)
  • Docker host running all containers

Phase 5: NFS GID Spoofing → Docker TLS Certs

NFS Export Discovery

text
/srv/web.fries.htb *(rw,no_subtree_check,insecure)

Contains certs/ directory restricted to GID 59605603 (infra managers — AD group).

Python NFS Client with GID Spoofing

Wrote a raw Python NFS v3 client (using socket + struct) that:

  1. Connects to mountd (port 52995) with <secret redacted> spoofing GID=59605603
  2. MOUNTs the export to get root filehandle
  3. LOOKUPs certs/ directory
  4. READs all certificate files

Extracted: ca.pem, ca-key.pem, server-cert.pem, server-key.pem

Lesson: NFS <secret redacted> trusts whatever UID/GID the client claims. With no_subtree_check and insecure, any client can spoof credentials. Root squash only blocks UID 0, not arbitrary GID spoofing.

Phase 6: Docker TLS → PWM Config

Authz-Broker Policy

/var/lib/authz-broker/policy.json:

  • CN=fries → no policy (denied)
  • CN=svc → container_list, container_logs
  • CN=sysadm → container (readonly)
  • CN=root → all

Client Certificate Generation

Used the CA key to sign custom certs:

  1. CN=sysadm → listed containers
  2. CN=root → full Docker access (exec, cp, run)

LDAP Passback Attack

  1. Modified PWM's LDAP URL from ldaps://dc01.fries.htb:636 to ldap://<TARGET>:9389
  2. Started nc listener on port 9389 (on host as svc)
  3. Triggered PWM login from localhost:8443
  4. Captured plaintext LDAP bind: svc_infra / m6tneOMAh5p0wQ0d

Phase 7: AD Exploitation

gMSA Password Read

text
crackmapexec ldap <TARGET> -u svc_infra -p m6tneOMAh5p0wQ0d --gmsa
→ gMSA_CA_prod$  NTLM: <hash redacted>

User Flag

Used Docker (CN=root cert) to mount host filesystem and read /root/user.txt.

ADCS ESC6 + LDAPS Authentication

  1. Enabled <secret redacted> via ICertAdminD2 DCOM (ManageCA right)
  2. Requested certificate as svc_infra with User template + UPN=<email redacted>
  3. Authenticated via LDAPS (Schannel bypasses SID-based strong mapping check)
  4. Added svc_infra to Domain Admins via LDAP shell
  5. Read root.txt via wmiexec as Domain Admin

Dead Ends & Failures

AttemptResultLesson
Brute-force PWM config password (~35 attempts)All failed, lockout triggeredDon't guess; find the credential through the intended path
Tomcat ..;/ path traversalBlocked by PWM security filterModern PWM validates path segments
d.cooper password against ADWrong by designHTB provides creds for non-AD services
Docker container breakout (PG/pgAdmin)No caps, no socket, seccomp=2Containers were properly hardened
Gitea admin Git hooksBlocked by app.ini <secret redacted>=falseDB changes don't override app config
certutil -setreg for ESC6Requires local admin elevationUse DCOM ICertAdmin2 interface instead
Kerberos auth with forged certSID mismatch (strong mapping)Use LDAPS/Schannel which bypasses SID check
DCSync as WEB$ machine account<secret redacted>Machine account lacks replication rights

Tools Used

  • nmap, ffuf, gobuster, crackmapexec, certipy, impacket suite
  • Custom Python: NFS GID spoof client, <secret redacted> exploit, DCOM ESC6 enabler
  • evil-winrm, hashcat, netcat

Source-Backed Dossier

The sections below are merged from companion Markdown notes for the same case. They are rendered after sanitization so the article stays precise without publishing raw flags, credentials, or target-specific secrets.

Notes

Scope

  • Target: <TARGET>
  • Domain: fries.htb
  • OS: Windows (AD likely)
  • Difficulty: Hard
  • Creators: ruycr4ft, kavigihan

Connection

  • Pwnbox: <TARGET> (profex0r)
  • Credentials: see loot/credentials.md

Evidence Ledger

TimestampCommandOutput FileFindingConfidenceNext
2026-05-10vhost fuzzingenum/vhosts-*Found db-mgmt05.fries.htb and code.fries.htbHighTest web credentials
2026-05-10pgAdmin login + <secret redacted>exploits/cve_2025_2945.pyAuthenticated RCE achieved as pgadmin in containerHighEnumerate pgAdmin/Gitea/Postgres secrets

Attack Map

Network Topology (Two-Host Model)

text
[Pwnbox <TARGET>] --VPN--> [<TARGET>]
                                    |
                    +---------------+---------------+
                    |                               |
          [Linux Proxy <TARGET>]    [DC01 <TARGET>]
          - Ubuntu 22.04                 - Windows Server 2019
          - nginx 1.18.0                 - Domain: fries.htb
          - Flask (port 80)              - Kerberos, LDAP, SMB
          - Tomcat 9.0.99 (port 443)     - DNS, WinRM, ADWS
          - SSH (port 22)                - SMB signing required
          - PWM app (config mode)        - Guest disabled
          - pgAdmin 9.1.0
          - Gitea 1.22.6

Service Map

PortServiceHostNotes
22SSH (OpenSSH 8.9p1 Ubuntu)ProxyPassword auth enabled
2049NFSProxyPublic research suggests /srv/web.fries.htb export; validate live
53DNS (Simple DNS Plus)DC01Zone transfer denied
80HTTP (nginx→Flask)ProxyStatic restaurant site (/about, /menu only)
88KerberosDC01Standard
135/445SMBDC01Signing required, null auth ok but no share access
389/636LDAP/LDAPSDC01Requires bind, rootDSE accessible
443HTTPS (nginx→Tomcat/PWM)ProxyPWM in open configuration mode
464kpasswdDC01Standard
5985WinRMDC01Requires auth
9389ADWSDC01Standard

Web Vhosts

VhostAppResult
db-mgmt05.fries.htbpgAdmin 9.1.0Authenticated RCE via <secret redacted>; shell as pgadmin in container
code.fries.htbGitea 1.22.6Valid dale session; private repo dale/fries.htb
pwm.fries.htbPWM v2.0.8Config mode; requires config unlock material
web.fries.htb / fries.htbFlask/nginxStatic public restaurant site from external view

Docker Network

IPService
<TARGET>Docker host
<TARGET>Flask :5000
<TARGET>PostgreSQL :5432, superuser + RCE
<TARGET>pgAdmin :80, RCE
<TARGET>Gitea :22, dale admin
<TARGET>PWM :8443

AD Users (Confirmed via Kerberos)

  • administrator
  • d.cooper
  • web
  • svc_infra
  • gMSA_CA_prod$ (gMSA, WinRM validated by operator)

PWM State

  • Open configuration mode (LDAP broken)
  • Config unlock material: UNKNOWN (guessing stopped per harness)
  • LDAP bind: svc_infra → ldaps://dc01.fries.htb:636
  • LDAPS failure reason: certificate mismatch (server cert subject empty, not in trust store)
  • svc_infra bind material: <secret redacted> (stored in config, TLS fails before bind tested)
  • REST API: all user-facing endpoints return 5053 (app unavailable)
  • Reference pages accessible: environment.jsp, rest.jsp, settings.jsp
  • Tomcat version: 9.0.99

Sensitive Values (see loot/credentials.md)

  • d.cooper → <secret redacted> everywhere (provided value wrong on this instance, not expired)
  • svc_infra → bind value unknown, stored in PWM config XML

Ranked Hypotheses

#HypothesisConfidenceStatus
1svc SSH using recovered pgAdmin admin valueHIGHNEXT
2NFS export access to Docker TLS cert materialHIGHAFTER SSH
3Docker TLS authz CN bypass to access Docker APIHIGHAFTER CERTS
4Docker/PWM config volume read through Docker APIHIGHAFTER API
5Extract or coerce PWM svc_infra bind materialHIGHAFTER CONFIG
6Linux/NFS/Docker host search for user.txtHIGHNEXT FOR USER
7gMSA ADCS ESC6+ESC16 direct issuanceHIGHNEXT FOR ROOT
8Certificate Manager Deny ACE removalLOWFALLBACK ONLY

Flag State

  • User flag captured from /root/user.txt on the Linux Docker host through Docker volume access as root. Raw value is stored only in loot/.
  • Root flag pending. Current root path is ADCS after gMSA WinRM; ESC7 ManageCA is confirmed, but Certificate Manager issuance is blocked by an explicit Deny ACE.

Exhausted Vectors

  • d.cooper password (35+ variants, Kerberos/NTLM/SSH)
  • PWM config brute force (~35 <password redacted>, lockout-limited)
  • Flask SSTI (no injection points)
  • Nginx alias/path traversal on port 80
  • Tomcat ..;/ bypass (caught by PWM security filter)
  • SMB/LDAP/RPC anonymous enumeration
  • Vhost/DNS subdomain brute
  • File extension fuzzing on port 80
  • RID cycling (access denied)
  • HTTP request smuggling (partial, no useful result)
  • HTTPS catch-all produces false positive 200s for all non-/pwm/ paths

Session Resume

Completion State: <secret redacted>

Current Checkpoint

  • Reset completed; current target IP is <TARGET>. Prior target IP was <TARGET>.
  • Full TCP scan complete and shows a split external surface: Ubuntu proxy services plus exposed DC services.
  • AD confirmed: DC01.fries.htb, fries.htb domain.
  • Provided d.cooper credential consistently fails across Kerberos/NTLM/SAMR before and after fresh reset. Treat it as intentionally invalid for AD/SMB/SSH, not stale machine state.
  • Vhosts discovered: db-mgmt05.fries.htb runs pgAdmin 9.1.0; code.fries.htb runs Gitea 1.22.6.
  • Provided d.cooper web credential works in pgAdmin.
  • <secret redacted> yielded authenticated RCE as pgadmin in container <TARGET>.
  • Docker network mapped: host .1, Flask .2:5000, PostgreSQL .3:5432, pgAdmin .4:80, Gitea .5:22, PWM .6:8443.
  • Gitea access obtained as dale; private repo dale/fries.htb contains Flask source.
  • Gitea commit history leaked PostgreSQL superuser DSN.
  • PostgreSQL superuser access achieved; COPY FROM PROGRAM gives RCE as the PostgreSQL service user in container <TARGET>.
  • Dale promoted to Gitea admin via database modification; only one Gitea repo was found.
  • Container breakout triage completed: no Docker socket/API, no host mounts, no useful capabilities, seccomp enforced. Gitea admin RCE is blocked by app.ini despite DB flag; Actions disabled.
  • PWM v2.0.8 remains in configuration mode; svc_infra bind value still not extracted.
  • WinRM is reachable from the container to DC, but no valid AD credential is known.
  • Update from active operator: svc_infra was recovered, gMSA gMSA_CA_prod$ was read, and WinRM to DC01 is working as the gMSA.
  • User flag captured from /root/user.txt on the Linux Docker host through Docker volume access as root. Raw flag is stored only under loot/.
  • Root path is ADCS. ESC7 ManageCA is confirmed, but Certificate Manager path is blocked by an explicit Deny ACE. Treat removal of Deny ACE as a risky fallback unless safer ManageCA paths are exhausted.

Ranked Hypotheses

#HypothesisEvidenceMissing ProofCheapest ValidationConfidenceStatus
1User flag is on Linux/NFS/Docker side, not Windows desktopsLive capture from /root/user.txt on Linux Docker hostNoneSave sanitized path and raw flag only in loot/SOLVEDDONE
2ESC6+ESC16 direct issuance avoids Certificate Manager DenygMSA has DC WinRM; ESC7 present; Deny is on Certificate Manager pathCA flags/template state and enrollable templateUse Certify/Certipy read-only enumeration, then enable ESC6/ESC16 only if ManageCA is confirmedHIGHNEXT
3Deny ACE only blocks officer/issue-request path, not ManageCA CA flag changesESC7 separates ManageCA from ManageCertificatescertipy find/Certify ACL evidenceConfirm gMSA retains ManageCA despite DenyHIGHNEXT
4SubCA/issue-request path is blocked by Certificate Manager DenyOperator reports explicit Deny ACERequest/issue error evidenceAvoid this path unless Deny can be safely removedMEDIUMHOLD
5Removing Deny ACE or changing CA security descriptor is possible but riskyManageCA may manage CA security; gMSA has DC executionWriteDACL/ManageCA proof plus rollbackOnly after snapshot/evaluator gateLOWFALLBACK

Closed Branches

  • Provided d.cooper credential — WRONG password on this instance (<secret redacted> / <secret redacted> / SAMR <secret redacted>), not expired.
  • Anonymous LDAP/SMB — access denied
  • Guest account — disabled
  • Port 80 SSTI — no injection points found
  • Vhost fuzzing — only web/pwm/dc01, no unique content
  • HTTPS catch-all — returns 200 with redirect for all paths (false positive)
  • ASREPRoast — d.cooper doesn't have <secret redacted>
  • Generic container breakout from pgAdmin/PostgreSQL — no Docker socket/API, no host mounts, no useful capabilities, seccomp enforced.
  • Gitea admin to RCE — DB flag alone is insufficient; app.ini blocks hooks and Actions are disabled.

Last RAG Tags: NONE (not queried yet)

Evaluator Decision

SPLIT <secret redacted>. For user flag, stop searching Windows desktops and search Linux/NFS/Docker host filesystem. For root, do not remove Deny ACE first. Validate whether gMSA ManageCA can enable ESC6+ESC16 and use a directly enrollable client-auth template with Administrator UPN + SID.

Blocker

User flag is captured. DC WinRM exists as gMSA, but Domain Admin/root is not achieved.

Next Checkpoint

After read-only ADCS enumeration as gMSA and validation of the safest root path.

Notes

<secret redacted> pgAdmin RCE

  • Target: db-mgmt05.fries.htb, pgAdmin 9.1.0.
  • Authenticated as d.cooper web user.
  • RCE achieved through Query Tool download endpoint.
  • Shell context: uid=5050(pgadmin), container IP <TARGET>.
  • Current exploit scripts live under exploits/; preserve working payload and exact command/output before further edits.

Post-Foothold Priorities

  1. Validate Linux host SSH as svc using the recovered pgAdmin admin value.
  2. From Linux host, validate NFS export /srv/web.fries.htb and access to Docker TLS cert material under certs/.
  3. Validate Docker TLS on localhost/gateway :2376 with read-only _ping, containers/json, and volumes.
  4. If authz blocks current cert identity, inspect policy/cert materials and generate a client cert with an allowed CN only after recording an evaluator gate.
  5. Use Docker API read-only archive/cp to extract PWM /config/PwmConfiguration.xml.
  6. Extract/decrypt/crack PWM config material or perform controlled LDAP passback to recover svc_infra.
  7. Use validated AD credentials through WinRM/LDAP to progress to user/root.

PostgreSQL RCE

  • PostgreSQL superuser DSN recovered from Gitea commit history.
  • COPY FROM PROGRAM gives command execution in PostgreSQL container <TARGET>.
  • Preserve exact SQL payloads and command outputs under enum/ or exploits/.

Docker TLS / PWM Config Research Path

  • Public Fries-specific research indicates the intended next bridge is not generic container breakout, but SSH to the Linux host as svc, NFS access to web files/certs, Docker TLS authz identity manipulation, then Docker API read of PWM /config.
  • Keep Docker interaction read-only until PWM config path is proven.

Dead Ends

Credential Guessing / Spraying

  • Provided d.cooper credential fails consistently via Kerberos, NTLM, and SAMR before and after fresh reset. Treat as intentionally wrong for AD/SMB/SSH.
  • PWM config unlock guessing stopped. Lockout behavior plus weak evidence makes this poor signal and high overhead.
  • Internal PWM unlock guessing remains low priority even after container foothold. There are higher-signal credential stores now.
  • After PostgreSQL RCE, do not test discovered web/database values against AD repeatedly. They are service-scoped unless live AD auth proves otherwise.

Anonymous Windows Enumeration

  • Anonymous LDAP/SMB/RPC did not produce share, RID, or directory access beyond basic service/domain confirmation.
  • Guest account unavailable.
  • ASREPRoast did not identify a usable no-preauth user.

HTTP / HTTPS Broad Enumeration

  • Port 80 Flask app reported static with no useful parameters or SSTI surface.
  • HTTPS catch-all creates false-positive 200s for arbitrary paths; future fuzzing must baseline length/body, not status alone.
  • Tomcat traversal attempts reportedly hit PWM security filtering; keep exact payload/output artifacts before considering this fully closed.
  • Docker API and registry probes reported unreachable; verify artifacts are mirrored before closing the Docker branch.
  • Direct PWM config-manager probing is low value: PWM v2.0.8 source shows config-manager routes require config-manager authentication in <secret redacted> mode.

Container Breakout

  • PostgreSQL and pgAdmin containers: no Docker socket/API, no host filesystem mounts, no useful Linux capabilities, seccomp enforced.
  • Gitea admin to RCE: allow_git_hook database flag alone is insufficient because app.ini blocks hooks; Actions are disabled. Revisit only if filesystem access to Gitea config or another Gitea execution primitive appears.

Notes

Scope

  • Target: <TARGET>
  • Domain: fries.htb
  • OS: Windows (AD likely)
  • Difficulty: Hard
  • Creators: ruycr4ft, kavigihan

Connection

  • Pwnbox: <TARGET> (<<secret redacted>>)
  • Credentials: see loot/credentials.md

Evidence Ledger

TimestampCommandOutput FileFindingConfidenceNext
2026-05-10vhost fuzzingenum/vhosts-*Found db-mgmt05.fries.htb and code.fries.htbHighTest web credentials
2026-05-10pgAdmin login + <secret redacted>exploits/cve_2025_2945.pyAuthenticated RCE achieved as pgadmin in containerHighEnumerate pgAdmin/Gitea/Postgres secrets