Headline
CVE-2021-4330: Changeset 2617529 for envato-elements – WordPress Plugin Repository
The Envato Elements & Download and Template Kit – Import plugins for WordPress are vulnerable to arbitrary file uploads due to insufficient validation of file type upon extracting uploaded Zip files in the installFreeTemplateKit and uploadTemplateKitZipFile functions. This makes it possible for attackers with contributor-lever permissions and above to upload arbitrary files and potentially gain remote code execution in versions up to and including 1.0.13 of Template Kit – Import and versions up to and including 2.0.10 of Envato Elements & Download.
envato-elements/trunk/envato-elements.php
r2614547
r2617529
5
5
* Author: Envato
6
6
* Author URI: https://elements.envato.com/extensions/wordpress/?utm_source=extensions&utm_medium=referral&utm_campaign=elements_extensions_wpplugins
7
* Version: 2.0.10
7
* Version: 2.0.11
8
8
* License: GPLv3 or later
9
9
* License URI: https://www.gnu.org/licenses/gpl-3.0.html
…
…
31
31
32
32
define( 'ENVATO_ELEMENTS_SLUG’, ‘envato-elements’ );
33
define( 'ENVATO_ELEMENTS_VER’, ‘2.0.10’ );
33
define( 'ENVATO_ELEMENTS_VER’, ‘2.0.11’ );
34
34
define( 'ENVATO_ELEMENTS_FILE’, __FILE__ );
35
35
define( 'ENVATO_ELEMENTS_DIR’, plugin_dir_path( ENVATO_ELEMENTS_FILE ) );
envato-elements/trunk/readme.txt
r2614547
r2617529
5
5
Tested up to: 5.8
6
6
Requires PHP: 5.6
7
Stable tag: 2.0.10
7
Stable tag: 2.0.11
8
8
License: GPLv3
9
9
License URI: https://www.gnu.org/licenses/gpl-3.0.html
…
…
79
79
80
80
== Changelog ==
81
82
= 2.0.11 - 2021-10-21 =
83
* Fix: Swap to using ZipArchive for Template Kit extraction
81
84
82
85
= 2.0.10 - 2021-09-17 =
envato-elements/trunk/vendor/template-kit-import/inc/class-importer.php
r2614547
r2617529
43
43
44
44
/\*\*
45
\* Called when we want to unpack a ZIP file into a folder.
46
\* Assumes the folder exists.
45
\* Extract
46
\*
47
\* Performs the extraction of the zip files to a temporary directory.
48
\* Returns an error if for some reason the ZipArchive utility isn't available.
49
\* Otherwise, Returns a strnig containing the temporary extraction directory
47
50
\*
48
51
\* @param string $temporary\_zip\_file
…
…
52
55
\*/
53
56
private function unpack\_template\_kit\_zip\_to\_folder( $temporary\_zip\_file, $destination\_folder ) {
54
global $wp\_filesystem;
55
56
require\_once ABSPATH . '/wp-admin/includes/file.php';
57
\\WP\_Filesystem();
58
59
if ( ! $wp\_filesystem instanceof \\WP\_Filesystem\_Base ) {
60
return new \\WP\_Error( 'zip\_error', 'Failed to initialize WP Filesystem' );
57
if ( ! class\_exists( '\\ZipArchive' ) ) {
58
return new \\WP\_Error( 'zip\_error', 'PHP Zip extension not loaded' );
61
59
}
62
60
63
$unzip\_result = unzip\_file( $temporary\_zip\_file, $destination\_folder );
64
if ( $unzip\_result !== true ) {
65
if ( is\_wp\_error( $unzip\_result ) ) {
66
return $unzip\_result;
61
$allowed\_file\_types = \[ 'json', 'jpg', 'png', 'css', 'html' \];
62
63
$zip = new \\ZipArchive();
64
65
$zip->open( $temporary\_zip\_file );
66
67
$allowed\_files = \[\];
68
69
// phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
70
for ( $i = 0; $i < $zip->numFiles; $i ++ ) {
71
$filename = $zip->getNameIndex( $i );
72
$extension = pathinfo( $filename, PATHINFO\_EXTENSION );
73
74
if ( in\_array( $extension, $allowed\_file\_types, true ) ) {
75
$allowed\_files\[\] = $filename;
67
76
}
77
}
68
78
69
return new \\WP\_Error( 'zip\_error', 'Failed to unzip zip file' );
70
}
79
$zip->extractTo( $destination\_folder, $allowed\_files );
80
81
$zip->close();
71
82
72
83
$extracted\_zip\_files = scandir( $destination\_folder );
…
…
76
87
$file\_names = array();
77
88
}
78
if ( ! $file\_names || ! in\_array( 'manifest.json', $file\_names, true ) || preg\_grep( '/\\.php/i', $file\_names ) ) {
89
if ( ! $file\_names || ! in\_array( 'manifest.json', $file\_names, true ) ) {
79
90
$this->delete\_template\_kit\_folder( $destination\_folder );
80
91