Skip to content

Commit

Permalink
Fix XSS vulnerability related to list pagination
Browse files Browse the repository at this point in the history
Special thanks to Ulaş Deniz İlhan from Zigrin Security for discovering
and reporting this vulnerability.
  • Loading branch information
getdatakick committed Oct 8, 2023
1 parent f5b2c1e commit 2c99464
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 35 deletions.
18 changes: 7 additions & 11 deletions classes/controller/AdminController.php
Expand Up @@ -957,14 +957,15 @@ public function getList(
$this->ensureListIdDefinition();

/* Manage default params values */
$useLimit = true;
if ($limit === false) {
$useLimit = false;
} elseif (empty($limit)) {
if (isset($this->context->cookie->{$this->list_id.'_pagination'}) && $this->context->cookie->{$this->list_id.'_pagination'}) {
$limit = (int)$this->context->cookie->{$this->list_id.'_pagination'};
} else {
$useLimit = true;
$limit = HelperList::resolvePagination($this->list_id, $this->context->cookie, $this->_pagination, $this->_default_pagination);
if ($limit !== $this->_default_pagination) {
$this->context->cookie->{$this->list_id.'_pagination'} = $limit;
} else {
$limit = (int)$this->_default_pagination;
unset($this->context->cookie->{$this->list_id.'_pagination'});
}
}

Expand All @@ -975,12 +976,7 @@ public function getList(
$orderBy = $this->resolveOrderBy($orderBy);
$orderWay = $this->resolveOrderWay($orderWay);

$limit = Tools::getIntValue($this->list_id.'_pagination', $limit);
if (in_array($limit, $this->_pagination) && $limit != $this->_default_pagination) {
$this->context->cookie->{$this->list_id.'_pagination'} = $limit;
} else {
unset($this->context->cookie->{$this->list_id.'_pagination'});
}


/* Check params validity */
if (!Validate::isOrderBy($orderBy) || !Validate::isOrderWay($orderWay)) {
Expand Down
85 changes: 61 additions & 24 deletions classes/helper/HelperList.php
Expand Up @@ -309,42 +309,22 @@ public function displayListHeader()
}

/* Determine total page number */
$pagination = $this->_default_pagination;
$cookie = $this->context->cookie;
if (in_array(Tools::getIntValue($this->list_id.'_pagination'), $this->_pagination)) {
$pagination = Tools::getIntValue($this->list_id.'_pagination');
} elseif (isset($cookie->{$this->list_id.'_pagination'}) && $cookie->{$this->list_id.'_pagination'}) {
$pagination = $cookie->{$this->list_id.'_pagination'};
}

$pagination = $this->getSelectedPagination();
$totalPages = max(1, ceil($this->listTotal / $pagination));

$identifier = Tools::getIsset($this->identifier) ? '&'.$this->identifier.'='.Tools::getIntValue($this->identifier) : '';
// $order = '';
// if (Tools::getIsset($this->table.'Orderby')) {
// $order = '&'.$this->table.'Orderby='.urlencode($this->orderBy).'&'.$this->table.'Orderway='.urlencode(strtolower($this->orderWay));
// }

$action = $this->currentIndex.$identifier.'&token='.$token.'#'.$this->list_id;

/* Determine current page number */
$page = Tools::getIntValue('submitFilter'.$this->list_id);

if (!$page) {
if ($page <= 0) {
$page = 1;
}

if ($page > $totalPages) {
$page = $totalPages;
}

$this->page = (int) $page;

/* Choose number of results per page */
$selectedPagination = Tools::getValue(
$this->list_id.'_pagination',
$cookie->{$this->list_id . '_pagination'} ?? $this->_default_pagination
);
$this->page = (int)$page;

if (is_null($this->table_id) && $this->position_identifier && Tools::getIntValue($this->position_identifier, 1)) {
$this->table_id = substr($this->identifier, 3, strlen($this->identifier));
Expand All @@ -357,6 +337,7 @@ public function displayListHeader()
$prefix = str_replace(['admin', 'controller'], '', mb_strtolower((string)$this->controller_name));
$ajax = false;
$controller = $this->getController();
$cookie = $this->context->cookie;
foreach ($this->fields_list as $key => $params) {
if (!isset($params['type'])) {
$params['type'] = 'text';
Expand Down Expand Up @@ -441,7 +422,7 @@ public function displayListHeader()
'page' => $page,
'simple_header' => $this->simple_header,
'total_pages' => $totalPages,
'selected_pagination' => $selectedPagination,
'selected_pagination' => $this->getSelectedPagination(),
'pagination' => $this->_pagination,
'list_total' => $this->listTotal,
'sql' => str_replace('\n', ' ', str_replace('\r', '', (string)$this->sql)),
Expand Down Expand Up @@ -1022,4 +1003,60 @@ public function displayDefaultLink($token, $id, $name = null)

return $tpl->fetch();
}

/**
* @return int
*/
protected function getSelectedPagination()
{
return static::resolvePagination($this->list_id, $this->context->cookie, $this->_pagination, $this->_default_pagination);
}

/**
* @param string $listId
* @param Cookie $cookie
* @param array $pagination
* @param int $defaultPagination
*
* @return int
*/
public static function resolvePagination(string $listId, Cookie $cookie, array $pagination, int $defaultPagination)
{
if ($pagination) {
$value = static::resolvePaginationValue($listId, $cookie, $defaultPagination);
if (in_array($value, $pagination)) {
return $value;
}
if (in_array($defaultPagination, $pagination)) {
return $defaultPagination;
}
return $pagination[0];
} else {
trigger_error("Pagination not set for list $listId", E_USER_WARNING);
return 20;
}
}

/**
* @param string $listId
* @param Cookie $cookie
* @param int $defaultPagination
*
* @return int
*/
protected static function resolvePaginationValue(string $listId, Cookie $cookie, int $defaultPagination)
{
$paginationKey = $listId.'_pagination';
$pagination = Tools::getIntValue($paginationKey);
if ($pagination > 0) {
return $pagination;
}
if (isset($cookie->{$paginationKey})) {
$pagination = (int)$cookie->{$paginationKey};
if ($pagination > 0) {
return $pagination;
}
}
return $defaultPagination;
}
}

0 comments on commit 2c99464

Please sign in to comment.