CVE-2020-15908 (Other, published 2020-07-23T04:15Z)
Description: value: tar/TarFileReader.cpp in Cauldron cbang (aka C-Bang or C!) before 1.6.0 allows Directory Traversal during extraction from a TAR archive.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-22 \u2014 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
Repository: https://github.com/CauldronDevelopmentLLC/cbang
Files changed:
src/cbang/tar/TarFileReader.cpp
tests/tarTests/.gitignore
tests/tarTests/BadExtractTest/data/args
tests/tarTests/BadExtractTest/expect/return
tests/tarTests/BadExtractTest/expect/stderr
tests/tarTests/CompressedExtractTest/data/args
tests/tarTests/CompressedExtractTest/expect/return
tests/tarTests/CompressedExtractTest/expect/stdout
tests/tarTests/ExtractTest/data/args
tests/tarTests/ExtractTest/expect/return
tests/tarTests/ExtractTest/expect/stdout
tests/tarTests/SConscript
tests/tarTests/tar.cpp
tests/tarTests/test.json
Commit message: Don't allow extraction of tar files outside of the target directory, added tar tests


Vulnerable code:
  if (SystemUtilities::isDirectory(path)) path += "/" + getFilename();
  return extract(*SystemUtilities::oopen(path));

Fixed code:
  if (SystemUtilities::isDirectory(path)) {
    path += "/" + getFilename();

    // Check that path is under the target directory
    string a = SystemUtilities::getCanonicalPath(_path);
    string b = SystemUtilities::getCanonicalPath(path);
    if (!String::startsWith(b, a))
      THROW("Tar path points outside of the extraction directory: " << path);
  }
  switch (getType()) {
  case NORMAL_FILE: case CONTIGUOUS_FILE:
    return extract(*SystemUtilities::oopen(path));
  case DIRECTORY: SystemUtilities::ensureDirectory(path); break;
  default: THROW("Unsupported tar file type " << getType());
  }

  return getFilename();
/path
--extract test.tar
1
Tar path points outside of the extraction directory: ./../hello.txt
--extract test.tar.bz2
0
hello.txt
--extract test.tar
0
hello.txt
Import('*')

# Local includes
env.Append(CPPPATH = ['#'])

prog = env.Program('tar', 'tar.cpp')

Return('prog')
/******************************************************************************\

          This file is part of the C! library.  A.K.A the cbang library.

                Copyright (c) 2003-2019, Cauldron Development LLC
                   Copyright (c) 2003-2017, Stanford University
                               All rights reserved.

         The C! library is free software: you can redistribute it and/or
        modify it under the terms of the GNU Lesser General Public License
       as published by the Free Software Foundation, either version 2.1 of
               the License, or (at your option) any later version.

        The C! library is distributed in the hope that it will be useful,
          but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                 Lesser General Public License for more details.

         You should have received a copy of the GNU Lesser General Public
                 License along with the C! library.  If not, see
                         <http://www.gnu.org/licenses/>.

        In addition, BSD licensing may be granted on a case by case basis
        by written permission from at least one of the copyright holders.
           You may request written permission by emailing the authors.

                  For information regarding this software email:
                                 Joseph Coffland
                          joseph@cauldrondevelopment.com

\******************************************************************************/

#include <cbang/tar/TarFileReader.h>
#include <cbang/Catch.h>

#include <iostream>

using namespace cb;
using namespace std;


int main(int argc, char *argv[]) {
  try {
    for (int i = 1; i < argc; i++) {
      string arg = argv[i];

      if (arg == "--extract" && i < argc - 1) {
        TarFileReader reader(argv[++i]);

        while (reader.hasMore())
          cout << reader.extract() << endl;

      } else THROWS("Invalid arg '" << arg << "'");
    }

    return 0;

  } catch (const Exception &e) {cerr << e.getMessage();}

  return 1;
}
{
  "command": "%(suite-dir)s/tar"
}