From d16961bed63b965d28d9edc1e32813d5de8d4572 Mon Sep 17 00:00:00 2001 From: deeplow Date: Tue, 18 Jul 2023 11:25:58 +0100 Subject: [PATCH] Security: Dynamically load libreoffice extension (PoC) Only load the LibreOffice extension for opening hwp/hwpx when it is actually needed. Adding an extension to libreoffice may allow for it to run arbitrary code. This makes it trust more scalable by trusting LibreOffice extensions only for the filetypes which they target. Reasoning --------- Assuming a malicious `.oxt` extension this means that the extension has arbitrary code execution in the container. While this is not an existential threat in itself, we should not expose every Dangerzone user to it. This is achieved by dynamically loading the extension at runtime only when needed. This ensures that a compromised extension will in its least malicious form be able to modify the visual content of any hancom office files but not *every file*. In the more malicious version, if the code execution manages to do a container escape, this will only affect users that have converted a Hancom office file. --- Dockerfile | 7 ++----- dangerzone/conversion/doc_to_pixels.py | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 78b2926..b59acdb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,15 +34,12 @@ RUN mkdir tessdata && cd tessdata \ && find . -name '*.traineddata' -maxdepth 2 -exec cp {} /usr/share/tessdata \; \ && cd .. && rm -r tessdata -RUN mkdir h2orestart && cd h2orestart \ +RUN mkdir /libreoffice_ext && cd libreoffice_ext \ && H2ORESTART_FILENAME=h2orestart.oxt \ && H2ORESTART_VERSION="v0.5.7" \ && wget https://github.com/ebandal/H2Orestart/releases/download/$H2ORESTART_VERSION/$H2ORESTART_FILENAME \ && echo "$H2ORESTART_CHECKSUM $H2ORESTART_FILENAME" | sha256sum -c \ - && _DESTDIR="/usr/lib/libreoffice/share/extensions/h2orestart/" \ - && install -dm755 $_DESTDIR \ - && unzip $H2ORESTART_FILENAME -d $_DESTDIR \ - && cd .. && rm -r h2orestart + && install -dm777 "/usr/lib/libreoffice/share/extensions/" ENV PYTHONPATH=/opt/dangerzone diff --git a/dangerzone/conversion/doc_to_pixels.py b/dangerzone/conversion/doc_to_pixels.py index ac6055a..10e73ee 100644 --- a/dangerzone/conversion/doc_to_pixels.py +++ b/dangerzone/conversion/doc_to_pixels.py @@ -80,19 +80,24 @@ class DocumentToPixels(DangerzoneConverter): # .hwp "application/vnd.hancom.hwp": { "type": "libreoffice", + "libreoffice_ext": "h2orestart.oxt", }, "application/haansofthwp": { "type": "libreoffice", + "libreoffice_ext": "h2orestart.oxt", }, "application/x-hwp": { "type": "libreoffice", + "libreoffice_ext": "h2orestart.oxt", }, # .hwpx "application/vnd.hancom.hwpx": { "type": "libreoffice", + "libreoffice_ext": "h2orestart.oxt", }, "application/haansofthwpx": { "type": "libreoffice", + "libreoffice_ext": "h2orestart.oxt", }, "application/hwp+zip": { "type": "libreoffice", @@ -144,6 +149,9 @@ class DocumentToPixels(DangerzoneConverter): if conversion["type"] is None: pdf_filename = "/tmp/input_file" elif conversion["type"] == "libreoffice": + libreoffice_ext = conversion.get("libreoffice_ext", None) + if libreoffice_ext: + await self.install_libreoffice_ext(libreoffice_ext) self.update_progress("Converting to PDF using LibreOffice") args = [ "libreoffice", @@ -303,6 +311,21 @@ class DocumentToPixels(DangerzoneConverter): ): shutil.move(filename, "/tmp/dangerzone") + async def install_libreoffice_ext(self, libreoffice_ext: str) -> None: + self.update_progress(f"Installing LibreOffice extension '{libreoffice_ext}'") + unzip_args = [ + "unzip", + "-d", + f"/usr/lib/libreoffice/share/extensions/{libreoffice_ext}/", + f"/libreoffice_ext/{libreoffice_ext}", + ] + await run_command( + unzip_args, + error_message="LibreOffice extension installation failed (unzipping)", + timeout_message="unzipping LibreOffice extension timed out 5 seconds", + timeout=5, + ) + async def main() -> int: converter = DocumentToPixels()