T06 · System Persistence
Warning
- Location
- recalc.py:18
- Finding
- Persistent LibreOffice Profile Modification Can Overwrite Existing User Macros<![CDATA[ ## Vulnerability Details **File Location**: `recalc.py`, lines 18–42 **Vulnerability Type**: Persistent application-profile modification and unsafe file overwrite **Risk Level**: Medium ### 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) ``` ### Technical Analysis The script installs executable LibreOffice Basic code directly into the current user's persistent LibreOffice profile. It uses the generic module path `Standard/Module1.xba`, which may already contain macros created by the user or another application. The existing-file check only searches for the substring `RecalculateAndSave`. If that substring is absent, the file is opened using mode `w`, which truncates the complete module before writing th ...[truncated 2110 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Use an isolated temporary LibreOffice profile** - Create a unique temporary directory for each recalculation operation. - Launch LibreOffice with an isolated profile using `-env:UserInstallation=file:///absolute/path`. - Install the recalculation macro only in that temporary profile. - Delete the profile after the operation, including on errors and timeouts. 2. **Do not overwrite generic user modules** - Avoid writing to `Standard/Module1.xba` in the user's normal profile. - If persistent installation is unavoidable, use a uniquely named library and module owned by this application. 3. **Preserve existing content** - Check whether the target path already exists before creating it. - Refuse to replace an existing module unless explicit user authorization is obtained. - If modification is required, create a verified backup and restore it in a `finally` block. - Do not use substring matching as the basis for deciding whether an entire XML module may be replaced. 4. **Implement reliable cleanup** - Track every file and directory created by the script. - Remove installed macro artifacts after recalculation. - Ensure cleanup runs after success, failure, exceptions, and subprocess timeouts. 5. **Apply defensive file handling** - Write new files atomically through a temporary file followed by a controlled rename. - Validate that the destination remains inside the intended isolated profile. - Use restrictive permissions for temporary profile files. - Reject symbolic-link destinations before writing to avoid overwriting an unintended file. ]]>
