Principal Writeup - HackTheBox
Last updated May 10, 2026 • 3 min read
Discovery
Port Scan
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.14 8080/tcp open http-proxy Jetty | http-title: Principal Internal Platform - Login |_http-server-header: Jetty | X-Powered-By: pac4j-jwt/6.0.3
Port 8080 runs a Java web application on Jetty. The X-Powered-By header immediately discloses the authentication framework and version: pac4j-jwt/6.0.3.
Initial Access
CVE-2026-29000 — pac4j-jwt JWE PlainJWT Authentication Bypass
CVE-2026-29000 affects pac4j-jwt versions before 4.5.9/5.7.9/6.3.3. When the server is configured to accept both JWE-encrypted and JWS-signed tokens, an attacker can wrap an unsigned PlainJWT inside a JWE envelope using only the server's RSA public key. The JWE layer decrypts successfully, but the inner PlainJWT bypasses signature verification entirely — allowing token forgery with no private key required.
The server exposes its public key at the JWKS endpoint:
The exploit fetches the JWKS, wraps an arbitrary PlainJWT claiming admin / ROLE_ADMIN inside JWE, and presents it as a bearer token.
Notice
One important detail: the JWT timestamp validation checks clock skew. Synchronise the local clock to the server's time before running the exploit:
Then run the exploit:
[*] Fetching JWKS from http://$TARGET_IP:8080/api/auth/jwks... [+] Found RSA public key (kid: enc-key-1) [*] Crafted PlainJWT for 'admin' with role 'ROLE_ADMIN' [+] Forged JWE token successfully [+] Final Token: eyJhbGci... [*] Accessing http://$TARGET_IP:8080/api/dashboard... [+] Success! Status: 200 [+] Authenticated as: admin (ROLE_ADMIN)
Set the token in an environment variable for subsequent requests:
API Enumeration
With admin access, enumerate available endpoints. The /api/users endpoint reveals a service account:
{
"username": "svc-deploy",
"note": "Service account for automated deployments via SSH certificate auth.",
"role": "deployer"
}
The /api/settings endpoint leaks a credential in plaintext:
{
"security": {
"encryptionKey": "$SVC_DEPLOY_PASSWORD",
"sshCaPath": "/opt/principal/ssh/"
}
}
SSH as svc-deploy
The encryptionKey value is reused as the SSH password for svc-deploy. Confirm with hydra across all enumerated users:
[22][ssh] host: $TARGET_IP login: svc-deploy password: $SVC_DEPLOY_PASSWORD
Privilege Escalation
SSH CA Key Theft
The svc-deploy user belongs to the deployers group. Enumerate files accessible to this group:
/etc/ssh/sshd_config.d/60-principal.conf /opt/principal/ssh /opt/principal/ssh/README.txt /opt/principal/ssh/ca
The SSH daemon configuration confirms certificate-based authentication is active:
TrustedUserCAKeys /opt/principal/ssh/ca.pub
The CA private key at /opt/principal/ssh/ca is readable by svc-deploy. Copy it to the attacker machine:
Forging an SSH Certificate for root
With the CA private key, generate a new keypair and sign it as root:
Signed user key root_cert-cert.pub: id "root" serial 0 for root valid forever
SSH in as root using the signed certificate:
root@principal:~#
Root shell.
References
-
exploit-intel.comexploit-intel.com/vuln/CVE-2026-29000 (opens in new tab)
CVE-2026-29000 pac4j-jwt JWE PlainJWT authentication bypass
-
NVD, CVE-2026-29000
-
www.pac4j.orgwww.pac4j.org (opens in new tab)
pac4j security framework documentation
-
man.openbsd.orgman.openbsd.org/ssh-keygen.1 (opens in new tab)
OpenSSH ssh-keygen, certificate signing reference