T07 · Tool Hijacking and Spoofing
Error
- Location
- scripts/office/soffice.py:24
- Finding
- Predictable shared LD_PRELOAD library enables local tool hijacking<![CDATA[ ## Vulnerability Details **File Location**: `scripts/office/soffice.py:24-31, 41-65` **Vulnerability Type**: Unsafe temporary file handling and dynamic-library preloading **Risk Level**: High ### Vulnerable Code ```python def get_soffice_env() -> dict: env = os.environ.copy() env["SAL_USE_VCLPLUGIN"] = "svp" if _needs_shim(): shim = _ensure_shim() env["LD_PRELOAD"] = str(shim) return env _SHIM_SO = Path(tempfile.gettempdir()) / "lo_socket_shim.so" def _ensure_shim() -> Path: if _SHIM_SO.exists(): return _SHIM_SO src = Path(tempfile.gettempdir()) / "lo_socket_shim.c" src.write_text(_SHIM_SOURCE) subprocess.run( ["gcc", "-shared", "-fPIC", "-o", str(_SHIM_SO), str(src), "-ldl"], check=True, capture_output=True, ) src.unlink() return _SHIM_SO ``` ### Technical Analysis The code stores a native shared library at the fixed path `/tmp/lo_socket_shim.so`. If that path already exists, `_ensure_shim()` trusts it without checking its owner, permissions, file type, resolved path, or contents. When AF_UNIX socket creation is unavailable, the existing file is assigned to `LD_PRELOAD` and loaded into the LibreOffice process. `LD_PRELOAD` libraries execute native initialization code in the target process before normal application execution. Consequently, accepting an attacker-controlled file at this location creates a direct local code-execution primitive. The source file `/tmp/lo_socket_shim.c` is also predictable and written non-atomically. The implementation does not reject symbolic links or protect the check-then-use sequence from replacement races. ### Attack Path 1. A local attacker who can write to the shared temporary directory creates `/tmp/lo_socket_shim.so` as a malicious shared library, or replaces the file between validation and LibreOffice execution. 2. The Skill runs in an environment where `_needs_shim()` returns `True`. 3. `_ensure_shim()` det ...[truncated 814 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Create a new private temporary directory for each invocation using `tempfile.TemporaryDirectory()`. - Ensure the directory is owned by the current user and has mode `0700`. - Compile the library to a unique path inside that directory rather than under a shared fixed filename. - Create files atomically and reject symbolic links and non-regular files. - Never reuse a pre-existing library solely because it exists. - If caching is required, verify ownership, restrictive permissions, and a cryptographic hash of the expected binary before using it. - Set `LD_PRELOAD` only for the specific LibreOffice child process and remove the temporary directory in a `finally` block. - Consider removing native interposition entirely and failing safely when the environment does not support the required LibreOffice socket behavior. ]]>
