Skip to content
Permalink
Browse files Browse the repository at this point in the history
harden plugin unzipping to zip-slip attacks
  • Loading branch information
kevinhendricks committed Jul 12, 2019
1 parent 17ea124 commit 0979ba8
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
39 changes: 39 additions & 0 deletions src/Misc/Utility.cpp
@@ -1,5 +1,6 @@
/************************************************************************
**
** Copyright (C) 2019 Kevin B. Hendricks, Stratford, Ontario Canada
** Copyright (C) 2009, 2010, 2011 Strahinja Markovic <strahinja.markovic@gmail.com>
**
** This file is part of Sigil.
Expand Down Expand Up @@ -715,6 +716,44 @@ bool Utility::UnZip(const QString &zippath, const QString &destpath)

// If there is no file name then we can't do anything with it.
if (!qfile_name.isEmpty()) {

// for security reasons against maliciously crafted zip archives
// we need the file path to always be inside the target folder
// and not outside, so we will remove all illegal backslashes
// and all relative upward paths segments "/../" from the zip's local
// file name/path before prepending the target folder to create
// the final path

QString original_path = qfile_name;
bool evil_or_corrupt_epub = false;

if (qfile_name.contains("\\")) evil_or_corrupt_epub = true;
qfile_name = "/" + qfile_name.replace("\\","");

if (qfile_name.contains("/../")) evil_or_corrupt_epub = true;
qfile_name = qfile_name.replace("/../","/");

while(qfile_name.startsWith("/")) {
qfile_name = qfile_name.remove(0,1);
}

if (cp437_file_name.contains("\\")) evil_or_corrupt_epub = true;
cp437_file_name = "/" + cp437_file_name.replace("\\","");

if (cp437_file_name.contains("/../")) evil_or_corrupt_epub = true;
cp437_file_name = cp437_file_name.replace("/../","/");

while(cp437_file_name.startsWith("/")) {
cp437_file_name = cp437_file_name.remove(0,1);
}

if (evil_or_corrupt_epub) {
unzCloseCurrentFile(zfile);
unzClose(zfile);
// throw (UNZIPLoadParseError(QString(QObject::tr("Possible evil or corrupt zip file name: %1")).arg(original_path).toStdString()));
return false;
}

// We use the dir object to create the path in the temporary directory.
// Unfortunately, we need a dir ojbect to do this as it's not a static function.
// Full file path in the temporary directory.
Expand Down
10 changes: 10 additions & 0 deletions src/sigil_exception.h
@@ -1,5 +1,6 @@
/************************************************************************
**
** Copyright (C) 2019 Kevin B. Hendricks, Stratford, Ontario Canada
** Copyright (C) 2015 John Schember <john@nachtimwald.com>
** Copyright (C) 2009, 2010, 2011 Strahinja Markovic <strahinja.markovic@gmail.com>
**
Expand Down Expand Up @@ -132,4 +133,13 @@ class EPUBLoadParseError : public std::runtime_error {
EPUBLoadParseError(const std::string &msg) : std::runtime_error(msg) { };
};


/**
* Thrown for Invalid EPUB errors while loading and parsing content files.
*/
class UNZIPLoadParseError : public std::runtime_error {
public:
UNZIPLoadParseError(const std::string &msg) : std::runtime_error(msg) { };
};

#endif // SG_EXCEPTION_H

0 comments on commit 0979ba8

Please sign in to comment.