From: Brion Vibber Date: Sun, 12 Dec 2004 23:31:23 +0000 (+0000) Subject: * Enhance upload extension blacklist to protect against vulnerable Apache configurations X-Git-Tag: 1.5.0alpha1~1097 X-Git-Url: https://git.cyclocoop.org/%28%28?a=commitdiff_plain;h=0714e507ff321dddbfbe48d50127e09629eb0c7b;p=lhc%2Fweb%2Fwiklou.git * Enhance upload extension blacklist to protect against vulnerable Apache configurations --- diff --git a/includes/SpecialUpload.php b/includes/SpecialUpload.php index 1e3d40c76d..5497b50a2f 100644 --- a/includes/SpecialUpload.php +++ b/includes/SpecialUpload.php @@ -156,14 +156,18 @@ class UploadForm { # Chop off any directories in the given filename $basename = basename( $this->mOname ); - if( preg_match( '/^(.*)\.([^.]*)$/', $basename, $matches ) ) { - $partname = $matches[1]; - $ext = $matches[2]; + /** + * We'll want to blacklist against *any* 'extension', and use + * only the final one for the whitelist. + */ + list( $partname, $ext ) = $this->splitExtensions( $basename ); + if( count( $ext ) ) { + $finalExt = $ext[count( $ext ) - 1]; } else { - $partname = $basename; - $ext = ''; + $finalExt = ''; } - + $fullExt = implode( '.', $ext ); + if ( strlen( $partname ) < 3 ) { $this->mainUploadForm( wfMsg( 'minlength' ) ); return; @@ -192,9 +196,10 @@ class UploadForm { /* Don't allow users to override the blacklist */ global $wgStrictFileExtensions; global $wgFileExtensions, $wgFileBlacklist; - if( $this->checkFileExtension( $ext, $wgFileBlacklist ) || - ($wgStrictFileExtensions && !$this->checkFileExtension( $ext, $wgFileExtensions ) ) ) { - return $this->uploadError( wfMsg( 'badfiletype', htmlspecialchars( $ext ) ) ); + if( $this->checkFileExtensionList( $ext, $wgFileBlacklist ) || + ($wgStrictFileExtensions && + !$this->checkFileExtension( $finalExt, $wgFileExtensions ) ) ) { + return $this->uploadError( wfMsg( 'badfiletype', htmlspecialchars( $fullExt ) ) ); } /** @@ -202,7 +207,7 @@ class UploadForm { * type but it's corrupt or data of the wrong type, we should * probably not accept it. */ - if( !$this->verify( $this->mUploadTempName, $ext ) ) { + if( !$this->verify( $this->mUploadTempName, $finalExt ) ) { return $this->uploadError( wfMsg( 'uploadcorrupt' ) ); } @@ -217,8 +222,8 @@ class UploadForm { global $wgCheckFileExtensions; if ( $wgCheckFileExtensions ) { - if ( ! $this->checkFileExtension( $ext, $wgFileExtensions ) ) { - $warning .= '
  • '.wfMsg( 'badfiletype', htmlspecialchars( $ext ) ).'
  • '; + if ( ! $this->checkFileExtension( $finalExt, $wgFileExtensions ) ) { + $warning .= '
  • '.wfMsg( 'badfiletype', htmlspecialchars( $fullExt ) ).'
  • '; } } @@ -534,6 +539,20 @@ class UploadForm { /* -------------------------------------------------------------- */ + /** + * Split a file into a base name and all dot-delimited 'extensions' + * on the end. Some web server configurations will fall back to + * earlier pseudo-'extensions' to determine type and execute + * scripts, so the blacklist needs to check them all. + * + * @return array + */ + function splitExtensions( $filename ) { + $bits = explode( '.', $filename ); + $basename = array_shift( $bits ); + return array( $basename, $bits ); + } + /** * Perform case-insensitive match against a list of file extensions. * Returns true if the extension is in the list. @@ -546,6 +565,23 @@ class UploadForm { return in_array( strtolower( $ext ), $list ); } + /** + * Perform case-insensitive match against a list of file extensions. + * Returns true if any of the extensions are in the list. + * + * @param array $ext + * @param array $list + * @return bool + */ + function checkFileExtensionList( $ext, $list ) { + foreach( $ext as $e ) { + if( in_array( strtolower( $e ), $list ) ) { + return true; + } + } + return false; + } + /** * Returns false if the file is of a known type but can't be recognized, * indicating a corrupt file.