Vulnerability: A cross-site scripting (XSS) vulnerability in app/dialplans/dialplans.php in FusionPBX 4.4.1 allows remote attackers to inject arbitrary web script or HTML via the app_uuid parameter.
Vulnerability ID: CVE-2019-19385
CWE: CWE-79
Severity score: 2.9
Project: https://github.com/fusionpbx/fusionpbx
Published: 2019-11-29
File: app/dialplans/dialplans.php
Commit message: Update dialplans.php
Commit author: FusionPBX

Vulnerable version (before fix):
  //get posted data 	if (is_array($_POST['dialplans'])) { 		$app_uuid = $_POST['app_uuid']; 		$action = $_POST['action']; 		$dialplans = $_POST['dialplans']; 		$search = $_POST['search']; 		$order_by = $_POST['order_by']; 		$order = $_POST['order']; 	}  //process action 	if ($action && is_array($dialplans) && @sizeof($dialplans) != 0) {  	$order_by = $_GET["order_by"]; 	$order = $_GET["order"];  //get the app uuid 	$app_uuid = $_GET["app_uuid"];  //make sure all dialplans with context of public have the inbound route app_uuid 	if ($app_uuid == 'c03b422e-13a8-bd1b-e42b-b6b9b4d27ce4') { 		$sql = "update v_dialplans set ";  //prepare the paging 	$rows_per_page = ($_SESSION['domain']['paging']['numeric'] != '') ? $_SESSION['domain']['paging']['numeric'] : 50; 	if (is_uuid($app_uuid)) { $params[] = "app_uuid=".$app_uuid; } 	if ($search) { $params[] = "search=".$search; } 	if ($order_by) { $params[] = "order_by=".$order_by; } 	if ($order) { $params[] = "order=".$order; } 	} 	echo 		"<input type='text' class='txt list-search' name='search' id='search' value=\"".escape($search)."\" placeholder=\"".$text['label-search']."\" onkeydown='list_search_reset();'>"; 	echo button::create(['label'=>$text['button-search'],'icon'=>$_SESSION['theme']['button_icon_search'],'type'=>'submit','id'=>'btn_search','style'=>($search != '' ? 'display: none;' : null)]); 	if (is_uuid($app_uuid)) { $params[] = "app_uuid=".urlencode($app_uuid); } 	if ($order_by) { $params[] = "order_by=".urlencode($order_by); } 	if ($order) { $params[] = "order=".urlencode($order); } 	if ($_GET['show'] && permission_exists('dialplan_all')) { $params[] = "show=".urlencode($_GET['show']); } 		foreach ($dialplans as $row) {  			//get the application id 			$app_uuid = $row['app_uuid'];  			// blank app id if doesn't match others, so will return to dialplan manager 			switch ($app_uuid) { //include the footer 	require_once "resources/footer.php";  ?>\ No newline at end of file

Fixed version (after fix):
  //get posted data 	if (is_array($_POST['dialplans'])) { 		$action = $_POST['action']; 		$dialplans = $_POST['dialplans']; 		$search = $_POST['search']; 		$order_by = $_POST['order_by']; 		$order = $_POST['order']; 	}  //get the app uuid 	if (is_uuid($_REQUEST["app_uuid"])) { 		$app_uuid = $_REQUEST["app_uuid"]; 	}  //process action 	if ($action && is_array($dialplans) && @sizeof($dialplans) != 0) {  	$order_by = $_GET["order_by"]; 	$order = $_GET["order"];  //make sure all dialplans with context of public have the inbound route app_uuid 	if ($app_uuid == 'c03b422e-13a8-bd1b-e42b-b6b9b4d27ce4') { 		$sql = "update v_dialplans set ";  //prepare the paging 	$rows_per_page = ($_SESSION['domain']['paging']['numeric'] != '') ? $_SESSION['domain']['paging']['numeric'] : 50; 	$params[] = "app_uuid=".$app_uuid; 	if ($search) { $params[] = "search=".$search; } 	if ($order_by) { $params[] = "order_by=".$order_by; } 	if ($order) { $params[] = "order=".$order; } 	} 	echo 		"<input type='text' class='txt list-search' name='search' id='search' value=\"".escape($search)."\" placeholder=\"".$text['label-search']."\" onkeydown='list_search_reset();'>"; 	echo button::create(['label'=>$text['button-search'],'icon'=>$_SESSION['theme']['button_icon_search'],'type'=>'submit','id'=>'btn_search','style'=>($search != '' ? 'display: none;' : null)]); 	$params[] = "app_uuid=".urlencode($app_uuid); 	if ($order_by) { $params[] = "order_by=".urlencode($order_by); } 	if ($order) { $params[] = "order=".urlencode($order); } 	if ($_GET['show'] && permission_exists('dialplan_all')) { $params[] = "show=".urlencode($_GET['show']); } 		foreach ($dialplans as $row) {  			//get the application id 			if (is_uuid($row['app_uuid'])) { 				$app_uuid = $row['app_uuid']; 			}  			// blank app id if doesn't match others, so will return to dialplan manager 			switch ($app_uuid) { //include the footer 	require_once "resources/footer.php"; \ No newline at end of file ?>

Patch:
patch: @@ -45,14 +45,18 @@
 
 //get posted data
 	if (is_array($_POST['dialplans'])) {
-		$app_uuid = $_POST['app_uuid'];
 		$action = $_POST['action'];
 		$dialplans = $_POST['dialplans'];
 		$search = $_POST['search'];
 		$order_by = $_POST['order_by'];
 		$order = $_POST['order'];
 	}
 
+//get the app uuid
+	if (is_uuid($_REQUEST["app_uuid"])) {
+		$app_uuid = $_REQUEST["app_uuid"];
+	}
+
 //process action
 	if ($action && is_array($dialplans) && @sizeof($dialplans) != 0) {
 
@@ -98,9 +102,6 @@
 	$order_by = $_GET["order_by"];
 	$order = $_GET["order"];
 
-//get the app uuid
-	$app_uuid = $_GET["app_uuid"];
-
 //make sure all dialplans with context of public have the inbound route app_uuid
 	if ($app_uuid == 'c03b422e-13a8-bd1b-e42b-b6b9b4d27ce4') {
 		$sql = "update v_dialplans set ";
@@ -161,7 +162,7 @@
 
 //prepare the paging
 	$rows_per_page = ($_SESSION['domain']['paging']['numeric'] != '') ? $_SESSION['domain']['paging']['numeric'] : 50;
-	if (is_uuid($app_uuid)) { $params[] = "app_uuid=".$app_uuid; }
+	$params[] = "app_uuid=".$app_uuid;
 	if ($search) { $params[] = "search=".$search; }
 	if ($order_by) { $params[] = "order_by=".$order_by; }
 	if ($order) { $params[] = "order=".$order; }
@@ -283,7 +284,7 @@
 	}
 	echo 		"<input type='text' class='txt list-search' name='search' id='search' value=\"".escape($search)."\" placeholder=\"".$text['label-search']."\" onkeydown='list_search_reset();'>";
 	echo button::create(['label'=>$text['button-search'],'icon'=>$_SESSION['theme']['button_icon_search'],'type'=>'submit','id'=>'btn_search','style'=>($search != '' ? 'display: none;' : null)]);
-	if (is_uuid($app_uuid)) { $params[] = "app_uuid=".urlencode($app_uuid); }
+	$params[] = "app_uuid=".urlencode($app_uuid);
 	if ($order_by) { $params[] = "order_by=".urlencode($order_by); }
 	if ($order) { $params[] = "order=".urlencode($order); }
 	if ($_GET['show'] && permission_exists('dialplan_all')) { $params[] = "show=".urlencode($_GET['show']); }
@@ -356,7 +357,9 @@
 		foreach ($dialplans as $row) {
 
 			//get the application id
-			$app_uuid = $row['app_uuid'];
+			if (is_uuid($row['app_uuid'])) {
+				$app_uuid = $row['app_uuid'];
+			}
 
 			// blank app id if doesn't match others, so will return to dialplan manager
 			switch ($app_uuid) {
@@ -459,4 +462,4 @@
 //include the footer
 	require_once "resources/footer.php";
 
-?>
\ No newline at end of file
+?>
path: app/dialplans/dialplans.php