T07 · Tool Hijacking and Spoofing
- Location
scripts/office/soffice.py:24- Finding
Predictable LD_PRELOAD Library Allows Local Native Code Execution
- Content
View full analysis
dict: env = os.environ.copy() env["SAL_USE_VCLPLUGIN"] = "svp" if _needs_shim(): shim = _ensure_shim() env["LD_PRELOAD"] = str(shim) return env def run_soffice(args: list[str], **kwargs) -> subprocess.CompletedProcess: env = get_soffice_env() return subprocess.run(["soffice"] + args, env=env, **kwargs) _SHIM_SO = Path(tempfile.gettempdir()) / "lo_socket_shim.so" def _needs_shim() -> bool: try: s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.close() return False except OSError: return True 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 native shim is stored at the fixed, globally predictable path `/tmp/lo_socket_shim.so`. If that path already exists, `_ensure_shim()` accepts it without verifying: - File ownership - File permissions - Whether it is a regular file or symbolic link - Whether it was produced from the embedded source - Its cryptographic integrity When Unix-domain socket creation fails, `get_soffice_env()` places this file in `LD_PRELOAD`. The dynamic loader then loads the shared object into every LibreOffice process launched with that environment. Native library constructors and interposed functions execute with the privileges of the user running the Skill. This creates a local tool-hijacking condition: an attacker who can write to the shared temporary di ...[truncated 1789 chars]- Remediation
View remediation
