[pkg-nagios-changes] [Git][nagios-team/pkg-icingaweb2][upstream] New upstream version 2.8.3
Bas Couwenberg (@sebastic)
gitlab at salsa.debian.org
Wed Jul 14 20:38:37 BST 2021
Bas Couwenberg pushed to branch upstream at Debian Nagios Maintainer Group / pkg-icingaweb2
Commits:
86d06174 by Bas Couwenberg at 2021-07-14T21:17:47+02:00
New upstream version 2.8.3
- - - - -
26 changed files:
- CHANGELOG.md
- VERSION
- application/VERSION
- library/Icinga/Application/Version.php
- library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php
- library/Icinga/Protocol/Ldap/LdapQuery.php
- library/Icinga/Web/View/Helper/IcingaCheckbox.php
- modules/doc/application/controllers/ModuleController.php
- modules/doc/module.info
- modules/migrate/module.info
- modules/monitoring/application/controllers/ListController.php
- modules/monitoring/application/views/scripts/list/hosts.phtml
- modules/monitoring/application/views/scripts/list/services.phtml
- modules/monitoring/library/Monitoring/Backend/Ido/Query/HostgroupQuery.php
- modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php
- modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicegroupQuery.php
- modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicestatusQuery.php
- modules/monitoring/library/Monitoring/Controller.php
- + modules/monitoring/library/Monitoring/Data/CustomvarProtectionIterator.php
- modules/monitoring/library/Monitoring/Object/MonitoredObject.php
- modules/monitoring/module.info
- modules/setup/module.info
- modules/test/module.info
- modules/translation/module.info
- public/css/icinga/layout-structure.less
- public/css/icinga/menu.less
Changes:
=====================================
CHANGELOG.md
=====================================
@@ -4,6 +4,21 @@ Please make sure to always read our [Upgrading](doc/80-Upgrading.md) documentati
## What's New
+### What's New in Version 2.8.3
+
+**Notice**: This is a security release. It is recommended to upgrade to this release if you don't plan to upgrade to v2.9.0.
+
+You can find all fixes related to this release on our [Project](https://github.com/Icinga/icingaweb2/projects/7).
+
+#### Security Fixes
+
+This release includes two security related fixes. Both were published as part of a security advisory on Github.
+They allow the circumvention of custom variable protection rules and blacklists as well as a path traversal if
+the `doc` module is enabled. Please check the respective advisory for details.
+
+* Custom variable protection and blacklists can be circumvented [GHSA-2xv9-886q-p7xx](https://github.com/Icinga/icingaweb2/security/advisories/GHSA-2xv9-886q-p7xx)
+* Possible path traversal by use of the `doc` module [GHSA-cmgc-h4cx-3v43](https://github.com/Icinga/icingaweb2/security/advisories/GHSA-cmgc-h4cx-3v43)
+
### What's New in Version 2.8.2
**Notice**: This is a security release. It is recommended to immediately upgrade to this release.
=====================================
VERSION
=====================================
@@ -1 +1 @@
-v2.8.2
+v2.8.3
=====================================
application/VERSION
=====================================
@@ -1 +1 @@
-8a89839af94a247ee2149b2336c73b8251b477c0 2020-08-17 16:14:11 +0200
+479f990d5981354c05c362700117fe086cd048a9 2021-07-12 09:58:18 +0200
=====================================
library/Icinga/Application/Version.php
=====================================
@@ -8,7 +8,7 @@ namespace Icinga\Application;
*/
class Version
{
- const VERSION = '2.8.2';
+ const VERSION = '2.8.3';
/**
* Get the version of this instance of Icinga Web 2
=====================================
library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php
=====================================
@@ -654,6 +654,7 @@ class LdapUserGroupBackend extends LdapRepository implements Inspectable, UserGr
return $this->ds
->select()
->from('*', array($this->userNameAttribute))
+ ->setUnfoldAttribute($this->userNameAttribute)
->setBase($dn)
->fetchOne();
}
@@ -694,8 +695,8 @@ class LdapUserGroupBackend extends LdapRepository implements Inspectable, UserGr
public function requireQueryColumn($table, $name, RepositoryQuery $query = null)
{
$column = parent::requireQueryColumn($table, $name, $query);
- if ($name === 'user_name' && $query !== null) {
- $query->getQuery()->setUnfoldAttribute('user_name');
+ if (($name === 'user_name' || $name === 'group_name') && $query !== null) {
+ $query->getQuery()->setUnfoldAttribute($name);
}
return $column;
@@ -749,6 +750,7 @@ class LdapUserGroupBackend extends LdapRepository implements Inspectable, UserGr
$groupQuery = $this->ds
->select()
->from($this->groupClass, array($this->groupNameAttribute))
+ ->setUnfoldAttribute($this->groupNameAttribute)
->where($groupMemberAttribute, $queryValue)
->setBase($this->groupBaseDn);
if ($this->groupFilter) {
=====================================
library/Icinga/Protocol/Ldap/LdapQuery.php
=====================================
@@ -215,6 +215,41 @@ class LdapQuery extends SimpleQuery
}
}
+ public function compare($a, $b, $orderIndex = 0)
+ {
+ if (array_key_exists($orderIndex, $this->order)) {
+ $column = $this->order[$orderIndex][0];
+ $direction = $this->order[$orderIndex][1];
+
+ $flippedColumns = $this->flippedColumns ?: array_flip($this->columns);
+ if (array_key_exists($column, $flippedColumns) && is_string($flippedColumns[$column])) {
+ $column = $flippedColumns[$column];
+ }
+
+ if (is_array($a->$column)) {
+ // rfc2891 states: If a sort key is a multi-valued attribute, and an entry happens to
+ // have multiple values for that attribute and no other controls are
+ // present that affect the sorting order, then the server SHOULD use the
+ // least value (according to the ORDERING rule for that attribute).
+ $a = clone $a;
+ $a->$column = array_reduce($a->$column, function ($carry, $item) use ($direction) {
+ $result = $carry === null ? 0 : strcmp($item, $carry);
+ return ($direction === self::SORT_ASC ? $result : $result * -1) < 1 ? $item : $carry;
+ });
+ }
+
+ if (is_array($b->$column)) {
+ $b = clone $b;
+ $b->$column = array_reduce($b->$column, function ($carry, $item) use ($direction) {
+ $result = $carry === null ? 0 : strcmp($item, $carry);
+ return ($direction === self::SORT_ASC ? $result : $result * -1) < 1 ? $item : $carry;
+ });
+ }
+ }
+
+ return parent::compare($a, $b, $orderIndex);
+ }
+
/**
* Fetch result as tree
*
=====================================
library/Icinga/Web/View/Helper/IcingaCheckbox.php
=====================================
@@ -22,7 +22,8 @@ class IcingaCheckbox extends \Zend_View_Helper_FormCheckbox
return $html
. '<label for="'
. $attribs['id']
- . '" class="'
+ . '" aria-hidden="true"'
+ . ' class="'
. $class
. '"><span class="toggle-slider"></span></label>';
}
=====================================
modules/doc/application/controllers/ModuleController.php
=====================================
@@ -139,7 +139,7 @@ class ModuleController extends DocController
$image = $this->params->getRequired('image');
$docPath = $this->getPath($module, Icinga::app()->getModuleManager()->getModuleDir($module, '/doc'));
$imagePath = realpath($docPath . '/' . $image);
- if ($imagePath === false) {
+ if ($imagePath === false || substr($imagePath, 0, strlen($docPath)) !== $docPath) {
$this->httpNotFound('%s does not exist', $image);
}
=====================================
modules/doc/module.info
=====================================
@@ -1,4 +1,4 @@
Module: doc
-Version: 2.8.2
+Version: 2.8.3
Description: Documentation module
Extracts, shows and exports documentation for Icinga Web 2 and its modules.
=====================================
modules/migrate/module.info
=====================================
@@ -1,5 +1,5 @@
Module: migrate
-Version: 2.8.2
+Version: 2.8.3
Description: Migrate module
This module was introduced with the domain-aware authentication feature in version 2.5.0.
It helps you migrating users and user configurations according to a given domain.
=====================================
modules/monitoring/application/controllers/ListController.php
=====================================
@@ -4,6 +4,7 @@
namespace Icinga\Module\Monitoring\Controllers;
use Icinga\Security\SecurityException;
+use Icinga\Util\GlobFilter;
use Icinga\Web\Form;
use Zend_Form;
use Icinga\Data\Filter\Filter;
@@ -768,8 +769,31 @@ class ListController extends Controller
-1,
PREG_SPLIT_NO_EMPTY
);
- $this->view->addColumns = $columns;
- return $columns;
+
+ $customVars = [];
+ $additionalCols = [];
+ foreach ($columns as $column) {
+ if (preg_match('~^_(host|service)_([a-zA-Z0-9_]+)$~', $column, $m)) {
+ $customVars[$m[1]]['vars'][$m[2]] = null;
+ } else {
+ $additionalCols[] = $column;
+ }
+ }
+
+ if (! empty($customVars)) {
+ $blacklistedProperties = new GlobFilter(
+ $this->getRestrictions('monitoring/blacklist/properties')
+ );
+ $customVars = $blacklistedProperties->removeMatching($customVars);
+ foreach ($customVars as $type => $vars) {
+ foreach ($vars['vars'] as $var => $_) {
+ $additionalCols[] = '_' . $type . '_' . $var;
+ }
+ }
+ }
+
+ $this->view->addColumns = $additionalCols;
+ return $additionalCols;
}
protected function addTitleTab($action, $title, $tip)
=====================================
modules/monitoring/application/views/scripts/list/hosts.phtml
=====================================
@@ -92,7 +92,11 @@ if (! $this->compact): ?>
<p class="overview-plugin-output"><?= $this->pluginOutput($this->ellipsis($host->host_output, 10000), true, $host->host_check_command) ?></p>
</td>
<?php foreach($this->addColumns as $col): ?>
+ <?php if ($host->$col && preg_match('~^_(host|service)_([a-zA-Z0-9_]+)$~', $col, $m)): ?>
+ <td><?= $this->escape(\Icinga\Module\Monitoring\Object\MonitoredObject::protectCustomVars([$m[2] => $host->$col])[$m[2]]) ?></td>
+ <?php else: ?>
<td><?= $this->escape($host->$col) ?></td>
+ <?php endif ?>
<?php endforeach ?>
</tr>
<?php endforeach ?>
=====================================
modules/monitoring/application/views/scripts/list/services.phtml
=====================================
@@ -120,7 +120,11 @@ if (! $this->compact): ?>
</div>
</td>
<?php foreach($this->addColumns as $col): ?>
+ <?php if ($service->$col && preg_match('~^_(host|service)_([a-zA-Z0-9_]+)$~', $col, $m)): ?>
+ <td><?= $this->escape(\Icinga\Module\Monitoring\Object\MonitoredObject::protectCustomVars([$m[2] => $service->$col])[$m[2]]) ?></td>
+ <?php else: ?>
<td><?= $this->escape($service->$col) ?></td>
+ <?php endif ?>
<?php endforeach ?>
</tr>
<?php endforeach ?>
=====================================
modules/monitoring/library/Monitoring/Backend/Ido/Query/HostgroupQuery.php
=====================================
@@ -225,15 +225,15 @@ class HostgroupQuery extends IdoQuery
protected function joinServicegroups()
{
$this->requireVirtualTable('services');
- $this->select->join(
+ $this->select->joinLeft(
array('sgm' => $this->prefix . 'servicegroup_members'),
'sgm.service_object_id = s.service_object_id',
array()
- )->join(
+ )->joinLeft(
array('sg' => $this->prefix . 'servicegroups'),
'sgm.servicegroup_id = sg.servicegroup_id',
array()
- )->join(
+ )->joinLeft(
array('sgo' => $this->prefix . 'objects'),
'sgo.object_id = sg.servicegroup_object_id AND sgo.is_active = 1 AND sgo.objecttype_id = 4',
array()
@@ -246,11 +246,11 @@ class HostgroupQuery extends IdoQuery
protected function joinServices()
{
$this->requireVirtualTable('hosts');
- $this->select->join(
+ $this->select->joinLeft(
array('s' => $this->prefix . 'services'),
's.host_object_id = h.host_object_id',
array()
- )->join(
+ )->joinLeft(
array('so' => $this->prefix . 'objects'),
'so.object_id = s.service_object_id AND so.is_active = 1 AND so.objecttype_id = 2',
array()
=====================================
modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php
=====================================
@@ -17,6 +17,7 @@ use Icinga\Exception\ProgrammingError;
use Icinga\Exception\QueryException;
use Icinga\Web\Session;
use Icinga\Module\Monitoring\Data\ColumnFilterIterator;
+use Zend_Db_Select;
/**
* Base class for Ido Queries
@@ -1189,7 +1190,13 @@ abstract class IdoQuery extends DbQuery
{
// TODO: This is not generic enough yet
list($type, $name) = $this->customvarNameToTypeName($customvar);
- $alias = ($type === 'host' ? 'hcv_' : 'scv_') . $name;
+ $alias = ($type === 'host' ? 'hcv_' : 'scv_') . preg_replace('~[^a-zA-Z0-9_]~', '_', $name);
+
+ // We're replacing any problematic char with an underscore, which will lead to duplicates, this avoids them
+ $from = $this->select->getPart(Zend_Db_Select::FROM);
+ for ($i = 2; array_key_exists($alias, $from); $i++) {
+ $alias = $alias . '_' . $i;
+ }
$this->customVars[strtolower($customvar)] = $alias;
@@ -1228,7 +1235,7 @@ abstract class IdoQuery extends DbQuery
protected function customvarNameToTypeName($customvar)
{
$customvar = strtolower($customvar);
- if (! preg_match('~^_(host|service)_([a-zA-Z0-9_]+)$~', $customvar, $m)) {
+ if (! preg_match('~^_(host|service)_(.+)$~', $customvar, $m)) {
throw new ProgrammingError(
'Got invalid custom var: "%s"',
$customvar
=====================================
modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicegroupQuery.php
=====================================
@@ -192,15 +192,15 @@ class ServicegroupQuery extends IdoQuery
protected function joinHostgroups()
{
$this->requireVirtualTable('services');
- $this->select->join(
+ $this->select->joinLeft(
array('hgm' => $this->prefix . 'hostgroup_members'),
'hgm.host_object_id = s.host_object_id',
array()
- )->join(
+ )->joinLeft(
array('hg' => $this->prefix . 'hostgroups'),
'hg.hostgroup_id = hgm.hostgroup_id',
array()
- )->join(
+ )->joinLeft(
array('hgo' => $this->prefix . 'objects'),
'hgo.object_id = hg.hostgroup_object_id AND hgo.objecttype_id = 3 AND hgo.is_active = 1',
array()
=====================================
modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicestatusQuery.php
=====================================
@@ -21,7 +21,7 @@ class ServicestatusQuery extends IdoQuery
/**
* {@inheritdoc}
*/
- protected $groupOrigin = array('hostgroups', 'servicegroups');
+ protected $groupOrigin = array('hostgroups', 'servicegroups', 'contacts', 'contactgroups');
protected $subQueryTargets = array(
'hostgroups' => 'hostgroup',
=====================================
modules/monitoring/library/Monitoring/Controller.php
=====================================
@@ -3,11 +3,13 @@
namespace Icinga\Module\Monitoring;
+use ArrayIterator;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\QueryException;
use Icinga\Data\Filter\Filter;
use Icinga\Data\Filterable;
use Icinga\File\Csv;
+use Icinga\Module\Monitoring\Data\CustomvarProtectionIterator;
use Icinga\Util\Json;
use Icinga\Web\Controller as IcingaWebController;
use Icinga\Web\Url;
@@ -60,7 +62,15 @@ class Controller extends IcingaWebController
'Content-Disposition',
'inline; filename=' . $this->getRequest()->getActionName() . '.json'
)
- ->appendBody(Json::sanitize($query->fetchAll()))
+ ->appendBody(
+ Json::sanitize(
+ iterator_to_array(
+ new CustomvarProtectionIterator(
+ new ArrayIterator($query->fetchAll())
+ )
+ )
+ )
+ )
->sendResponse();
exit;
case 'csv':
@@ -72,7 +82,7 @@ class Controller extends IcingaWebController
'Content-Disposition',
'attachment; filename=' . $this->getRequest()->getActionName() . '.csv'
)
- ->appendBody((string) Csv::fromQuery($query))
+ ->appendBody((string) Csv::fromQuery(new CustomvarProtectionIterator($query)))
->sendResponse();
exit;
}
=====================================
modules/monitoring/library/Monitoring/Data/CustomvarProtectionIterator.php
=====================================
@@ -0,0 +1,25 @@
+<?php
+/* Icinga Web 2 | (c) 2021 Icinga GmbH | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Data;
+
+use Icinga\Module\Monitoring\Object\MonitoredObject;
+use IteratorIterator;
+
+class CustomvarProtectionIterator extends IteratorIterator
+{
+ const IS_CV_RE = '~^_(host|service)_([a-zA-Z0-9_]+)$~';
+
+ public function current()
+ {
+ $row = parent::current();
+
+ foreach ($row as $col => $val) {
+ if (preg_match(self::IS_CV_RE, $col, $m)) {
+ $row->$col = MonitoredObject::protectCustomVars([$m[2] => $val])[$m[2]];
+ }
+ }
+
+ return $row;
+ }
+}
=====================================
modules/monitoring/library/Monitoring/Object/MonitoredObject.php
=====================================
@@ -418,19 +418,6 @@ abstract class MonitoredObject implements Filterable
*/
public function fetchCustomvars()
{
- $blacklist = array();
- $blacklistPattern = '';
-
- if (($blacklistConfig = Config::module('monitoring')->get('security', 'protected_customvars', '')) !== '') {
- foreach (explode(',', $blacklistConfig) as $customvar) {
- $nonWildcards = array();
- foreach (explode('*', $customvar) as $nonWildcard) {
- $nonWildcards[] = preg_quote($nonWildcard, '/');
- }
- $blacklist[] = implode('.*', $nonWildcards);
- }
- $blacklistPattern = '/^(' . implode('|', $blacklist) . ')$/i';
- }
if ($this->type === self::TYPE_SERVICE) {
$this->fetchServiceVariables();
@@ -442,10 +429,7 @@ abstract class MonitoredObject implements Filterable
$this->customvars = $customvars;
$this->hideBlacklistedProperties();
-
- if ($blacklistPattern) {
- $this->customvars = $this->obfuscateCustomVars($this->customvars, $blacklistPattern);
- }
+ $this->customvars = $this->obfuscateCustomVars($this->customvars, null);
return $this;
}
@@ -454,22 +438,48 @@ abstract class MonitoredObject implements Filterable
* Obfuscate custom variables recursively
*
* @param stdClass|array $customvars The custom variables to obfuscate
- * @param string $blacklistPattern Which custom variables to obfuscate
*
* @return stdClass|array The obfuscated custom variables
*/
- protected function obfuscateCustomVars($customvars, $blacklistPattern)
+ protected function obfuscateCustomVars($customvars, $_)
{
- $obfuscatedCustomVars = array();
- foreach ($customvars as $name => $value) {
- if ($blacklistPattern && preg_match($blacklistPattern, $name)) {
- $obfuscatedCustomVars[$name] = '***';
- } else {
- $obfuscatedCustomVars[$name] = $value instanceof stdClass || is_array($value)
- ? $this->obfuscateCustomVars($value, $blacklistPattern)
- : $value;
+ return self::protectCustomVars($customvars);
+ }
+
+ public static function protectCustomVars($customvars)
+ {
+ $blacklist = [];
+ $blacklistPattern = '';
+
+ if (($blacklistConfig = Config::module('monitoring')->get('security', 'protected_customvars', '')) !== '') {
+ foreach (explode(',', $blacklistConfig) as $customvar) {
+ $nonWildcards = array();
+ foreach (explode('*', $customvar) as $nonWildcard) {
+ $nonWildcards[] = preg_quote($nonWildcard, '/');
+ }
+ $blacklist[] = implode('.*', $nonWildcards);
}
+ $blacklistPattern = '/^(' . implode('|', $blacklist) . ')$/i';
+ }
+
+ if (! $blacklistPattern) {
+ return $customvars;
}
+
+ $obfuscatedCustomVars = [];
+ $obfuscator = function ($vars) use ($blacklistPattern, &$obfuscatedCustomVars, &$obfuscator) {
+ foreach ($vars as $name => $value) {
+ if ($blacklistPattern && preg_match($blacklistPattern, $name)) {
+ $obfuscatedCustomVars[$name] = '***';
+ } else {
+ $obfuscatedCustomVars[$name] = $value instanceof stdClass || is_array($value)
+ ? $obfuscator($value)
+ : $value;
+ }
+ }
+ };
+ $obfuscator($customvars);
+
return $customvars instanceof stdClass ? (object) $obfuscatedCustomVars : $obfuscatedCustomVars;
}
=====================================
modules/monitoring/module.info
=====================================
@@ -1,5 +1,5 @@
Module: monitoring
-Version: 2.8.2
+Version: 2.8.3
Description: Icinga monitoring module
IDO accessor and UI for your monitoring. This is the initial instalment for a
graphical presentation of Icinga environments. The predecessor of Icinga DB.
=====================================
modules/setup/module.info
=====================================
@@ -1,5 +1,5 @@
Module: setup
-Version: 2.8.2
+Version: 2.8.3
Description: Setup module
Web based wizard for setting up Icinga Web 2 and its modules.
This includes the data backends (e.g. relational database, LDAP),
=====================================
modules/test/module.info
=====================================
@@ -1,5 +1,5 @@
Module: test
-Version: 2.8.2
+Version: 2.8.3
Description: Translation module
This module allows developers to run (unit) tests against Icinga Web 2 and
any of its modules. Usually you do not need to enable this.
=====================================
modules/translation/module.info
=====================================
@@ -1,5 +1,5 @@
Module: translation
-Version: 2.8.2
+Version: 2.8.3
Description: Translation module
This module allows developers and translators to translate Icinga Web 2 and
its modules for multiple languages. You do not need this module to run an
=====================================
public/css/icinga/layout-structure.less
=====================================
@@ -133,17 +133,20 @@ body {
/*
* Class to hide content from users but available for screen reader
- * @todo(mh): Replace .audible class
+ * Based on: https://cloudfour.com/thinks/see-no-evil-hidden-content-and-accessibility/
*/
.sr-only {
border: 0;
clip: rect(0 0 0 0);
+ clip-path: polygon(0px 0px, 0px 0px, 0px 0px);
+ -webkit-clip-path: polygon(0px 0px, 0px 0px, 0px 0px);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
- position: absolute;
+ position: fixed; // absolute causes view port glitches in chrome (#4310)
width: 1px;
+ white-space: nowrap;
}
// Hide non-javascript elements if javascript is enabled
=====================================
public/css/icinga/menu.less
=====================================
@@ -107,7 +107,7 @@
}
}
-ul:not(.nav-level-2) > .selected > a {
+#menu ul:not(.nav-level-2) > .selected > a {
background-color: @menu-highlight-color;
color: @text-color-inverted;
View it on GitLab: https://salsa.debian.org/nagios-team/pkg-icingaweb2/-/commit/86d061743b9c40448d1e349f64841fafe566d0c6
--
View it on GitLab: https://salsa.debian.org/nagios-team/pkg-icingaweb2/-/commit/86d061743b9c40448d1e349f64841fafe566d0c6
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-nagios-changes/attachments/20210714/f2bf4416/attachment-0001.htm>
More information about the pkg-nagios-changes
mailing list