Compare commits

...

4 Commits

Author SHA1 Message Date
Benjamin DALSASS
43121a5a4b N°9379 - PHP unserialze function - security hardening
- typo
2026-04-09 16:34:35 +02:00
Benjamin DALSASS
ff2f10e5b6 N°9379 - PHP unserialze function - security hardening
- ormcaselog index
2026-04-09 15:26:49 +02:00
Benjamin DALSASS
ddaf014898 N°9379 - PHP unserialze function - security hardening
- Ensure shortcut doen't contain php objects, otherwise delete shortcut
2026-04-09 14:59:06 +02:00
Benjamin DALSASS
a71fefa328 N°9379 - PHP unserialze function - security hardening
- Create an unserialze function encapsulation
- Ensure data table settings doesn't contain php objects, otherwise revert to default settings
2026-04-09 08:31:41 +02:00
4 changed files with 79 additions and 4 deletions

View File

@@ -1546,7 +1546,16 @@ class ShortcutMenuNode extends MenuNode
public function GetHyperlink($aExtraParams)
{
$sContext = $this->oShortcut->Get('context');
$aContext = unserialize($sContext);
try {
$aContext = utils::Unserialize($sContext, ['allowed_classes' => false]);
} catch (Exception $e) {
IssueLog::Warning("User shortcut corrupted, delete the shortcut", LogChannels::CONSOLE, [
'shortcut_name' => $this->oShortcut->GetName(),
'root_cause' => $e->getMessage(),
]);
// delete the shortcut
$this->oShortcut->DBDelete();
}
if (isset($aContext['menu'])) {
unset($aContext['menu']);
}

View File

@@ -3252,4 +3252,50 @@ TXT
return $aTrace;
}
/**
* PHP unserialize encapsulation, allow throwing exception when not allowed object class is detected (for security hardening)
*
* @param mixed $data data to unserialize
* @param array $aOptions PHP @unserialise options
* @param bool $bThrowNotAllowedObjectClassException flag to throw exception
*
* @return mixed PHP @unserialise return
* @throws Exception
*/
public static function Unserialize(mixed $data, array $aOptions, bool $bThrowNotAllowedObjectClassException = true): mixed
{
$data = unserialize($data, $aOptions);
if ($bThrowNotAllowedObjectClassException) {
try {
self::AssertNoIncompleteClassDetected($data);
} catch (Exception $e) {
throw new CoreException('Unserialization failed because an incomplete class was detected.', [], '', $e);
}
}
return $data;
}
/**
* Assert that data provided doesn't contain any incomplete class.
*
* @throws Exception
*/
public static function AssertNoIncompleteClassDetected(mixed $data): void
{
if (is_object($data)) {
if ($data instanceof __PHP_Incomplete_Class) {
throw new Exception('__PHP_Incomplete_Class_Name object detected');
}
foreach (get_object_vars($data) as $property) {
self::AssertNoIncompleteClassDetected($property);
}
} elseif (is_array($data)) {
foreach ($data as $value) {
self::AssertNoIncompleteClassDetected($value);
}
}
}
}

View File

@@ -4829,7 +4829,7 @@ class AttributeCaseLog extends AttributeLongText
}
if (strlen($sIndex) > 0) {
$aIndex = unserialize($sIndex);
$aIndex = utils::Unserialize($sIndex, ['allowed_classes' => false], false);
$value = new ormCaseLog($sLog, $aIndex);
} else {
$value = new ormCaseLog($sLog);

View File

@@ -8,8 +8,13 @@ use AttributeFriendlyName;
use AttributeLinkedSet;
use cmdbAbstract;
use cmdbAbstractObject;
use CoreException;
use Dict;
use Exception;
use IssueLog;
use LogChannels;
use Metamodel;
use utils;
/**
* Class DataTableSettings
@@ -130,7 +135,10 @@ class DataTableSettings
*/
public function unserialize($sData)
{
$aData = unserialize($sData);
$aData = utils::Unserialize($sData, ['allowed_classes' => false]);
if (!is_array($aData)) {
throw new CoreException('Wrong data table settings format, expected an array', ['datatable_settings_data' => $aData]);
}
$this->iDefaultPageSize = $aData['iDefaultPageSize'];
$this->aColumns = $aData['aColumns'];
foreach ($this->aClassAliases as $sAlias => $sClass) {
@@ -269,7 +277,19 @@ class DataTableSettings
return null;
}
}
$oSettings->unserialize($pref);
try {
$oSettings->unserialize($pref);
} catch (Exception $e) {
IssueLog::Warning("User table settings corrupted, back to the default values provided by the data model", LogChannels::CONSOLE, [
'table_id' => $sTableId,
'root_cause' => $e->getMessage(),
]);
// unset the preference
appUserPreferences::UnsetPref($oSettings->GetPrefsKey($sTableId));
// use the default values provided by the data model
return null;
}
return $oSettings;
}