Bug #77214 [Com]: ZipArchive::extractTo() errors on directories ending with .
| From: | david at moodle dot com | Date: | Thu, 14 Jan 2021 18:58:28 +0000 |
| Subject: | Bug #77214 [Com]: ZipArchive::extractTo() errors on directories ending with . | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-231566@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=77214&edit=1
ID: 77214
Comment by: david at moodle dot com
Reported by: nystrom dot lars dot egon at gmail dot com
Summary: ZipArchive::extractTo() errors on directories ending
with .
Status: Verified
Type: Bug
Package: Zip Related
Operating System: Linux
PHP Version: 7.2.12
Block user comment: N
Private report: N
New Comment:
I was experiencing this problem as well and I was able to debug it to what I believe causes the bug.
Let us have a simple ZIP archive to reproduce the problem, having a single file with the path
dot./sub/file.txt
When using ZipArchive::extractTo() to extract this file, the file was actually extracted into
sub/file.txt
Looking at the function source code at https://github.com/php/php-src/blob/533af1eb14dbeb10c83f291b07da62b70d0df8ae/ext/zip/php_zip.c#L2714
I saw that it calls
php_zip_extract_file() from the same file to do the job.
The function in turn calls php_zip_make_relative_path() to clean the file paths and
avoid path traversal attack - see https://github.com/php/php-src/blob/533af1eb14dbeb10c83f291b07da62b70d0df8ae/ext/zip/php_zip.c#L146-L150
From the implementation of php_zip_make_relative_path() at https://github.com/php/php-src/blob/533af1eb14dbeb10c83f291b07da62b70d0df8ae/ext/zip/php_zip.c#L83-L117
I understood that it iterates through the file path from the end to the start and when it finds a
slash character with a dot before it, it trims that whole part and starts from the position after
the slash.
I believe that is wrong. To avoid traversal attack, it should check for two dots before the slash
(like ../something). Also it seems there seems to be off-by-one mistake as the comment there reads
"i is the position of ." but I think that i is the position of the slash.
Previous Comments:
------------------------------------------------------------------------
[2018-11-28 19:19:30] cmb@php.net
I get this error message if the archive contains an *empty*
directory entry with a trailing dot. Test script:
<?php
$zip = new ZipArchive;
$zip->open(__DIR__ . '/77214.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
$zip->addEmptyDir('foo.');
$zip->close();
$zip->open(__DIR__ . '/77214.zip');
$zip->extractTo(__DIR__ . '/77214');
$zip->close();
The culprit is php_zip_make_relative_path()[1], which mistakenly
returns an empty string instead of "foo."
[1] <https://github.com/php/php-src/blob/php-7.3.0RC6/ext/zip/php_zip.c#L115-L130>
------------------------------------------------------------------------
[2018-11-28 16:21:19] nystrom dot lars dot egon at gmail dot com
Description:
------------
This is closely related to bug #69477, but I'm experiencing a different behavior.
When you have a zip archive that contains a directory with a name that ends with . (a dot)
ZipArchive errors out with the message:
ZipArchive::extractTo(/path/to/extract/to/): failed to open stream: Is a directory
Test script:
---------------
$extractPath = "/path/to/extract/to";
$zip = new ZipArchive;
$zip->open("/path/to/zipfile");
// Next line causes the error if the zip file contains a directory named 'myfolder.'
$zip->extractTo($extractPath, ['myfolder.']);
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=77214&edit=1