--- a/libs/Smarty.class.php +++ b/libs/Smarty.class.php @@ -1210,11 +1210,12 @@ */ public function _realpath($path, $realpath = null) { - $nds = $this->ds == '/' ? '\\' : '/'; - // normalize $this->ds - $path = str_replace($nds, $this->ds, $path); - preg_match('%^(?(?:[[:alpha:]]:[\\\\]|/|[\\\\]{2}[[:alpha:]]+|[[:print:]]{2,}:[/]{2}|[\\\\])?)(?(?:[[:print:]]*))$%', - $path, $parts); + $nds = array('/' => '\\', '\\' => '/'); + preg_match( + '%^(?(?:[[:alpha:]]:[\\\\]|/|[\\\\]{2}[[:alpha:]]+|[[:print:]]{2,}:[/]{2}|[\\\\])?)(?(?:[[:print:]]*))$%u', + $path, + $parts + ); $path = $parts[ 'path' ]; if ($parts[ 'root' ] == '\\') { $parts[ 'root' ] = substr(getcwd(), 0, 2) . $parts[ 'root' ]; @@ -1223,25 +1224,18 @@ $path = getcwd() . $this->ds . $path; } } - // remove noop 'DIRECTORY_SEPARATOR DIRECTORY_SEPARATOR' and 'DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR' patterns - $path = preg_replace('#([\\\\/]([.]?[\\\\/])+)#', $this->ds, $path); - // resolve '..DIRECTORY_SEPARATOR' pattern, smallest first - if (strpos($path, '..' . $this->ds) != false && - preg_match_all('#(([.]?[\\\\/])*([.][.])[\\\\/]([.]?[\\\\/])*)+#', $path, $match) - ) { - $counts = array(); - foreach ($match[ 0 ] as $m) { - $counts[] = (int) ((strlen($m) - 1) / 3); - } - sort($counts); - foreach ($counts as $count) { - $path = preg_replace('#(([\\\\/]([.]?[\\\\/])*[^\\\\/.]+){' . $count . - '}[\\\\/]([.]?[\\\\/])*([.][.][\\\\/]([.]?[\\\\/])*){' . $count . '})(?=[^.])#', - $this->ds, $path); - } - } - - return $parts[ 'root' ] . $path; + // normalize the directory separator + $path = str_replace(array($nds[$this->ds], $this->ds . '.' . $this->ds), $this->ds, $path); + $parts[ 'root' ] = str_replace($nds[ $this->ds ], $this->ds, $parts[ 'root' ]); + do { + $path = preg_replace( + array('#[\\\\/]{2}#', '#[\\\\/][.][\\\\/]#', '#[\\\\/]([^\\\\/.]+)[\\\\/][.][.][\\\\/]#'), + $this->ds, + $path, + -1, + $count); + } while($count > 0); + return $realpath !== false ? $parts[ 'root' ] . $path : str_ireplace(getcwd(), '.', $parts[ 'root' ] . $path); } /** --- a/libs/sysplugins/smarty_security.php +++ b/libs/sysplugins/smarty_security.php @@ -641,7 +641,8 @@ { $directory = dirname($filepath) . DIRECTORY_SEPARATOR; $_directory = array(); - while (true) { + if (!preg_match('#[\\\\/][.][.][\\\\/]#',$directory)) { + while (true) { // remember the directory to add it to _resource_dir in case we're successful $_directory[ $directory ] = true; // test if the directory is trusted @@ -653,14 +654,16 @@ } // abort if we've reached root if (!preg_match('#[\\\/][^\\\/]+[\\\/]$#', $directory)) { - break; + //give up + throw new SmartyException("directory '{$filepath}' not allowed by security setting"); } // bubble up one level $directory = preg_replace('#[\\\/][^\\\/]+[\\\/]$#', DIRECTORY_SEPARATOR, $directory); + } } // give up - throw new SmartyException("directory '{$filepath}' not allowed by security setting"); + throw new SmartyException(sprintf('Smarty Security: not trusted file path \'%s\' ',$filepath)); } /**