CVE-2018-12642 (PHP, published 2018-06-22T12:29Z)
Description: value: Froxlor through 0.9.39.5 has Incorrect Access Control for tickets not owned by the current user.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-732 \u2014 Incorrect Permission Assignment for Critical Resource
The product specifies permissions for a security-critical resource in a way that allows that resource to be read or modified by unintended actors.
Repository: https://github.com/Froxlor/Froxlor
Files changed:
customer_tickets.php
lib/classes/ticket/class.ticket.php
Commit message: deny access to tickets not owned by current user, thx to chbi

Signed-off-by: Michael Kaufmann <michael.kaufmann@aixit.com>


Vulnerable code:
			$replyticket = ticket::getInstanceOf($userinfo, -1);
			$mainticket = ticket::getInstanceOf($userinfo, (int)$id);
			$mainticket = ticket::getInstanceOf($userinfo, (int)$id);
			$mainticket = ticket::getInstanceOf($userinfo, (int)$id);
		$mainticket = ticket::getInstanceOf($userinfo, (int)$id);

class ticket {
	 * @var tid
	 * @var t_data
	 * @var tickets
	static private $tickets = array();
	 * @param array userinfo
	 * @param int ticket id
	private function __construct($userinfo, $tid = - 1) {


	 * @param array userinfo
	 * @param int ticket id
	static public function getInstanceOf($_usernfo, $_tid) {
		if (!isset(self::$tickets[$_tid])) {
			self::$tickets[$_tid] = new ticket($_usernfo, $_tid);
		return self::$tickets[$_tid];
	private function initData() {

	private function readData() {

		if (isset($this->tid)
			&& $this->tid != - 1
		) {
			$_ticket_stmt = Database::prepare('
				SELECT * FROM `' . TABLE_PANEL_TICKETS . '` WHERE `id` = :tid'
			);
			$_ticket = Database::pexecute_first($_ticket_stmt, array('tid' => $this->tid));

	public function Insert() {

                `answerto` = :answerto"
		);
	public function Update() {

                WHERE `id` = :tid'
		);
	public function Archive() {

			UPDATE `' . TABLE_PANEL_TICKETS . '` SET `archived` = "1" WHERE `id` = :tid'
		);
		Database::pexecute($upd_stmt, array('tid' => $this->tid));

			UPDATE `' . TABLE_PANEL_TICKETS . '` SET `archived` = "1" WHERE `answerto` = :tid'
		);
		Database::pexecute($upd_stmt, array('tid' => $this->tid));
	public function Delete() {

			DELETE FROM `' . TABLE_PANEL_TICKETS . '` WHERE `id` = :tid'
		);
		Database::pexecute($del_stmt, array('tid' => $this->tid));

			DELETE FROM `' . TABLE_PANEL_TICKETS . '` WHERE `answerto` = :tid'
		);
		Database::pexecute($del_stmt, array('tid' => $this->tid));

				FROM `' . TABLE_PANEL_CUSTOMERS . '` WHERE `customerid` = :customerid'
			);
			$usr = Database::pexecute_first($usr_stmt, array('customerid' => $customerid));

			AND `templategroup`= 'mails' AND `varname`= :tplsubject"
		);


			AND `templategroup`= 'mails' AND `varname`= :tplmailbody"
		);

			} catch(phpmailerException $e) {

				$rstlog = FroxlorLogger::getInstanceOf(array('loginname' => 'ticket_class'));


				WHERE `adminid` = :adminid"
			);
			$admin = Database::pexecute_first($admin_stmt, array('adminid' => $this->userinfo['adminid']));
			} catch(phpmailerException $e) {

				$rstlog = FroxlorLogger::getInstanceOf(array('loginname' => 'ticket_class'));

	static public function addCategory($_category = null, $_admin = 1, $_order = 1) {

		if ($_category != null
			&& $_category != ''
		) {

					`logicalorder` = :lo"
			);
	static public function editCategory($_category = null, $_id = 0, $_order = 1) {

		if ($_category != null
			&& $_category != ''
			&& $_id != 0
		) {

			Database::pexecute($upd_stmt, array('name' => $_category, 'lo' => $_order, 'id' => $_id));
	static public function deleteCategory($_id = 0) {


				WHERE `category` = :cat"
			);
			$result = Database::pexecute_first($result_stmt, array('cat' => $_id));

					DELETE FROM `" . TABLE_PANEL_TICKET_CATS . "` WHERE `id` = :id"
				);
				Database::pexecute($del_stmt, array('id' => $_id));

	static public function getCategoryName($_id = 0) {

				SELECT `name` FROM `" . TABLE_PANEL_TICKET_CATS . "` WHERE `id` = :id"
			);
			$category = Database::pexecute_first($stmt, array('id' => $_id));
	 * 
	 * @param object $_uid admin-id (optional)
	 * 
	static public function getHighestOrderNumber($_uid = 0) {

		$sql = "SELECT MAX(`logicalorder`) as `highestorder` FROM `" . TABLE_PANEL_TICKET_CATS . "`".$where.";";
		return (isset($result['highestorder']) ? (int)$result['highestorder'] : 0);
	static public function getLastArchived($_num = 10, $_admin = 1) {


				ORDER BY `main`.`lastchange` DESC LIMIT 0, ".(int)$_num
			);
			Database::pexecute($result_stmt, array('adminid' => $_admin));


				$counter++;


			WHERE `main`.`archived` = '1' AND `main`.`adminid` = :admin"
		;


		if ($subject != NULL
			&& $subject != ''
		) {
			$search_params['subject'] = "%".$subject."%";

		if ($priority != null
			&& isset($priority[0])
			&& $priority[0] != ''
		) {

			if (isset($priority[1])
				&& $priority[1] != ''
			) {

				if (isset($priority[2])
					&& $priority[2] != ''
				) {




			} elseif (isset($priority[2])
				&& $priority[2] != ''
			) {



		} elseif($priority != null
			&& isset($priority[1])
			&& $priority[1] != ''
		) {
			if (isset($priority[2])
				&& $priority[2] != ''
			) {

		} elseif($priority != null) {

			if (isset($priority[3])
				&& $priority[3] != ''
			) {

		if ($fromdate != null
			&& $fromdate > 0
		) {

		if ($todate != null
			&& $todate > 0
		) {

		if ($message != null
			&& $message != ''
		) {
			$search_params['message'] = "%".$message."%";





					$query .= "`main`.`category` = :catid_".$catid." OR ";
					$search_params['catid_'.$catid] = $catid;


		return array('0' => $query, '1' => $search_params);
		switch($_status)
		{
		switch($_priority)
		{
		$html_entities = array (
					"Ä" =>  "&Auml;",
					"ä" =>  "&auml;",
					"Ö" =>  "&Ouml;",
					"ö" =>  "&ouml;",
					"Ü" =>  "&Uuml;",
					"ü" =>  "&uuml;",
					"ß" =>  "&szlig;"
					/*
					 * @TODO continue this table for all the special-characters
					 */

	 * @param	int		customer-id
	 *
	 * @return	array/bool	array of ticket-ids if customer has any, else false
	static public function customerHasTickets($_cid = 0) {

				SELECT `id` FROM `" . TABLE_PANEL_TICKETS . "` WHERE `customerid` = :cid"
			);
			Database::pexecute($result_stmt, array('cid' => $_cid));



	public function Get($_var = '', $_vartrusted = false) {

			if (!$_vartrusted) {

				} elseif(strtolower($_var) == 'subject') {
	public function Set($_var = '', $_value = '', $_vartrusted = false, $_valuetrusted = false) {

		if ($_var != ''
			&& $_value != ''
		) {
			if (!$_vartrusted) {

			if (!$_valuetrusted) {

			if (strtolower($_var) == 'message'
				|| strtolower($_var) == 'subject'
			) {


Fixed code:
			try {
				$replyticket = ticket::getInstanceOf($userinfo, -1);
			} catch(Exception $e) {
				standard_error($e->getMessage());
			}
			try {
				$mainticket = ticket::getInstanceOf($userinfo, (int)$id);
			} catch(Exception $e) {
				standard_error($e->getMessage());
			}
			try {
				$mainticket = ticket::getInstanceOf($userinfo, (int)$id);
			} catch(Exception $e) {
				standard_error($e->getMessage());
			}
			try {
				$mainticket = ticket::getInstanceOf($userinfo, (int)$id);
			} catch(Exception $e) {
				standard_error($e->getMessage());
			}
		try {
			$mainticket = ticket::getInstanceOf($userinfo, (int)$id);
		} catch(Exception $e) {
			standard_error($e->getMessage());
		}
class ticket
{
	 *
	 *
	 * @var int
	 *
	 * @var array
	 *
	 * @var ticket
	private static $tickets = array();
	 * @param
	 *        	array userinfo
	 * @param
	 *        	int ticket id
	private function __construct($userinfo, $tid = - 1)
	{
		
		
	 * @param
	 *        	array userinfo
	 * @param
	 *        	int ticket id
	static public function getInstanceOf($_usernfo, $_tid)
	{
		if (! isset(self::$tickets[$_tid . '-' . $_usernfo['userid']])) {
			self::$tickets[$_tid . '-' . $_usernfo['userid']] = new ticket($_usernfo, $_tid);
		return self::$tickets[$_tid . '-' . $_usernfo['userid']];
	private function initData()
	{
	private function readData()
	{
		if (isset($this->tid) && $this->tid != - 1) {
			
			if ($this->userinfo['customerid'] > 0) {
				$_ticket_stmt = Database::prepare('
					SELECT * FROM `' . TABLE_PANEL_TICKETS . '` WHERE `id` = :tid AND `customerid` = :cid');
				$tdata = array(
					'tid' => $this->tid,
					'cid' => $this->userinfo['customerid']
				);
			} else {
				$_ticket_stmt = Database::prepare('
					SELECT * FROM `' . TABLE_PANEL_TICKETS . '` WHERE `id` = :tid' . ($this->userinfo['customers_see_all'] ? '' : ' AND `adminid` = :adminid'));
				$tdata = array(
					'tid' => $this->tid
				);
				if ($this->userinfo['customers_see_all'] != '1') {
					$tdata['adminid'] = $this->userinfo['adminid'];
				}
			}
			$_ticket = Database::pexecute_first($_ticket_stmt, $tdata);
			
			if ($_ticket == false) {
				throw new Exception("Invalid ticket id");
			}
			
	public function Insert()
	{
                `answerto` = :answerto");
	public function Update()
	{
		
                WHERE `id` = :tid');
	public function Archive()
	{
		
			UPDATE `' . TABLE_PANEL_TICKETS . '` SET `archived` = "1" WHERE `id` = :tid');
		Database::pexecute($upd_stmt, array(
			'tid' => $this->tid
		));
		
			UPDATE `' . TABLE_PANEL_TICKETS . '` SET `archived` = "1" WHERE `answerto` = :tid');
		Database::pexecute($upd_stmt, array(
			'tid' => $this->tid
		));
	public function Delete()
	{
		
			DELETE FROM `' . TABLE_PANEL_TICKETS . '` WHERE `id` = :tid');
		Database::pexecute($del_stmt, array(
			'tid' => $this->tid
		));
		
			DELETE FROM `' . TABLE_PANEL_TICKETS . '` WHERE `answerto` = :tid');
		Database::pexecute($del_stmt, array(
			'tid' => $this->tid
		));
		
				FROM `' . TABLE_PANEL_CUSTOMERS . '` WHERE `customerid` = :customerid');
			$usr = Database::pexecute_first($usr_stmt, array(
				'customerid' => $customerid
			));
			
			AND `templategroup`= 'mails' AND `varname`= :tplsubject");
		
		
			AND `templategroup`= 'mails' AND `varname`= :tplmailbody");
		
			} catch (phpmailerException $e) {
			
				$rstlog = FroxlorLogger::getInstanceOf(array(
					'loginname' => 'ticket_class'
				));
			
				WHERE `adminid` = :adminid");
			$admin = Database::pexecute_first($admin_stmt, array(
				'adminid' => $this->userinfo['adminid']
			));
			} catch (phpmailerException $e) {
			
				$rstlog = FroxlorLogger::getInstanceOf(array(
					'loginname' => 'ticket_class'
				));
			
	static public function addCategory($_category = null, $_admin = 1, $_order = 1)
	{
		if ($_category != null && $_category != '') {
			
					`logicalorder` = :lo");
	static public function editCategory($_category = null, $_id = 0, $_order = 1)
	{
		if ($_category != null && $_category != '' && $_id != 0) {
			
			Database::pexecute($upd_stmt, array(
				'name' => $_category,
				'lo' => $_order,
				'id' => $_id
			));
	static public function deleteCategory($_id = 0)
	{
			
				WHERE `category` = :cat");
			$result = Database::pexecute_first($result_stmt, array(
				'cat' => $_id
			));
			
					DELETE FROM `" . TABLE_PANEL_TICKET_CATS . "` WHERE `id` = :id");
				Database::pexecute($del_stmt, array(
					'id' => $_id
				));
		
	static public function getCategoryName($_id = 0)
	{
				SELECT `name` FROM `" . TABLE_PANEL_TICKET_CATS . "` WHERE `id` = :id");
			$category = Database::pexecute_first($stmt, array(
				'id' => $_id
			));
	 *
	 * @param object $_uid
	 *        	admin-id (optional)
	 *        	
	static public function getHighestOrderNumber($_uid = 0)
	{
		$sql = "SELECT MAX(`logicalorder`) as `highestorder` FROM `" . TABLE_PANEL_TICKET_CATS . "`" . $where . ";";
		return (isset($result['highestorder']) ? (int) $result['highestorder'] : 0);
	static public function getLastArchived($_num = 10, $_admin = 1)
	{
			
				ORDER BY `main`.`lastchange` DESC LIMIT 0, " . (int) $_num);
			Database::pexecute($result_stmt, array(
				'adminid' => $_admin
			));
			
				
				$counter ++;
			
		
			WHERE `main`.`archived` = '1' AND `main`.`adminid` = :admin";
		
		
		if ($subject != NULL && $subject != '') {
			$search_params['subject'] = "%" . $subject . "%";
		
		if ($priority != null && isset($priority[0]) && $priority[0] != '') {
			
			if (isset($priority[1]) && $priority[1] != '') {
				
				if (isset($priority[2]) && $priority[2] != '') {
					
					
			} elseif (isset($priority[2]) && $priority[2] != '') {
				
		} elseif ($priority != null && isset($priority[1]) && $priority[1] != '') {
			if (isset($priority[2]) && $priority[2] != '') {
		} elseif ($priority != null) {
			
			if (isset($priority[3]) && $priority[3] != '') {
		
		if ($fromdate != null && $fromdate > 0) {
		
		if ($todate != null && $todate > 0) {
		
		if ($message != null && $message != '') {
			$search_params['message'] = "%" . $message . "%";
		
		
			
			
			
					$query .= "`main`.`category` = :catid_" . $catid . " OR ";
					$search_params['catid_' . $catid] = $catid;
			
		
		return array(
			'0' => $query,
			'1' => $search_params
		);
		switch ($_status) {
		switch ($_priority) {
		$html_entities = array(
			"Ä" => "&Auml;",
			"ä" => "&auml;",
			"Ö" => "&Ouml;",
			"ö" => "&ouml;",
			"Ü" => "&Uuml;",
			"ü" => "&uuml;",
			"ß" => "&szlig;"
			/*
		 * @TODO continue this table for all the special-characters
		 */
		
	 * @param
	 *        	int customer-id
	 *        	
	 * @return array/bool array of ticket-ids if customer has any, else false
	static public function customerHasTickets($_cid = 0)
	{
				SELECT `id` FROM `" . TABLE_PANEL_TICKETS . "` WHERE `customerid` = :cid");
			Database::pexecute($result_stmt, array(
				'cid' => $_cid
			));
			
			
		
	public function Get($_var = '', $_vartrusted = false)
	{
			if (! $_vartrusted) {
			
				} elseif (strtolower($_var) == 'subject') {
	public function Set($_var = '', $_value = '', $_vartrusted = false, $_valuetrusted = false)
	{
		if ($_var != '' && $_value != '') {
			if (! $_vartrusted) {
			
			if (! $_valuetrusted) {
			
			if (strtolower($_var) == 'message' || strtolower($_var) == 'subject') {