Bug 398096 - Especially crafted Okular archives may lead to an arbitrary file creation on the user workstation
Summary: Especially crafted Okular archives may lead to an arbitrary file creation on ...
Alias: None
Product: okular
Classification: Applications
Component: general (show other bugs)
Version: unspecified
Platform: Other Linux
: NOR major
Target Milestone: ---
Assignee: Okular developers
Depends on:
Reported: 2018-08-31 12:52 UTC by Joran Hervé
Modified: 2018-09-03 21:32 UTC (History)
3 users (show)

See Also:
Latest Commit:
Version Fixed In: 18.08.1

Proof of Concept (7.12 KB, application/vnd.kde.okular-archive)
2018-08-31 12:52 UTC, Joran Hervé

Note You need to log in before you can comment on or make changes to this bug.
Description Joran Hervé 2018-08-31 12:52:24 UTC
Created attachment 114718 [details]
Proof of Concept


I found an issue that may allow to maliciously deploy file at arbitrary location by opening Okular archives.

When opening an Okular archive, "content.xml" is parsed in order to extract the document name (field "DocumentFileName"). If this file is also present in the archive, it is temporarily saved inside "/tmp" under a random name with "okular_XXXXXX.extension" form and is finally opened by the viewer.

The issue comes from the "unpackDocumentArchive(...)" of "core/document.cpp":

1: To create the temporary name of the document, this function search extract the extension of the "DocumentFileName" using the following line:

const int dotPos = documentFileName.indexOf( QLatin1Char('.') );
if ( dotPos != -1 )
    archiveData->document.setFileTemplate(QDir::tempPath() + QLatin1String("/okular_XXXXXX") + documentFileName.mid(dotPos));

In case of a "DocumentFileName" named "this.is.a.test", the temporary name will have the form "/tmp/okular_XXXXXX.is.a.test".
If "DocumentFileName" was "aaa.aaa/../../testXXXXXX.txt", the temporary name would become the path "/tmp/okular_XXXXXX.aaa/../../testXXXXXX.txt".

2: Before generating this name, the function "unpackDocumentArchive(...)" check if the document exists using the following code:

const KArchiveEntry * docEntry = mainDir->entry( documentFileName );
if ( !docEntry || !docEntry->isFile() )
    return nullptr;

Archives are not supposed to contain files with relative paths but it is possible to manually craft them. As the "KArchiveDirectory" class used to parse archives do not raise any exceptions in such case, it is possible to control the path of the temporary file (with exception of the six random characters).

3: Such temporary files are supposed to be removed when closing Okular which limit the impact of this bug. However, it may be possible to forge malicious archives containing documents that would cause a crash of Okular during opening (for example a document with very large pictures to ran out of memory) in order to avoid the deletion phase. As PDF may be "polyglot" ( https://en.wikipedia.org/wiki/Polyglot_(computing) ), the document could also contain a configuration file or an executable to deploy on the victim workstation.

Correcting this issue may be done by searching the last dot and not the first one on the line :
const int dotPos = documentFileName.indexOf( QLatin1Char('.') );

To illustrate this issue, I have joined an Okular archive file which (when opened with "root" permission) create a polyglot (PDF/script) file named "payloadXXXXX.pdf" in the "/root/" folder.

I'm apologizing for the mistakes and am available if you have any question.

Best regards,

Comment 1 Albert Astals Cid 2018-08-31 21:42:53 UTC
You should never run okular as root, that's just bad practice and there's really no reason for anyone be doing that.

Anyhow i guess the problem applies for regular users too
Comment 2 Albert Astals Cid 2018-08-31 22:14:44 UTC
My suggestion at https://phabricator.kde.org/D15192
Comment 3 Albert Astals Cid 2018-09-03 19:15:09 UTC
Git commit 8ff7abc14d41906ad978b6bc67e69693863b9d47 by Albert Astals Cid.
Committed on 03/09/2018 at 19:14.
Pushed by aacid into branch 'Applications/18.08'.

Fix path traversal issue when extracting an .okular file

With specially crafted .okular files you can trick okular to create temporary files outside the temporary folder

We fix that by making sure the file doesn't have folders since the ones we create don't

Subscribers: okular-devel

Tags: #okular

Differential Revision: https://phabricator.kde.org/D15192

M  +12   -0    core/document.cpp