Compare commits

...

6 Commits

Author SHA1 Message Date
bdalsass
13239c2751 N°8201 - [CVE_Request]_Cross-Site-Script Reflected(XSS Reflected at the name="attr_installed" (Low or Medium) 2025-05-23 10:06:01 +02:00
bdalsass
81b20ee583 N°8168 - Stored XSS in portals lnk 2025-05-23 08:42:56 +02:00
bdalsass
38683c20b1 N°8313 - edit dashboard (fix broken test) 2025-05-16 14:05:55 +02:00
bdalsass
81791dd253 N°8313 - edit dashboard 2025-05-16 14:05:55 +02:00
bdalsass
e77e0eec9f N°8355 - render_dashboard 2025-05-16 14:05:55 +02:00
jf-cbd
960133c0df N°8379 - fix backup issue 2025-05-13 16:27:59 +02:00
9 changed files with 37 additions and 51 deletions

View File

@@ -529,10 +529,7 @@ EOF
*/ */
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true) public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
{ {
if (!array_key_exists('dashboard_div_id', $aExtraParams)) $aExtraParams['dashboard_div_id'] = utils::Sanitize($aExtraParams['dashboard_div_id'] ?? null, $this->GetId(), utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER);
{
$aExtraParams['dashboard_div_id'] = utils::Sanitize($this->GetId(), '', 'element_identifier');
}
$oPage->add('<div class="dashboard-title-line"><div class="dashboard-title">'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</div></div>'); $oPage->add('<div class="dashboard-title-line"><div class="dashboard-title">'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</div></div>');
@@ -1002,7 +999,7 @@ EOF
$sSelectorHtml .= '</div>'; $sSelectorHtml .= '</div>';
$sSelectorHtml = addslashes($sSelectorHtml); $sSelectorHtml = addslashes($sSelectorHtml);
$sFile = addslashes($this->GetDefinitionFile()); $sFile = addslashes($this->GetDefinitionFile());
$sReloadURL = $this->GetReloadURL(); $sReloadURL = json_encode($this->GetReloadURL());
$oPage->add_ready_script( $oPage->add_ready_script(
<<<EOF <<<EOF
@@ -1059,7 +1056,7 @@ EOF
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.iframe-transport.js'); $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.iframe-transport.js');
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.fileupload.js'); $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.fileupload.js');
$sEditMenu = "<div id=\"DashboardMenu\"><ul><li><i class=\"top-right-icon icon-additional-arrow fas fa-pencil-alt\"></i><ul>"; $sEditMenu = "<div id=\"DashboardMenu\"><ul><li><i class=\"top-right-icon icon-additional-arrow fas fa-pencil-alt\"></i><ul>";
$aActions = array(); $aActions = array();
$sFile = addslashes($this->sDefinitionFile); $sFile = addslashes($this->sDefinitionFile);
$sJSExtraParams = json_encode($aExtraParams); $sJSExtraParams = json_encode($aExtraParams);
@@ -1091,6 +1088,7 @@ EOF
EOF EOF
); );
$sReloadURL = json_encode($this->GetReloadURL());
$oPage->add_script( $oPage->add_script(
<<<EOF <<<EOF
function EditDashboard(sId, sDashboardFile, aExtraParams) function EditDashboard(sId, sDashboardFile, aExtraParams)
@@ -1188,7 +1186,7 @@ EOF
$oPage->add('</div>'); $oPage->add('</div>');
$oPage->add('<div id="event_bus"/>'); // For exchanging messages between the panes, same as in the designer $oPage->add('<div id="event_bus"/>'); // For exchanging messages between the panes, same as in the designer
$oPage->add('</div>'); $oPage->add('</div>');
$sDialogTitle = Dict::S('UI:DashboardEdit:Title'); $sDialogTitle = Dict::S('UI:DashboardEdit:Title');
$sOkButtonLabel = Dict::S('UI:Button:Save'); $sOkButtonLabel = Dict::S('UI:Button:Save');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel'); $sCancelButtonLabel = Dict::S('UI:Button:Cancel');
@@ -1200,7 +1198,7 @@ EOF
$sTitle = json_encode($this->sTitle); $sTitle = json_encode($this->sTitle);
$sFile = json_encode($this->GetDefinitionFile()); $sFile = json_encode($this->GetDefinitionFile());
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php'; $sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
$sReloadURL = $this->GetReloadURL(); $sReloadURL = json_encode($this->GetReloadURL());
$sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage')); $sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage'));
$sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage')); $sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage'));

View File

@@ -432,8 +432,8 @@ class utils
// For URL // For URL
case static::ENUM_SANITIZATION_FILTER_URL: case static::ENUM_SANITIZATION_FILTER_URL:
// N°6350 - returns only valid URLs $retValue = filter_var($value, FILTER_SANITIZE_URL);
$retValue = filter_var($value, FILTER_VALIDATE_URL); $retValue = filter_var($retValue, FILTER_VALIDATE_URL);
break; break;
default: default:

View File

@@ -53,14 +53,7 @@ class DBRestore extends DBBackup
$sUser = self::EscapeShellArg($this->sDBUser); $sUser = self::EscapeShellArg($this->sDBUser);
$sPwd = self::EscapeShellArg($this->sDBPwd); $sPwd = self::EscapeShellArg($this->sDBPwd);
$sDBName = self::EscapeShellArg($this->sDBName); $sDBName = self::EscapeShellArg($this->sDBName);
if (empty($this->sMySQLBinDir)) $sMySQLExe = DBBackup::MakeSafeMySQLCommand($this->sMySQLBinDir, 'mysql');
{
$sMySQLExe = 'mysql';
}
else
{
$sMySQLExe = '"'.$this->sMySQLBinDir.'/mysql"';
}
if (is_null($this->iDBPort)) if (is_null($this->iDBPort))
{ {
$sPortOption = ''; $sPortOption = '';

View File

@@ -56,15 +56,7 @@ try
// //
$sMySQLBinDir = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', ''); $sMySQLBinDir = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', '');
$sMySQLBinDir = utils::ReadParam('mysql_bindir', $sMySQLBinDir, true); $sMySQLBinDir = utils::ReadParam('mysql_bindir', $sMySQLBinDir, true);
if (empty($sMySQLBinDir)) $sMySQLDump = DBBackup::MakeSafeMySQLCommand($sMySQLBinDir, 'mysqldump');
{
$sMySQLDump = 'mysqldump';
}
else
{
//echo 'Info - Found mysql_bindir: '.$sMySQLBinDir;
$sMySQLDump = '"'.$sMySQLBinDir.'/mysqldump"';
}
$sCommand = "$sMySQLDump -V 2>&1"; $sCommand = "$sMySQLDump -V 2>&1";
$aOutput = array(); $aOutput = array();

View File

@@ -1989,7 +1989,7 @@ catch(CoreException $e)
{ {
$oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n"); $oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
} }
$oP->error(Dict::Format('UI:Error_Details', $e->getHtmlDesc())); $oP->error(Dict::Format('UI:Error_Details', Str::pure2html($e->getHtmlDesc())));
$oP->output(); $oP->output();
if (MetaModel::IsLogEnabledIssue()) if (MetaModel::IsLogEnabledIssue())
@@ -2025,7 +2025,7 @@ catch(Exception $e)
require_once(APPROOT.'/setup/setuppage.class.inc.php'); require_once(APPROOT.'/setup/setuppage.class.inc.php');
$oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError')); $oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
$oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n"); $oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
$oP->error(Dict::Format('UI:Error_Details', $e->getMessage())); $oP->error(Dict::Format('UI:Error_Details', Str::pure2html($e->getMessage())));
$oP->output(); $oP->output();
if (MetaModel::IsLogEnabledIssue()) if (MetaModel::IsLogEnabledIssue())

View File

@@ -104,6 +104,8 @@ class DBBackup
/** @var string */ /** @var string */
protected $sDBName; protected $sDBName;
/** @var string */ /** @var string */
protected $sMySQLBinDir = '';
/** @var string */
protected $sDBSubName; protected $sDBSubName;
/** /**
@@ -131,7 +133,6 @@ class DBBackup
$this->sDBSubName = $oConfig->get('db_subname'); $this->sDBSubName = $oConfig->get('db_subname');
} }
protected $sMySQLBinDir = '';
/** /**
* Create a normalized backup name, depending on the current date/time and Database * Create a normalized backup name, depending on the current date/time and Database
@@ -299,8 +300,9 @@ class DBBackup
} }
$this->LogInfo("Starting backup of $this->sDBHost/$this->sDBName(suffix:'$this->sDBSubName')"); $this->LogInfo("Starting backup of $this->sDBHost/$this->sDBName(suffix:'$this->sDBSubName')");
$sMySQLBinDir = utils::ReadParam('mysql_bindir', $this->sMySQLBinDir, true);
$sMySQLDump = $this->GetMysqldumpCommand(); $sMySQLDump = $this->MakeSafeMySQLCommand($sMySQLBinDir, 'mysqldump');
// Store the results in a temporary file // Store the results in a temporary file
$sTmpFileName = self::EscapeShellArg($sBackupFileName); $sTmpFileName = self::EscapeShellArg($sBackupFileName);
@@ -557,20 +559,22 @@ EOF;
/** /**
* @return string the command to launch mysqldump (without its params) * @return string the command to launch mysqldump (without its params)
* @throws \BackupException
*/ */
private function GetMysqldumpCommand() public static function MakeSafeMySQLCommand($sMySQLBinDir, string $sCmd)
{ {
$sMySQLBinDir = utils::ReadParam('mysql_bindir', $this->sMySQLBinDir, true); if (empty($sMySQLBinDir)) {
if (empty($sMySQLBinDir)) $sMySQLCommand = $sCmd;
{
$sMysqldumpCommand = 'mysqldump';
} }
else else {
{ $sMySQLBinDir = escapeshellcmd($sMySQLBinDir);
$sMysqldumpCommand = '"'.$sMySQLBinDir.'/mysqldump"'; $sMySQLCommand = '"'.$sMySQLBinDir.'/$sCmd"';
if (!file_exists($sMySQLCommand)) {
throw new BackupException("$sCmd not found in $sMySQLBinDir");
}
} }
return $sMysqldumpCommand; return $sMySQLCommand;
} }
} }

View File

@@ -484,16 +484,15 @@ class SetupUtils
{ {
$sMySQLBinDir = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', ''); $sMySQLBinDir = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', '');
} }
try {
if (empty($sMySQLBinDir)) $sMySQLDump = DBBackup::MakeSafeMySQLCommand($sMySQLBinDir, 'mysqldump');
{ } catch (Exception $e) {
$sMySQLDump = 'mysqldump'; $aResult[] = new CheckResult(CheckResult::ERROR, $e->getMessage());
} return $aResult;
else
{
SetupPage::log('Info - Found mysql_bindir: '.$sMySQLBinDir);
$sMySQLDump = '"'.$sMySQLBinDir.'/mysqldump"';
} }
if (!empty($sMySQLBinDir)) {
SetupPage::log('Info - Found mysql_bindir: '.$sMySQLBinDir);
}
$sCommand = "$sMySQLDump -V 2>&1"; $sCommand = "$sMySQLDump -V 2>&1";
$aOutput = array(); $aOutput = array();

View File

@@ -611,7 +611,7 @@ JS
if ($oAttDef->IsExternalKey()) if ($oAttDef->IsExternalKey())
{ {
/** @var \AttributeExternalKey $oAttDef */ /** @var \AttributeExternalKey $oAttDef */
$aAttProperties['value'] = $oRemoteItem->Get($sAttCode . '_friendlyname'); $aAttProperties['value'] = \Str::pure2html($oRemoteItem->Get($sAttCode . '_friendlyname'));
// Checking if user can access object's external key // Checking if user can access object's external key
$sObjectUrl = ApplicationContext::MakeObjectUrl($oAttDef->GetTargetClass(), $oRemoteItem->Get($sAttCode)); $sObjectUrl = ApplicationContext::MakeObjectUrl($oAttDef->GetTargetClass(), $oRemoteItem->Get($sAttCode));

View File

@@ -495,7 +495,7 @@ class utilsTest extends ItopTestCase
'good element_identifier' => ['element_identifier', 'AD05nb', 'AD05nb'], 'good element_identifier' => ['element_identifier', 'AD05nb', 'AD05nb'],
'bad element_identifier' => ['element_identifier', 'AD05nb+', 'AD05nb'], 'bad element_identifier' => ['element_identifier', 'AD05nb+', 'AD05nb'],
'good url' => ['url', 'https://www.w3schools.com', 'https://www.w3schools.com'], 'good url' => ['url', 'https://www.w3schools.com', 'https://www.w3schools.com'],
'bad url' => ['url', 'https://www.w3schoo<EFBFBD><EFBFBD>ls.co<EFBFBD>m', null], 'bad url' => ['url', 'https//www.w3schools.com', null],
'raw_data' => ['raw_data', '<Test>\s😃😃😃', '<Test>\s😃😃😃'], 'raw_data' => ['raw_data', '<Test>\s😃😃😃', '<Test>\s😃😃😃'],
]; ];
} }