T07 · Tool Hijacking and Spoofing
Error
- Location
- scripts/recalc.py:18
- Finding
- Untrusted Pre-existing LibreOffice Macro Can Hijack Workbook Recalculation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/recalc.py`, lines 18–52 and 67–73 **Vulnerability Type**: Insufficient validation of an executable application-level macro **Risk Level**: High ### Vulnerable Code ```python def setup_libreoffice_macro(): """Setup LibreOffice macro for recalculation if not already configured""" if platform.system() == "Darwin": macro_dir = os.path.expanduser("~/Library/Application Support/LibreOffice/4/user/basic/Standard") else: macro_dir = os.path.expanduser("~/.config/libreoffice/4/user/basic/Standard") macro_file = os.path.join(macro_dir, "Module1.xba") if os.path.exists(macro_file): with open(macro_file, "r") as f: if "RecalculateAndSave" in f.read(): return True if not os.path.exists(macro_dir): subprocess.run(["soffice", "--headless", "--terminate_after_init"], capture_output=True, timeout=10) os.makedirs(macro_dir, exist_ok=True) macro_content = """<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd"> <script:module xmlns:script="http://openoffice.org/2000/script" script:name="Module1" script:language="StarBasic"> Sub RecalculateAndSave() ThisComponent.calculateAll() ThisComponent.store() ThisComponent.close(True) End Sub </script:module>""" try: with open(macro_file, "w") as f: f.write(macro_content) return True except Exception: return False ``` The accepted macro is subsequently invoked: ```python cmd = [ "soffice", "--headless", "--norestore", "vnd.sun.star.script:Standard.Module1.RecalculateAndSave?language=Basic&location=application", abs_path, ] ``` ### Technical Analysis The script treats an existing LibreOffice macro as trusted if its source contains the substring `RecalculateAndSave`. It does not validate the exact macro impleme ...[truncated 2142 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Use an isolated LibreOffice profile** - Create a unique temporary directory for every recalculation. - Start LibreOffice with a dedicated profile, such as `-env:UserInstallation=file:///...`. - Ensure the directory is accessible only to the current process or user. - Remove the profile in a `finally` block after recalculation. 2. **Avoid application-level persistent macros** - Prefer a supported non-macro LibreOffice or UNO recalculation interface. - Do not execute macros stored in the user's shared `Standard` library. 3. **Validate trusted executable content** - If a macro remains necessary, write a uniquely named module into the isolated profile. - Compare the complete module content or a cryptographic digest before execution. - Do not use a substring or procedure-name check as a trust decision. 4. **Harden file handling** - Reject symlinked macro paths. - Verify ownership and restrictive permissions before using any existing file. - Use atomic file creation with exclusive semantics rather than overwriting an arbitrary existing module. 5. **Constrain execution** - Run LibreOffice in a sandbox or container with access limited to the target workbook and temporary profile. - Disable network access where recalculation does not require it. - Apply operating-system resource and process restrictions. ]]>
