summaryrefslogtreecommitdiffstats
path: root/piolium/attack-surface/spec-gap-summary.md
diff options
context:
space:
mode:
Diffstat (limited to 'piolium/attack-surface/spec-gap-summary.md')
-rw-r--r--piolium/attack-surface/spec-gap-summary.md164
1 files changed, 164 insertions, 0 deletions
diff --git a/piolium/attack-surface/spec-gap-summary.md b/piolium/attack-surface/spec-gap-summary.md
new file mode 100644
index 0000000..5e52e81
--- /dev/null
+++ b/piolium/attack-surface/spec-gap-summary.md
@@ -0,0 +1,164 @@
1# P7 Spec, Framework Contract & Parser Gap Summary
2
3**Target:** salmon/minecraft-ui
4**Date:** 2025-07-29
5**Phase:** P7 — Specification, Framework Contract & Parser Differential Analysis
6**Mode:** deep
7
8---
9
10## Overview
11
12This report documents gaps between authoritative specifications, framework contracts, and the codebase implementation for salmon/minecraft-ui. The analysis covers:
13
14- **RFC 9106** (Argon2) — password hashing parameter compliance
15- **Java `.properties` format** (Oracle spec) — server.properties parsing
16- **Source RCON Protocol** (Minecraft community spec — wiki.vg/RCON) — packet handling
17- **RFC 6265** (HTTP State Management) — cookie parsing and session handling
18- **Axum Framework Contracts** — middleware ordering, extension-based auth, multipart boundary parsing
19- **Hidden Control Channels** — Docker environment injection, file path construction, host header trust
20- **Deployment Assumptions** — reverse proxy, localhost binding, no TLS
21
22---
23
24## Spec Gap Candidates
25
26### Gap 1: Java `.properties` — Missing Escape Sequence Processing
27
28- **Spec:** Oracle Java `.properties` file format
29- **Requirement:** The format specifies escape sequences: `\n`, `\r`, `\t`, `\\`, `\uXXXX`, `\ ` (literal space), `\!`, `\#`, `\=`, `\:`, and multi-line continuation with trailing `\`.
30- **Code Path:** `src/properties.rs:13-19` — `read_properties()` splits on `=` or `:` without escaping
31- **Gap Type:** parsing | canonicalization
32- **Impact:** Values containing `=`, `:`, or Java escape sequences in `server.properties` are misparsed. An attacker who can control `server.properties` values (e.g., via `level-seed` setting) can inject fake key-value pairs or corrupt parsing. The `level-seed` value in `server.properties` is written by `regenerate_world` via a line-replacement loop that creates `level-seed={seed}` — the seed value is not escaped for the `.properties` format.
33- **Attack Vector:** Auth'd user sets a seed containing `\nlevel-type=FLAT\n` which, when written to `server.properties` via the naive line-replacement in `regenerate_world`, injects additional properties. On next server start, the injected properties alter server behavior.
34- **Exploit Conditions:** Auth'd user; instance not active; access to `regenerate_world` handler.
35- **Severity:** MEDIUM
36- **Evidence:** `src/properties.rs:13-19` uses `split_once('=')` and `split_once(':')` with no escape processing. Java `.properties` spec requires backslash escaping for separators.
37
38### Gap 2: Argon2id (RFC 9106) — Non-Recommended Default Parameters
39
40- **RFC/Spec:** RFC 9106, Sections 3.1, 4, 7.4
41- **Requirement:** RFC 9106 §4 recommends as FIRST option: `Argon2id` with `t=1`, `p=4`, `m=2^21` (2 GiB). §7.4 states "Argon2id variant with t=1 and 2 GiB memory is the FIRST RECOMMENDED option". Salt SHOULD be 16 bytes and SHOULD be unique per password.
42- **Code Path:** `src/auth.rs:28` — `Argon2::default().hash_password(password.as_bytes(), &salt)?`
43- **Gap Type:** missing-check | parameter-choice
44- **Impact:** `Argon2::default()` uses m_cost=19456 KiB (~19 MiB), t_cost=2 iterations, p_cost=1 lane. This is ~100x less memory than RFC 9106 recommends. While not a compliance vulnerability (any parameters are valid per the algorithm spec), the weak defaults reduce brute-force attack resistance relative to the RFC's recommended "default setting for all environments."
45- **Attack Vector:** Offline password hash cracking benefits from the 19 MiB vs 2 GiB memory reduction (~100x cheaper per guess).
46- **Exploit Conditions:** Attacker obtains password hash from database (SQLite file access or SQL injection).
47- **Impact:** Accelerated offline brute-force by ~100x less memory per hash evaluation.
48- **Severity:** MEDIUM
49- **Evidence:** `src/auth.rs:28` uses `Argon2::default()` (m=19456 KiB, t=2, p=1). RFC 9106 §4 recommends m=2^21 KiB (2 GiB), t=1, p=4 for pass hashing. Source: `/home/salmon/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/argon2-0.5.3/src/params.rs:29` defines DEFAULT_M_COST = 19 * 1024.
50
51### Gap 3: RCON Protocol — Insufficient Response Read After EXECCOMMAND
52
53- **Spec:** Source RCON Protocol (Minecraft community convention — wiki.vg/RCON)
54- **Requirement:** After sending `SERVERDATA_EXECCOMMAND` (type 2), the server responds with a `SERVERDATA_RESPONSE_VALUE` (type 0) packet containing the command output, followed by a second `SERVERDATA_RESPONSE_VALUE` (type 0) as an end marker. Multi-packet responses are possible.
55- **Code Path:** `src/rcon.rs:72-76` — reads one response, then ignores errors on second
56- **Gap Type:** state-machine | error-handling
57- **Impact:** Reads only one guaranteed response. Fragmented multi-packet responses are truncated. The comment acknowledges this: "some servers send it, some don't; ignore errors."
58- **Attack Vector:** Long RCON command output (> 1400 bytes) gets truncated.
59- **Exploit Conditions:** Any RCON command with output exceeding ~1400 bytes.
60- **Impact:** Truncated command response (information disclosure).
61- **Severity:** LOW — protocol compliance only, no direct security bypass.
62- **Evidence:** `src/rcon.rs:72` — `let response = self.read_packet(&mut stream)?;` followed by `let _ = self.read_packet(&mut stream);` with error ignored.
63
64### Gap 4: Java `.properties` — Key Continuation and Whitespace Separator Not Supported
65
66- **Spec:** Oracle Java `.properties` format
67- **Code Path:** `src/properties.rs:13-19`
68- **Gap Type:** parsing
69- **Impact:** Lines with whitespace-only separators (e.g., `key value`) are silently ignored.
70- **Severity:** LOW — informational; conventional Minecraft server.properties uses `=`.
71
72### Gap 5: Auth Middleware — Manual Cookie Parsing (RFC 6265)
73
74- **RFC/Spec:** RFC 6265 (HTTP State Management), Sections 4.2.2, 5
75- **Code Path:** `src/auth.rs:105-118` — manual `split(';')` then `split_once('=')`
76- **Gap Type:** parsing | canonicalization
77- **Impact:** The parser does NOT strip OWS around cookie names per RFC 6265 §4.2.2. Does NOT handle quoted cookie values.
78- **Severity:** LOW — well-formed browser cookies not affected; no auth bypass possible.
79
80### Gap 6: Framework Contract — Logout Without Auth Middleware
81
82- **Contract:** Axum middleware; all state-changing ops require auth.
83- **Code Path:** `src/routes/mod.rs:29` — `/logout` on outer router, not in `protected` group.
84- **Gap Type:** middleware-ordering
85- **Impact:** Anonymous requests can delete sessions (requires valid session ID — UUIDv4 impractical).
86- **Severity:** LOW — theoretical; UUIDv4 unpredictability prevents exploitation.
87
88### Gap 7: Framework Contract — No Server-Side Session TTL Enforcement
89
90- **Contract:** Session cookie Max-Age=86400 but no server-side expiration check.
91- **Code Path:** `src/auth.rs:93` — `Max-Age=86400`; `src/auth.rs:108-115` — no `created_at` check.
92- **Gap Type:** missing-check
93- **Impact:** Session rows remain valid indefinitely in DB. Stolen session ID (via XSS, log access, DB leak) works forever.
94- **Attack Vector:** Session ID leak → permanent session hijacking. No server-side TTL means an attacker who obtains a session ID can reuse it indefinitely, long after the Max-Age expires.
95- **Exploit Conditions:** Attacker must first obtain a valid session ID.
96- **Impact:** Session hijacking window extended indefinitely.
97- **Severity:** MEDIUM
98- **Evidence:** `src/auth.rs:93` sets `Max-Age=86400` but `src/auth.rs:108-115` does `WHERE s.id = ?1` with no date filter.
99
100### Gap 8: Hidden Control Channel — Instance MOTD Injected Into Docker Env Without Sanitization
101
102- **Contract:** Docker env vars derived from instance settings; Docker env parsing splits on `\n`.
103- **Code Path:** `src/docker.rs:103` — `format!("MOTD={}", instance.motd)`
104- **Gap Type:** hidden-control-channel | missing-check
105- **Impact:** MOTD containing newline characters (`%0a`) injects arbitrary additional env vars into the Docker container. For example, MOTD=`hello\nEULA=FALSE\nONLINE_MODE=true` would override security-critical env vars. All Docker env vars (VERSION, TYPE, MEMORY, MAX_PLAYERS, DIFFICULTY, RCON_PASSWORD, GAMEMODE, LEVEL_TYPE, LEVEL_SEED, PVP, MOTD) are set without sanitization.
106- **Attack Vector:** Auth'd user edits instance MOTD → saves → triggers container restart → injected env vars alter Docker container behavior.
107- **Exploit Conditions:** Auth'd user; container restarted after instance edit.
108- **Impact:** Full Docker container environment variable injection — could override EULA, ONLINE_MODE, RCON settings, or inject arbitrary env vars.
109- **Severity:** HIGH
110- **Evidence:** `src/docker.rs:103` — `format!("MOTD={}", instance.motd)`. No escaping. MOTD sourced from `src/routes/instances.rs:206` via `Form<EditInstanceForm>` without sanitization.
111
112### Gap 9: Hidden Control Channel — Instance Name Used in File Paths Without Sanitization
113
114- **Contract:** Instance name → filesystem path.
115- **Code Path:** `src/routes/instances.rs:173` — `server_directory.join("instances").join(&form.name)`
116- **Gap Type:** hidden-control-channel | missing-check
117- **Impact:** `std::path::Path::join` DOES traverse on `..` prefix. Instance name `../../evil` results in path outside intended tree. All subsequent operations (mod uploads, world import, backups) land at attacker-chosen locations. Files created: instance data directory, mod JAR files, world files.
118- **Attack Vector:** Auth'd user creates instance with `../../evil_name` → data dir created at `server_directory/instances/../../evil_name/data` = `server_directory/evil_name/data`. Then upload mod or import world to write files at traversed location.
119- **Exploit Conditions:** Auth'd user.
120- **Impact:** Arbitrary file write relative to server_directory (WebUI process user permissions).
121- **Severity:** HIGH
122- **Evidence:** `src/routes/instances.rs:173` — `let instance_dir = state.config.server_directory.join("instances").join(&form.name).join("data");` No validation of `form.name` for `..` or path separators. Also stored in DB at `src/routes/instances.rs:119` without sanitization.
123
124### Gap 10: Hidden Control Channel — Content-Type Boundary Parsing Trusts Attacker Input
125
126- **Contract:** Multer multipart parser; boundary from Content-Type header.
127- **Code Path:** `src/routes/mods.rs:140-149` — boundary parsed without validation
128- **Gap Type:** hidden-control-channel | missing-check
129- **Impact:** Attacker-controlled boundary value fed to `multer::Multipart::with_constraints`. While multer validates boundaries internally, a crafted boundary could cause field misidentification, size limit bypass, or field-skipping behavior.
130- **Attack Vector:** Send crafted Content-Type header with boundary overlapping body content: malformed multipart parsing.
131- **Exploit Conditions:** Auth'd user uploading mods.
132- **Impact:** Potential DoS or file size limit bypass.
133- **Severity:** MEDIUM
134- **Evidence:** `src/routes/mods.rs:141-148` — boundary parsed from user-supplied `Content-Type`.
135
136### Gap 11: Hidden Control Channel — All Instance Settings In Docker Env Without Sanitization
137
138- **Contract:** All instance settings → Docker env.
139- **Code Path:** `src/docker.rs:87-113`
140- **Gap Type:** hidden-control-channel | missing-check
141- **Impact:** Beyond MOTD (Gap 8), LEVEL_SEED, LEVEL_TYPE, GAMEMODE, DIFFICULTY, VERSION, RCON_PASSWORD are all injected without sanitization.
142- **Severity:** HIGH — combined with Gap 8.
143
144### Gap 12: Framework Contract — RCON Password Exposed to All Authenticated Users
145
146- **Contract:** Supposed role-based access control for sensitive instance data.
147- **Code Path:** `src/routes/instances.rs:313` — `rcon_password: row.get(15)?` in `edit_form`
148- **Gap Type:** missing-check
149- **Impact:** Any authenticated user can view any instance's RCON password by visiting `/instances/{id}/edit`. No superuser or instance-ownership check. RCON password grants full Minecraft server control.
150- **Attack Vector:** Auth'd user navigates to `/instances/1/edit` → sees RCON password → uses RCON client to issue arbitrary commands.
151- **Exploit Conditions:** Auth'd user.
152- **Impact:** Full Minecraft server compromise via RCON — whitelist bypass, data destruction, command execution.
153- **Severity:** HIGH
154- **Evidence:** `src/routes/instances.rs:313` — `rcon_password` selected and returned. No superuser check. Compare with `src/routes/accounts.rs:35` where checks exist.
155
156---
157
158## Cross-Reference with Phase 3 Domain Attack Research
159
160- **Gap 8/11** (Docker env injection) — NOT covered in Phase 3. New finding.
161- **Gap 9** (Instance name path traversal) — NOT specifically covered. Phase 3 identified mod filename traversal (T2) but not instance name as traversal vector.
162- **Gap 12** (RCON password exposure) — Covered in Phase 3 as T5.
163- **Gap 7** (No session TTL) — Covered in Phase 3 domain research.
164- **Gap 2** (Argon2 defaults) — NOT covered in Phase 3.