T05 · Unauthorized Access and Privilege Escalation
- Location
- music-server.py:17
- Finding
- Predictable lock file allows symlink-based file truncation and permission modification## Vulnerability Details **File Location**: `music-server.py`, lines 17 and 28-36 **Vulnerability Type**: Insecure temporary file handling and symbolic-link following **Risk Level**: High ### Vulnerable Code ```python LOCK_FILE = Path(os.environ.get("MUSIC_LOCK_FILE", "/tmp/music_player.lock")) def save_lock_file(): """Save server port to lock file""" try: with open(LOCK_FILE, 'w') as f: f.write(str(CONTROL_PORT)) os.chmod(LOCK_FILE, 0o666) # Make it readable by all except Exception as e: print(f"Error saving lock file: {e}", file=sys.stderr) ``` ### Technical Analysis The default lock file uses the predictable path `/tmp/music_player.lock`, located in a shared temporary directory. The file is opened in write mode without preventing symbolic-link traversal, checking ownership, or atomically ensuring that a new regular file is being created. If the path is a symbolic link, `open(..., 'w')` follows the link and truncates the target before writing the port number. The subsequent `os.chmod()` also follows the link under normal platform behavior and attempts to change the target permissions to `0666`, making it writable by every local user. Exploitability depends on operating-system protections for shared temporary directories, such as Linux protected-symlink settings, and on the permissions and identity under which the server runs. These mitigations should not be relied upon as the application's security boundary. ### Attack Path 1. A local attacker identifies that the server will use `/tmp/music_player.lock`. 2. Before the server starts, the attacker places a symbolic link at that path pointing to a file writable by the account that will run the server. 3. A victim or privileged service account starts `music-server.py`. 4. `open(LOCK_FILE, 'w')` follows the symbolic link, truncates the target, and writes `12346`. 5. `os.chmod(LOCK_FILE, 0o666)` attempts to ma ...[truncated 757 chars]
- Remediation
- ## Remediation Suggestions - Store runtime state in a private per-user runtime directory, such as `$XDG_RUNTIME_DIR`, with directory permissions of `0700`. - Create the file atomically using `os.open()` with `O_CREAT`, `O_EXCL`, and, where supported, `O_NOFOLLOW`. - Create the lock file with mode `0600`; do not make it world-writable. - Before using an existing path, use `lstat()` and reject symbolic links and non-regular files. - Verify that the file is owned by the expected user. - Prefer an advisory lock on an already securely opened descriptor rather than treating a predictable pathname as authoritative. - Avoid running the music server with elevated privileges.
