From c3b9342a85c6f2c9382e074ad9cc440ce80a6f34 Mon Sep 17 00:00:00 2001
From: Dusan Vuckovic <dusan.vuckovic@otrs.com>
Date: Wed, 20 Mar 2019 09:40:56 +0000
Subject: [PATCH] Improved XML parsing.

---
 Kernel/System/XML.pm   | 14 ++++++-----
 scripts/test/XML/XXE.t | 53 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+), 6 deletions(-)
 create mode 100644 scripts/test/XML/XXE.t

--- a/Kernel/System/XML.pm
+++ b/Kernel/System/XML.pm
@@ -794,9 +794,10 @@ sub XMLParse {
     if ( eval 'require XML::Parser' ) {    ## no critic
         my $Parser = XML::Parser->new(
             Handlers => {
-                Start => sub { $Self->_HS(@_); },
-                End   => sub { $Self->_ES(@_); },
-                Char  => sub { $Self->_CS(@_); },
+                Start     => sub { $Self->_HS(@_); },
+                End       => sub { $Self->_ES(@_); },
+                Char      => sub { $Self->_CS(@_); },
+                ExternEnt => sub { return '' },         # suppress loading of external entities
             },
         );
 
@@ -828,9 +829,10 @@ sub XMLParse {
 
         my $Parser = XML::Parser::Lite->new(
             Handlers => {
-                Start => sub { $Self->_HS(@_); },
-                End   => sub { $Self->_ES(@_); },
-                Char  => sub { $Self->_CS(@_); },
+                Start     => sub { $Self->_HS(@_); },
+                End       => sub { $Self->_ES(@_); },
+                Char      => sub { $Self->_CS(@_); },
+                ExternEnt => sub { return '' },         # suppress loading of external entities
             },
         );
         $Parser->parse( $Param{String} );
--- /dev/null
+++ b/scripts/test/XML/XXE.t
@@ -0,0 +1,53 @@
+# --
+# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
+# --
+# This software comes with ABSOLUTELY NO WARRANTY. For details, see
+# the enclosed file COPYING for license information (GPL). If you
+# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
+# --
+
+use strict;
+use warnings;
+use utf8;
+
+use vars (qw($Self));
+
+my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
+my $XXEFilename  = $ConfigObject->Get('Home') . '/var/tmp/XXE.t.txt';
+
+# Write XXE payload.
+unlink $XXEFilename;
+my $FileCreated = $Kernel::OM->Get('Kernel::System::Main')->FileWrite(
+    Location => $XXEFilename,
+    Content  => \"XXE",
+);
+$Self->True(
+    $FileCreated,
+    'XXE payload written.',
+);
+
+$Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
+    Type => 'XMLParse',
+);
+
+my $XML = <<"EOF";
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE r [
+<!ELEMENT r ANY >
+<!ENTITY sp SYSTEM "$XXEFilename">
+]>
+<test_xml>Node &sp;</test_xml>
+EOF
+
+my $XMLObject = $Kernel::OM->Get('Kernel::System::XML');
+
+$Self->Is(
+    [ $XMLObject->XMLParse( String => $XML ) ]->[0]->{Content},
+    "Node ",
+    'K::S::XML XXE check.',
+);
+
+# Clean-up
+unlink $XXEFilename;
+
+1;
