From 9e2604af85a90267186c19d121206e1cc25be1d5 Mon Sep 17 00:00:00 2001 From: Daniel Rudolf Date: Wed, 28 Oct 2015 01:36:28 +0100 Subject: [PATCH] Prevent content_dir breakouts using malicious request URLs It's appalling that nobody (including me!) thought about that! --- lib/Pico.php | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/Pico.php b/lib/Pico.php index 85e3f0a..4d78507 100644 --- a/lib/Pico.php +++ b/lib/Pico.php @@ -556,7 +556,28 @@ class Pico if (empty($this->requestUrl)) { $this->requestFile = $this->getConfig('content_dir') . 'index' . $this->getConfig('content_ext'); } else { - $this->requestFile = $this->getConfig('content_dir') . $this->requestUrl; + // prevent content_dir breakouts using malicious request URLs + // we don't use realpath() here because we neither want to check for file existance + // nor prohibit symlinks which intentionally point to somewhere outside the content_dir + // it is STRONGLY RECOMMENDED to use open_basedir - always, not just with Pico! + $requestUrl = str_replace('\\', '/', $this->requestUrl); + $requestUrlParts = explode('/', $requestUrl); + + $requestFileParts = array(); + foreach ($requestUrlParts as $requestUrlPart) { + if (($requestUrlPart === '') || ($requestUrlPart === '.')) { + continue; + } elseif ($requestUrlPart === '..') { + array_pop($requestFileParts); + continue; + } + + $requestFileParts[] = $requestUrlPart; + } + + // discover the content file to serve + // Note: $requestFileParts neither contains a trailing nor a leading slash + $this->requestFile = $this->getConfig('content_dir') . implode('/', $requestFileParts); if (is_dir($this->requestFile)) { // if no index file is found, try a accordingly named file in the previous dir // if this file doesn't exist either, show the 404 page, but assume the index