CVE-2023-6069 (PHP, published 2023-11-10T01:15Z)
Description: value: Improper Link Resolution Before File Access in GitHub repository froxlor/froxlor prior to 2.1.0.


Severity: nan (CVSS v3 base score: 8.8)
Weakness: CWE-59 \u2014 Improper Link Resolution Before File Access ('Link Following')
The product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource.
Repository: https://github.com/froxlor/froxlor
Files changed:
customer_ftp.php
lib/Froxlor/Api/Commands/DirOptions.php
lib/Froxlor/Api/Commands/DirProtections.php
lib/Froxlor/Api/Commands/Ftps.php
lib/Froxlor/Api/Commands/SubDomains.php
lib/Froxlor/Cron/Http/Apache.php
lib/Froxlor/FileDir.php
tests/Ftps/FtpsTest.php
Commit message: check for symlinks when required to be within customer-homedir

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>


Vulnerable code:
			$actions_links = [
		$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);
		$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);
				$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);
			$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);
				$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $completedomain);
				$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);
					// or a renew is ongoing - disable redirect
						// only create the require all granted if there is not active directory-protection
use PDO;
use RecursiveCallbackFilterIterator;
		int $uid,
		int $gid,
		bool $placeindex = false,
		bool $allow_notwithinhomedir = false
	): bool {
	 * Function which returns a correct dirname, means to add slashes at the beginning and at the end if there weren't
	 * some
	public static function makeCorrectDir(string $dir): string
		$logger = null,
		bool $force = false
	) {
use PHPUnit\Framework\TestCase;
		$json_result = Ftps::getLocal($customer_userdata)->add();
		$json_result = Ftps::getLocal($admin_userdata, $data)->add();

Fixed code:
			$actions_links[] = [
		$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']);
		$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']);
				$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']);
			$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']);
				$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $completedomain, $customer['documentroot']);
				$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']);
					// or a renewal is ongoing - disable redirect
						// only create the' require all granted' if there is no active directory-protection
use PDO;
use RecursiveCallbackFilterIterator;
		int    $uid,
		int    $gid,
		bool   $placeindex = false,
		bool   $allow_notwithinhomedir = false
	): bool
	{
	 * Returns a correct/secure dirname, means to add slashes at the beginning and at the end if there weren't
	 * some. If $fixes_homedir is specified,
	 *
	public static function makeCorrectDir(string $dir, string $fixed_homedir = ""): string

			// if given, check that the target path is within the $fixed_homedir
			// by checking each folder for being a symlink and whether it targets
			// the customers homedir or points outside of it
			if (!empty($fixed_homedir)) {
				$to_check = explode("/", substr($dir, strlen($fixed_homedir) + 1), -1);
				$check_dir = substr($fixed_homedir, 0, -1);
				// Symlink check
				foreach ($to_check as $sub_dir) {
					$check_dir .= '/' . $sub_dir;
					if (is_link($check_dir)) {
						$original_target = $check_dir;
						$check_dir = readlink($check_dir);
						if (substr($check_dir, 0, strlen($fixed_homedir)) != $fixed_homedir) {
							throw new Exception("Found symlink pointing outside of customer home directory: " . substr($original_target, strlen($fixed_homedir)));
						}
					}
				}
				// check for the path to be within the given homedir
				if (substr($dir, 0, strlen($fixed_homedir)) != $fixed_homedir) {
					throw new Exception("Target path not within the required customer home directory");
				}
			}

			   $logger = null,
		bool   $force = false
	)
	{
use Froxlor\Froxlor;
use PHPUnit\Framework\TestCase;
	public function testCustomerFtpsAddSymlinkOutsideHomedir()
	{
		global $admin_userdata;

		// get customer
		$json_result = Customers::getLocal($admin_userdata, array(
			'loginname' => 'test1'
		))->get();
		$customer_userdata = json_decode($json_result, true)['data']; //

		$customer_userdata['documentroot'] = sys_get_temp_dir() . '/';
		@unlink($customer_userdata['documentroot'] . '/frx');
		symlink(Froxlor::getInstallDir(), $customer_userdata['documentroot'] . '/frx');

		$data = [
			'ftp_password' => 'h4xXx0r',
			'path' => '/frx/sub',
			'ftp_description' => 'testing',
			'sendinfomail' => TRAVIS_CI == 1 ? 0 : 1
		];

		$this->expectExceptionMessage('Found symlink pointing outside of customer home directory: /frx');
		Ftps::getLocal($customer_userdata, $data)->add();
	}

		Ftps::getLocal($customer_userdata)->add();
		Ftps::getLocal($admin_userdata, $data)->add();