CVE-2021-43403 (PHP, published 2022-09-29T03:15Z)
Description: value: An issue was discovered in FusionPBX before 4.5.30. The log_viewer.php Log View page allows an authenticated user to choose an arbitrary filename for download (i.e., not necessarily freeswitch.log in the intended directory).
Severity: nan (CVSS v3 base score: 6.5)
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/fusionpbx/fusionpbx
Files changed:
app/log_viewer/log_viewer.php
Commit message: Add better log filename validation.

This was needed after the a previous pull request that allowed selecting a log file to download.

Vulnerable code:
	Portions created by the Initial Developer are Copyright (C) 2008-2019
	if (!isset($_POST['line_number']) || $_POST['line_number'] == '') { $_POST['line_number'] = 0; }
	if (!isset($_POST['sort']) || $_POST['sort'] == '') { $_POST['sort'] = "asc"; }
	if (!isset($_POST['size']) || strlen($_POST['size']) == 0) { $_POST['size'] = "32"; }
	if (!isset($_POST['filter'])) { $_POST['filter'] = ""; }	
	if (!isset($_POST['log_file']) || substr($_POST['log_file'],0,14) != "freeswitch.log") { $_POST['log_file'] = "freeswitch.log"; }	
		if (isset($_GET['n']) && substr($_GET['n'],0,14) == "freeswitch.log") {
			$dir = $_SESSION['switch']['log']['dir'];
			$filename = $_GET['n'];
			session_cache_limiter('public');
			$fd = fopen($dir."/".$filename, "rb");
			header("Content-Type: binary/octet-stream");
			header("Content-Length: " . filesize($tmp."/".$filename));
			header('Content-Disposition: attachment; filename="'.$filename.'"');
			fpassthru($fd);
			exit;
	$files = scandir($_SESSION['switch']['log']['dir']);
	foreach($files as $file) if (substr($file,0,14) == "freeswitch.log") {
			$selected = ($file == $_POST['log_file']) ? "selected='selected'" : "";
			echo "			<option value='".$file."'".$selected.">".$file."</option>";
		echo button::create(['type'=>'button','label'=>$text['button-download'],'icon'=>$_SESSION['theme']['button_icon_download'],'style'=>'margin-left: 15px;','link'=>'log_viewer.php?a=download&n='.$_POST['log_file']]);
		if (substr($_POST['log_file'],0,14) == "freeswitch.log") {
			$log_file = $_SESSION['switch']['log']['dir']."/".$_POST['log_file'];
		}
?>

Fixed code:
	Portions created by the Initial Developer are Copyright (C) 2008-2021
	if (!isset($_POST['line_number']) || $_POST['line_number'] == '') {
		$_POST['line_number'] = 0; 
	}
	if (!isset($_POST['sort']) || $_POST['sort'] == '') { 
		$_POST['sort'] = "asc";
	}
	if (!isset($_POST['size']) || strlen($_POST['size']) == 0) { 
		$_POST['size'] = "32";
	}
	if (!isset($_POST['filter'])) {
		$_POST['filter'] = '';
	}
	if (isset($_POST['log_file'])) {
		$approved_files = glob($_SESSION['switch']['log']['dir'].'/freeswitch.log*');
		foreach($approved_files as $approved_file) {
			if ($approved_file == $_SESSION['switch']['log']['dir'].'/'.$_POST['log_file']) {
				$log_file = $approved_file;
			}
		}
	}
	else {
		$log_file = $_SESSION['switch']['log']['dir'].'/freeswitch.log';
	}
		if (isset($_GET['n'])) {
			if (isset($filename)) { unset($filename); }
			$approved_files = glob($_SESSION['switch']['log']['dir'].'/freeswitch.log*');
			foreach($approved_files as $approved_file) {
				if ($approved_file == $_SESSION['switch']['log']['dir'].'/'.$_GET['n']) {
					$filename = $approved_file;
				}
			}
			if (isset($filename) && file_exists($filename)) {
				session_cache_limiter('public');
				$fd = fopen($filename, "rb");
				header("Content-Type: binary/octet-stream");
				header("Content-Length: " . filesize($filename));
				header('Content-Disposition: attachment; filename="'.basename($filename).'"');
				fpassthru($fd);
				exit;
			}
	$files = glob($_SESSION['switch']['log']['dir'].'/freeswitch.log*');
	foreach($files as $file) {
		$selected = ($file == $log_file) ? "selected='selected'" : "";
		echo "			<option value='".basename($file)."'".$selected.">".basename($file)."</option>";
		echo button::create(['type'=>'button','label'=>$text['button-download'],'icon'=>$_SESSION['theme']['button_icon_download'],'style'=>'margin-left: 15px;','link'=>'log_viewer.php?a=download&n='.basename($log_file)]);
?>