mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-07-25 14:54:24 +02:00
Merge pull request from GHSA-2xv9-886q-p7xx
Fix that custom variable protection and blacklists can be circumvented
This commit is contained in:
commit
7abb62976a
@ -4,6 +4,7 @@
|
|||||||
namespace Icinga\Module\Monitoring\Controllers;
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
use Icinga\Security\SecurityException;
|
use Icinga\Security\SecurityException;
|
||||||
|
use Icinga\Util\GlobFilter;
|
||||||
use Icinga\Web\Form;
|
use Icinga\Web\Form;
|
||||||
use Zend_Form;
|
use Zend_Form;
|
||||||
use Icinga\Data\Filter\Filter;
|
use Icinga\Data\Filter\Filter;
|
||||||
@ -761,8 +762,31 @@ class ListController extends Controller
|
|||||||
-1,
|
-1,
|
||||||
PREG_SPLIT_NO_EMPTY
|
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)
|
protected function addTitleTab($action, $title, $tip)
|
||||||
|
@ -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>
|
<p class="overview-plugin-output"><?= $this->pluginOutput($this->ellipsis($host->host_output, 10000), true, $host->host_check_command) ?></p>
|
||||||
</td>
|
</td>
|
||||||
<?php foreach($this->addColumns as $col): ?>
|
<?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>
|
<td><?= $this->escape($host->$col) ?></td>
|
||||||
|
<?php endif ?>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
@ -120,7 +120,11 @@ if (! $this->compact): ?>
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<?php foreach($this->addColumns as $col): ?>
|
<?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>
|
<td><?= $this->escape($service->$col) ?></td>
|
||||||
|
<?php endif ?>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
@ -3,11 +3,13 @@
|
|||||||
|
|
||||||
namespace Icinga\Module\Monitoring;
|
namespace Icinga\Module\Monitoring;
|
||||||
|
|
||||||
|
use ArrayIterator;
|
||||||
use Icinga\Exception\ConfigurationError;
|
use Icinga\Exception\ConfigurationError;
|
||||||
use Icinga\Exception\QueryException;
|
use Icinga\Exception\QueryException;
|
||||||
use Icinga\Data\Filter\Filter;
|
use Icinga\Data\Filter\Filter;
|
||||||
use Icinga\Data\Filterable;
|
use Icinga\Data\Filterable;
|
||||||
use Icinga\File\Csv;
|
use Icinga\File\Csv;
|
||||||
|
use Icinga\Module\Monitoring\Data\CustomvarProtectionIterator;
|
||||||
use Icinga\Util\Json;
|
use Icinga\Util\Json;
|
||||||
use Icinga\Web\Controller as IcingaWebController;
|
use Icinga\Web\Controller as IcingaWebController;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
@ -60,7 +62,15 @@ class Controller extends IcingaWebController
|
|||||||
'Content-Disposition',
|
'Content-Disposition',
|
||||||
'inline; filename=' . $this->getRequest()->getActionName() . '.json'
|
'inline; filename=' . $this->getRequest()->getActionName() . '.json'
|
||||||
)
|
)
|
||||||
->appendBody(Json::sanitize($query->fetchAll()))
|
->appendBody(
|
||||||
|
Json::sanitize(
|
||||||
|
iterator_to_array(
|
||||||
|
new CustomvarProtectionIterator(
|
||||||
|
new ArrayIterator($query->fetchAll())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
->sendResponse();
|
->sendResponse();
|
||||||
exit;
|
exit;
|
||||||
case 'csv':
|
case 'csv':
|
||||||
@ -72,7 +82,7 @@ class Controller extends IcingaWebController
|
|||||||
'Content-Disposition',
|
'Content-Disposition',
|
||||||
'attachment; filename=' . $this->getRequest()->getActionName() . '.csv'
|
'attachment; filename=' . $this->getRequest()->getActionName() . '.csv'
|
||||||
)
|
)
|
||||||
->appendBody((string) Csv::fromQuery($query))
|
->appendBody((string) Csv::fromQuery(new CustomvarProtectionIterator($query)))
|
||||||
->sendResponse();
|
->sendResponse();
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -418,7 +418,37 @@ abstract class MonitoredObject implements Filterable
|
|||||||
*/
|
*/
|
||||||
public function fetchCustomvars()
|
public function fetchCustomvars()
|
||||||
{
|
{
|
||||||
$blacklist = array();
|
|
||||||
|
if ($this->type === self::TYPE_SERVICE) {
|
||||||
|
$this->fetchServiceVariables();
|
||||||
|
$customvars = $this->serviceVariables;
|
||||||
|
} else {
|
||||||
|
$this->fetchHostVariables();
|
||||||
|
$customvars = $this->hostVariables;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->customvars = $customvars;
|
||||||
|
$this->hideBlacklistedProperties();
|
||||||
|
$this->customvars = $this->obfuscateCustomVars($this->customvars, null);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obfuscate custom variables recursively
|
||||||
|
*
|
||||||
|
* @param stdClass|array $customvars The custom variables to obfuscate
|
||||||
|
*
|
||||||
|
* @return stdClass|array The obfuscated custom variables
|
||||||
|
*/
|
||||||
|
protected function obfuscateCustomVars($customvars, $_)
|
||||||
|
{
|
||||||
|
return self::protectCustomVars($customvars);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function protectCustomVars($customvars)
|
||||||
|
{
|
||||||
|
$blacklist = [];
|
||||||
$blacklistPattern = '';
|
$blacklistPattern = '';
|
||||||
|
|
||||||
if (($blacklistConfig = Config::module('monitoring')->get('security', 'protected_customvars', '')) !== '') {
|
if (($blacklistConfig = Config::module('monitoring')->get('security', 'protected_customvars', '')) !== '') {
|
||||||
@ -432,44 +462,24 @@ abstract class MonitoredObject implements Filterable
|
|||||||
$blacklistPattern = '/^(' . implode('|', $blacklist) . ')$/i';
|
$blacklistPattern = '/^(' . implode('|', $blacklist) . ')$/i';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->type === self::TYPE_SERVICE) {
|
if (! $blacklistPattern) {
|
||||||
$this->fetchServiceVariables();
|
return $customvars;
|
||||||
$customvars = $this->serviceVariables;
|
|
||||||
} else {
|
|
||||||
$this->fetchHostVariables();
|
|
||||||
$customvars = $this->hostVariables;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->customvars = $customvars;
|
$obfuscatedCustomVars = [];
|
||||||
$this->hideBlacklistedProperties();
|
$obfuscator = function ($vars) use ($blacklistPattern, &$obfuscatedCustomVars, &$obfuscator) {
|
||||||
|
foreach ($vars as $name => $value) {
|
||||||
if ($blacklistPattern) {
|
if ($blacklistPattern && preg_match($blacklistPattern, $name)) {
|
||||||
$this->customvars = $this->obfuscateCustomVars($this->customvars, $blacklistPattern);
|
$obfuscatedCustomVars[$name] = '***';
|
||||||
}
|
} else {
|
||||||
|
$obfuscatedCustomVars[$name] = $value instanceof stdClass || is_array($value)
|
||||||
return $this;
|
? $obfuscator($value)
|
||||||
}
|
: $value;
|
||||||
|
}
|
||||||
/**
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
$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;
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
$obfuscator($customvars);
|
||||||
|
|
||||||
return $customvars instanceof stdClass ? (object) $obfuscatedCustomVars : $obfuscatedCustomVars;
|
return $customvars instanceof stdClass ? (object) $obfuscatedCustomVars : $obfuscatedCustomVars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user