From 0103f48c86ca1a15a3c6326a0a913cb5395681d1 Mon Sep 17 00:00:00 2001 From: Benni Mack <benni@typo3.org> Date: Tue, 23 Feb 2016 11:45:30 +0100 Subject: [PATCH] [SECURITY] XML entity expansion Remote XML entites can be loaded in places where TYPO3 expects only local files to be fetched. All places are changed so the option to load entities is disabled. Resolves: #61269 Releases: master, 7.6, 6.2 Security-Commit: 736a7ef0823893047843c6a7f5e72b220bfd4697 Security-Bulletins: TYPO3-CORE-SA-2016-005, 006, 007, 008 Change-Id: I26701fc2ffb5aed7ccbd96c168aef571d012091e Reviewed-on: https://review.typo3.org/46834 Reviewed-by: Oliver Hader <oliver.hader@typo3.org> Tested-by: Oliver Hader <oliver.hader@typo3.org> --- typo3/sysext/adodb/Documentation/Index.rst | 2 ++ typo3/sysext/adodb/adodb/adodb-xmlschema.inc.php | 6 ++++++ typo3/sysext/adodb/adodb/adodb-xmlschema03.inc.php | 6 ++++++ .../core/Classes/Imaging/IconProvider/SvgIconProvider.php | 3 +++ .../core/Classes/Localization/Parser/AbstractXmlParser.php | 6 +++++- .../core/Classes/Localization/Parser/LocallangXmlParser.php | 6 +++++- typo3/sysext/core/Classes/Type/File/ImageInfo.php | 6 +++++- typo3/sysext/core/Classes/Utility/GeneralUtility.php | 6 ++++++ typo3/sysext/core/Tests/FunctionalTestCase.php | 6 +++++- .../documentation/Classes/Service/DocumentationService.php | 3 +++ .../Classes/Utility/Parser/ExtensionXmlPushParser.php | 3 +++ .../Classes/Utility/Parser/MirrorXmlPushParser.php | 3 +++ typo3/sysext/lang/Classes/Service/TerService.php | 3 +++ .../Tests/Functional/Recycle/AbstractRecycleTestCase.php | 6 +++++- .../Classes/Controller/SpellCheckingController.php | 3 +++ .../rtehtmlarea/Classes/Extension/MicroDataSchema.php | 3 +++ typo3/sysext/t3editor/Classes/TypoScriptReferenceLoader.php | 3 +++ 17 files changed, 69 insertions(+), 5 deletions(-) diff --git a/typo3/sysext/adodb/Documentation/Index.rst b/typo3/sysext/adodb/Documentation/Index.rst index d1ef0980c579..a3bae0d49d9a 100644 --- a/typo3/sysext/adodb/Documentation/Index.rst +++ b/typo3/sysext/adodb/Documentation/Index.rst @@ -25,6 +25,7 @@ updated to upstream. - ADOdb: Allow setting NOT NULL/DEFAULT on blob and text columns (67442_) (Upstream pull request: [3]_) - ADOdb: Table names in sequences broken (64990_) - ADOdb: PHP7 redefinition of parameter (71244_) +- Security: XML entity expansion (61269_) .. [2] https://github.com/ADOdb/ADOdb/commit/85f05a98974ea85ecae943faf230a27afdbaa746 .. [3] https://github.com/ADOdb/ADOdb/pull/118 @@ -38,6 +39,7 @@ updated to upstream. .. _67442: https://forge.typo3.org/issues/67442 .. _64990: https://forge.typo3.org/issues/64990 .. _71244: https://forge.typo3.org/issues/71244 +.. _61269: https://forge.typo3.org/issues/61269 Diff diff --git a/typo3/sysext/adodb/adodb/adodb-xmlschema.inc.php b/typo3/sysext/adodb/adodb/adodb-xmlschema.inc.php index 72a9f9bc757e..fc2c5bc9b9fc 100644 --- a/typo3/sysext/adodb/adodb/adodb-xmlschema.inc.php +++ b/typo3/sysext/adodb/adodb/adodb-xmlschema.inc.php @@ -1456,6 +1456,8 @@ class adoSchema { $this->success = 2; $xmlParser = $this->create_parser(); + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); // Process the file while( $data = fread( $fp, 4096 ) ) { @@ -1468,6 +1470,7 @@ class adoSchema { } } + libxml_disable_entity_loader($previousValueOfEntityLoader); xml_parser_free( $xmlParser ); return $this->sqlArray; @@ -1502,6 +1505,8 @@ class adoSchema { $this->success = 2; $xmlParser = $this->create_parser(); + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); if( !xml_parse( $xmlParser, $xmlstring, TRUE ) ) { die( sprintf( @@ -1511,6 +1516,7 @@ class adoSchema { ) ); } + libxml_disable_entity_loader($previousValueOfEntityLoader); xml_parser_free( $xmlParser ); return $this->sqlArray; diff --git a/typo3/sysext/adodb/adodb/adodb-xmlschema03.inc.php b/typo3/sysext/adodb/adodb/adodb-xmlschema03.inc.php index 3ed5aecbe07f..ba190e7aeafd 100644 --- a/typo3/sysext/adodb/adodb/adodb-xmlschema03.inc.php +++ b/typo3/sysext/adodb/adodb/adodb-xmlschema03.inc.php @@ -1612,6 +1612,8 @@ class adoSchema { $this->success = 2; $xmlParser = $this->create_parser(); + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); // Process the file while( $data = fread( $fp, 4096 ) ) { @@ -1624,6 +1626,7 @@ class adoSchema { } } + libxml_disable_entity_loader($previousValueOfEntityLoader); xml_parser_free( $xmlParser ); return $this->sqlArray; @@ -1659,6 +1662,8 @@ class adoSchema { $this->success = 2; $xmlParser = $this->create_parser(); + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); if( !xml_parse( $xmlParser, $xmlstring, TRUE ) ) { die( sprintf( @@ -1668,6 +1673,7 @@ class adoSchema { ) ); } + libxml_disable_entity_loader($previousValueOfEntityLoader); xml_parser_free( $xmlParser ); return $this->sqlArray; diff --git a/typo3/sysext/core/Classes/Imaging/IconProvider/SvgIconProvider.php b/typo3/sysext/core/Classes/Imaging/IconProvider/SvgIconProvider.php index d4cf6f2dcb89..8e1e5e543870 100644 --- a/typo3/sysext/core/Classes/Imaging/IconProvider/SvgIconProvider.php +++ b/typo3/sysext/core/Classes/Imaging/IconProvider/SvgIconProvider.php @@ -93,7 +93,10 @@ class SvgIconProvider implements IconProviderInterface $svgContent = file_get_contents($source); $svgContent = preg_replace('/<script[\s\S]*?>[\s\S]*?<\/script>/i', '', $svgContent); + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); $svgElement = simplexml_load_string($svgContent); + libxml_disable_entity_loader($previousValueOfEntityLoader); // remove xml version tag $domXml = dom_import_simplexml($svgElement); diff --git a/typo3/sysext/core/Classes/Localization/Parser/AbstractXmlParser.php b/typo3/sysext/core/Classes/Localization/Parser/AbstractXmlParser.php index 801c44e58555..bbd5bbdad715 100644 --- a/typo3/sysext/core/Classes/Localization/Parser/AbstractXmlParser.php +++ b/typo3/sysext/core/Classes/Localization/Parser/AbstractXmlParser.php @@ -91,7 +91,11 @@ abstract class AbstractXmlParser implements LocalizationParserInterface */ protected function parseXmlFile() { - $rootXmlNode = simplexml_load_file($this->sourcePath, 'SimpleXMLElement', LIBXML_NOWARNING); + $xmlContent = file_get_contents($this->sourcePath); + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); + $rootXmlNode = simplexml_load_string($xmlContent, 'SimpleXMLElement', LIBXML_NOWARNING); + libxml_disable_entity_loader($previousValueOfEntityLoader); if (!isset($rootXmlNode) || $rootXmlNode === false) { throw new InvalidXmlFileException('The path provided does not point to existing and accessible well-formed XML file.', 1278155988); } diff --git a/typo3/sysext/core/Classes/Localization/Parser/LocallangXmlParser.php b/typo3/sysext/core/Classes/Localization/Parser/LocallangXmlParser.php index 328c09c53d7d..d00f8beefbdb 100644 --- a/typo3/sysext/core/Classes/Localization/Parser/LocallangXmlParser.php +++ b/typo3/sysext/core/Classes/Localization/Parser/LocallangXmlParser.php @@ -167,7 +167,11 @@ class LocallangXmlParser extends AbstractXmlParser { $rootXmlNode = false; if (file_exists($targetPath)) { - $rootXmlNode = simplexml_load_file($targetPath, 'SimpleXMLElement', LIBXML_NOWARNING); + $xmlContent = file_get_contents($targetPath); + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); + $rootXmlNode = simplexml_load_string($xmlContent, 'SimpleXMLElement', LIBXML_NOWARNING); + libxml_disable_entity_loader($previousValueOfEntityLoader); } if (!isset($rootXmlNode) || $rootXmlNode === false) { throw new InvalidXmlFileException('The path provided does not point to existing and accessible well-formed XML file (' . $targetPath . ').', 1278155987); diff --git a/typo3/sysext/core/Classes/Type/File/ImageInfo.php b/typo3/sysext/core/Classes/Type/File/ImageInfo.php index ef82186fecf0..faddaba1e34a 100644 --- a/typo3/sysext/core/Classes/Type/File/ImageInfo.php +++ b/typo3/sysext/core/Classes/Type/File/ImageInfo.php @@ -86,7 +86,11 @@ class ImageInfo extends FileInfo { $imagesSizes = array(); - $xml = simplexml_load_file($this->getPathname()); + $fileContent = file_get_contents($this->getPathname()); + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); + $xml = simplexml_load_string($fileContent); + libxml_disable_entity_loader($previousValueOfEntityLoader); $xmlAttributes = $xml->attributes(); // First check if width+height are set diff --git a/typo3/sysext/core/Classes/Utility/GeneralUtility.php b/typo3/sysext/core/Classes/Utility/GeneralUtility.php index 767729e79bb3..7c5600bb5523 100755 --- a/typo3/sysext/core/Classes/Utility/GeneralUtility.php +++ b/typo3/sysext/core/Classes/Utility/GeneralUtility.php @@ -1647,6 +1647,8 @@ class GeneralUtility */ public static function xml2tree($string, $depth = 999, $parserOptions = array()) { + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); $parser = xml_parser_create(); $vals = array(); $index = array(); @@ -1656,6 +1658,7 @@ class GeneralUtility xml_parser_set_option($parser, $option, $value); } xml_parse_into_struct($parser, $string, $vals, $index); + libxml_disable_entity_loader($previousValueOfEntityLoader); if (xml_get_error_code($parser)) { return 'Line ' . xml_get_current_line_number($parser) . ': ' . xml_error_string(xml_get_error_code($parser)); } @@ -1895,6 +1898,8 @@ class GeneralUtility */ protected static function xml2arrayProcess($string, $NSprefix = '', $reportDocTag = false) { + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); // Create parser: $parser = xml_parser_create(); $vals = array(); @@ -1909,6 +1914,7 @@ class GeneralUtility xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $theCharset); // Parse content: xml_parse_into_struct($parser, $string, $vals, $index); + libxml_disable_entity_loader($previousValueOfEntityLoader); // If error, return error message: if (xml_get_error_code($parser)) { return 'Line ' . xml_get_current_line_number($parser) . ': ' . xml_error_string(xml_get_error_code($parser)); diff --git a/typo3/sysext/core/Tests/FunctionalTestCase.php b/typo3/sysext/core/Tests/FunctionalTestCase.php index 1c629245765d..b5a26ec15e23 100644 --- a/typo3/sysext/core/Tests/FunctionalTestCase.php +++ b/typo3/sysext/core/Tests/FunctionalTestCase.php @@ -277,7 +277,11 @@ abstract class FunctionalTestCase extends BaseTestCase $database = $this->getDatabaseConnection(); - $xml = simplexml_load_file($path); + $fileContent = file_get_contents($path); + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); + $xml = simplexml_load_string($fileContent); + libxml_disable_entity_loader($previousValueOfEntityLoader); $foreignKeys = array(); /** @var $table \SimpleXMLElement */ diff --git a/typo3/sysext/documentation/Classes/Service/DocumentationService.php b/typo3/sysext/documentation/Classes/Service/DocumentationService.php index 680bc11da6d4..ce74975dd665 100644 --- a/typo3/sysext/documentation/Classes/Service/DocumentationService.php +++ b/typo3/sysext/documentation/Classes/Service/DocumentationService.php @@ -245,7 +245,10 @@ class DocumentationService */ protected function parsePackagesXML($string) { + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); $data = json_decode(json_encode((array)simplexml_load_string($string)), true); + libxml_disable_entity_loader($previousValueOfEntityLoader); if (count($data) !== 2) { throw new \TYPO3\CMS\Documentation\Exception\XmlParser('Error in XML parser while decoding packages XML file.', 1374222437); } diff --git a/typo3/sysext/extensionmanager/Classes/Utility/Parser/ExtensionXmlPushParser.php b/typo3/sysext/extensionmanager/Classes/Utility/Parser/ExtensionXmlPushParser.php index 68daf102db14..3a20d88d6ef3 100644 --- a/typo3/sysext/extensionmanager/Classes/Utility/Parser/ExtensionXmlPushParser.php +++ b/typo3/sysext/extensionmanager/Classes/Utility/Parser/ExtensionXmlPushParser.php @@ -69,6 +69,8 @@ class ExtensionXmlPushParser extends AbstractExtensionXmlParser if (!is_resource($this->objXml)) { throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException('Unable to create XML parser.', 1342640663); } + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); // keep original character case of XML document xml_parser_set_option($this->objXml, XML_OPTION_CASE_FOLDING, false); xml_parser_set_option($this->objXml, XML_OPTION_SKIP_WHITE, false); @@ -83,6 +85,7 @@ class ExtensionXmlPushParser extends AbstractExtensionXmlParser throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException(sprintf('XML error %s in line %u of file resource %s.', xml_error_string(xml_get_error_code($this->objXml)), xml_get_current_line_number($this->objXml), $file), 1342640703); } } + libxml_disable_entity_loader($previousValueOfEntityLoader); xml_parser_free($this->objXml); } diff --git a/typo3/sysext/extensionmanager/Classes/Utility/Parser/MirrorXmlPushParser.php b/typo3/sysext/extensionmanager/Classes/Utility/Parser/MirrorXmlPushParser.php index f21b95ba5cfb..3e77f43b1da9 100644 --- a/typo3/sysext/extensionmanager/Classes/Utility/Parser/MirrorXmlPushParser.php +++ b/typo3/sysext/extensionmanager/Classes/Utility/Parser/MirrorXmlPushParser.php @@ -64,6 +64,8 @@ class MirrorXmlPushParser extends AbstractMirrorXmlParser if (!is_resource($this->objXml)) { throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException('Unable to create XML parser.', 1342641009); } + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); // keep original character case of XML document xml_parser_set_option($this->objXml, XML_OPTION_CASE_FOLDING, false); xml_parser_set_option($this->objXml, XML_OPTION_SKIP_WHITE, false); @@ -78,6 +80,7 @@ class MirrorXmlPushParser extends AbstractMirrorXmlParser throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException(sprintf('XML error %s in line %u of file resource %s.', xml_error_string(xml_get_error_code($this->objXml)), xml_get_current_line_number($this->objXml), $file), 1342641011); } } + libxml_disable_entity_loader($previousValueOfEntityLoader); xml_parser_free($this->objXml); } diff --git a/typo3/sysext/lang/Classes/Service/TerService.php b/typo3/sysext/lang/Classes/Service/TerService.php index 75595baf7c89..2fbd29548041 100644 --- a/typo3/sysext/lang/Classes/Service/TerService.php +++ b/typo3/sysext/lang/Classes/Service/TerService.php @@ -59,12 +59,15 @@ class TerService extends TerUtility implements SingletonInterface { // Create parser: $parser = xml_parser_create(); + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); $values = array(); $index = array(); xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0); // Parse content xml_parse_into_struct($parser, $string, $values, $index); + libxml_disable_entity_loader($previousValueOfEntityLoader); // If error, return error message if (xml_get_error_code($parser)) { $line = xml_get_current_line_number($parser); diff --git a/typo3/sysext/recycler/Tests/Functional/Recycle/AbstractRecycleTestCase.php b/typo3/sysext/recycler/Tests/Functional/Recycle/AbstractRecycleTestCase.php index b197e0ade0f6..11eed511da09 100644 --- a/typo3/sysext/recycler/Tests/Functional/Recycle/AbstractRecycleTestCase.php +++ b/typo3/sysext/recycler/Tests/Functional/Recycle/AbstractRecycleTestCase.php @@ -92,7 +92,11 @@ abstract class AbstractRecycleTestCase extends \TYPO3\CMS\Core\Tests\FunctionalT } $data = array(); - $xml = simplexml_load_file($path); + $fileContent = file_get_contents($path); + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); + $xml = simplexml_load_string($fileContent); + libxml_disable_entity_loader($previousValueOfEntityLoader); /** @var $table \SimpleXMLElement */ foreach ($xml->children() as $table) { diff --git a/typo3/sysext/rtehtmlarea/Classes/Controller/SpellCheckingController.php b/typo3/sysext/rtehtmlarea/Classes/Controller/SpellCheckingController.php index 1babffbfefde..2fdc2aa5f78d 100644 --- a/typo3/sysext/rtehtmlarea/Classes/Controller/SpellCheckingController.php +++ b/typo3/sysext/rtehtmlarea/Classes/Controller/SpellCheckingController.php @@ -316,6 +316,8 @@ class SpellCheckingController $content = GeneralUtility::_POST('content'); // Parsing the input HTML $parser = xml_parser_create(strtoupper($this->parserCharset)); + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); xml_set_object($parser, $this); if (!xml_set_element_handler($parser, 'startHandler', 'endHandler')) { @@ -333,6 +335,7 @@ class SpellCheckingController if (xml_get_error_code($parser)) { throw new \UnexpectedValueException('Line ' . xml_get_current_line_number($parser) . ': ' . xml_error_string(xml_get_error_code($parser)), 1294585788); } + libxml_disable_entity_loader($previousValueOfEntityLoader); xml_parser_free($parser); if ($this->pspell_is_available && !$this->forceCommandMode) { pspell_clear_session($this->pspell_link); diff --git a/typo3/sysext/rtehtmlarea/Classes/Extension/MicroDataSchema.php b/typo3/sysext/rtehtmlarea/Classes/Extension/MicroDataSchema.php index 547b11401df0..e8f03d362f2a 100644 --- a/typo3/sysext/rtehtmlarea/Classes/Extension/MicroDataSchema.php +++ b/typo3/sysext/rtehtmlarea/Classes/Extension/MicroDataSchema.php @@ -107,9 +107,12 @@ class MicroDataSchema extends RteHtmlAreaApi { $types = array(); $properties = array(); + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); // Load the document $document = new \DOMDocument(); $document->loadXML($string); + libxml_disable_entity_loader($previousValueOfEntityLoader); if ($document) { // Scan resource descriptions $items = $document->getElementsByTagName('Description'); diff --git a/typo3/sysext/t3editor/Classes/TypoScriptReferenceLoader.php b/typo3/sysext/t3editor/Classes/TypoScriptReferenceLoader.php index 4b1f03c22a38..7948aa00029e 100644 --- a/typo3/sysext/t3editor/Classes/TypoScriptReferenceLoader.php +++ b/typo3/sysext/t3editor/Classes/TypoScriptReferenceLoader.php @@ -75,8 +75,11 @@ class TypoScriptReferenceLoader */ protected function loadFile($filepath) { + // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept + $previousValueOfEntityLoader = libxml_disable_entity_loader(true); $this->xmlDoc = new \DOMDocument('1.0', 'utf-8'); $this->xmlDoc->load($filepath); + libxml_disable_entity_loader($previousValueOfEntityLoader); // @TODO: oliver@typo3.org: I guess this is not required here $this->xmlDoc->saveXML(); } -- GitLab