1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
# This fixes OSA-2017-08, also known as CVE-2017-16854: An attacker who is
# logged into OTRS as a customer can use the ticket search form to disclose
# internal article information of their customer tickets.
# URL: https://www.otrs.com/security-advisory-2017-08-security-update-otrs-framework/
diff -Naur otrs2-5.0.16.orig/Kernel/Modules/CustomerTicketSearch.pm otrs2-5.0.16/Kernel/Modules/CustomerTicketSearch.pm
--- otrs2-5.0.16.orig/Kernel/Modules/CustomerTicketSearch.pm 2017-01-17 03:39:35.000000000 +0100
+++ otrs2-5.0.16/Kernel/Modules/CustomerTicketSearch.pm 2017-12-07 13:35:37.915211744 +0100
@@ -585,7 +585,12 @@
}
else
{
+ ARTICLE:
for my $Articles (@Article) {
+
+ # Skip internal articles.
+ next ARTICLE if $Articles->{ArticleType} =~ /-int/;
+
if ( $Articles->{Body} ) {
$Data{ArticleTree}
.= "\n-->||$Articles->{ArticleType}||$Articles->{From}||"
@@ -724,10 +729,9 @@
my @PDFData;
for my $TicketID (@ViewableTicketIDs) {
- # get first article data
- my %Data = $TicketObject->ArticleLastCustomerArticle(
+ # Get last customer or any other article if it doesn't exist.
+ my %Data = $Self->_LastCustomerArticle(
TicketID => $TicketID,
- Extended => 1,
DynamicFields => 0,
);
@@ -1058,10 +1062,9 @@
)
{
- # get first article data
- my %Article = $TicketObject->ArticleLastCustomerArticle(
+ # Get last customer or any other article if it doesn't exist.
+ my %Article = $Self->_LastCustomerArticle(
TicketID => $TicketID,
- Extended => 1,
DynamicFields => 1,
);
@@ -1902,4 +1905,47 @@
return %StopWordsServerErrors;
}
+sub _LastCustomerArticle {
+ my ( $Self, %Param ) = @_;
+
+ my $TicketObject = $Kernel::OM->Get('Kernel::System::Ticket');
+
+ # Get all customer articles.
+ my @Index = $TicketObject->ArticleIndex(
+ TicketID => $Param{TicketID},
+ SenderType => 'customer',
+ );
+
+ # Go over articles in reverse order and return the last external one.
+ if (@Index) {
+ for my $CustomerArticleID ( reverse @Index ) {
+ my %LastCustomerArticle = $TicketObject->ArticleGet(
+ ArticleID => $CustomerArticleID,
+ Extended => 1,
+ DynamicFields => $Param{DynamicFields},
+ );
+ if ( $LastCustomerArticle{ArticleType} !~ /-int/ ) {
+ return %LastCustomerArticle;
+ }
+ }
+ }
+
+ # If no customer articles were found, return the last external one.
+ @Index = $TicketObject->ArticleIndex(
+ TicketID => $Param{TicketID},
+ );
+ for my $ArticleID ( reverse @Index ) {
+ my %LastArticle = $TicketObject->ArticleGet(
+ ArticleID => $ArticleID,
+ Extended => 1,
+ DynamicFields => $Param{DynamicFields},
+ );
+ if ( $LastArticle{StateType} eq 'merged' || $LastArticle{ArticleType} !~ /-int/ ) {
+ return %LastArticle;
+ }
+ }
+
+ return;
+}
+
1;
diff -Naur otrs2-5.0.16.orig/scripts/test/Selenium/Customer/CustomerTicketSearch.t otrs2-5.0.16/scripts/test/Selenium/Customer/CustomerTicketSearch.t
--- otrs2-5.0.16.orig/scripts/test/Selenium/Customer/CustomerTicketSearch.t 2017-01-17 03:39:35.000000000 +0100
+++ otrs2-5.0.16/scripts/test/Selenium/Customer/CustomerTicketSearch.t 2017-12-07 13:35:37.915211744 +0100
@@ -85,6 +85,25 @@
"Ticket ID $TicketID - created",
);
+ # Add test article to the ticket.
+ # Make it email-internal, with sender type customer, in order to check if it's filtered out correctly.
+ my $InternalArticleMessage = 'not for the customer';
+ my $ArticleID = $TicketObject->ArticleCreate(
+ TicketID => $TicketID,
+ ArticleType => 'email-internal',
+ SenderType => 'customer',
+ Subject => $TitleRandom,
+ Body => $InternalArticleMessage,
+ ContentType => 'text/plain; charset=ISO-8859-15',
+ HistoryType => 'EmailCustomer',
+ HistoryComment => 'Some free text!',
+ UserID => 1,
+ );
+ $Self->True(
+ $ArticleID,
+ "Article is created - ID $ArticleID"
+ );
+
# get test ticket number
my %Ticket = $TicketObject->TicketGet(
TicketID => $TicketID,
@@ -100,6 +119,12 @@
"Ticket $TitleRandom found on page",
);
+ # Check if internal article was not shown.
+ $Self->True(
+ index( $Selenium->get_page_source(), $InternalArticleMessage ) == -1,
+ 'Internal article not found on page'
+ );
+
# click on '← Change search options'
$Selenium->find_element( "← Change search options", 'link_text' )->VerifiedClick();
|