CVE-2016-9454: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Revive Adserver before 3.2.3 suffers from Persistent XSS. A vector for persistent XSS attacks via the Revive Adserver user interface exists, requiring a trusted (non-admin) account. The banner image URL for external banners wasn't properly escaped when displayed in most of the banner related pages.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 5.4
Published: 2017-03-28T02:59Z
Repository: https://github.com/revive-adserver/revive-adserver
Language: PHP
Files changed: lib/max/Delivery/adRender.php, lib/templates/admin/campaign-zone-zones.html
Commit date: 2016-03-01 16:23:10 +0100
Commit message: Fix h1 reports 107550 and 107634

Persistent XSS
--------------
Johan Caluwe has reported via HackerOne two vectors for persistent XSS
Revive Adserver user interface, both requiring a trusted (non-admin) account:

1. the website name wasn't properly escaped when displayed in the
   campaign-zone.php script;
2. the banner image url for external banners wasn't properly escaped when
   displayed in most of the banner related pages.

A CVE-ID has been requested, but not assigned yet.

CWE: CWE-79
CVSSv2: 3.5 (AV:N/AC:M/Au:S/C:N/I:P/A:N)

Diff: diff --git a/lib/max/Delivery/adRender.php b/lib/max/Delivery/adRender.php
index bf1f32251b..3c8402ada6 100644
--- a/lib/max/Delivery/adRender.php
+++ b/lib/max/Delivery/adRender.php
@@ -208,11 +208,11 @@ function MAX_adRenderImageBeacon($logUrl, $beaconId = 'beacon', $userAgent = nul
     } else {
         $div = "<div id='{$beaconId}' style='position: absolute; left: 0px; top: 0px; visibility: hidden;'>";
         $style = " style='width: 0px; height: 0px;'";
         $divEnd = '</div>';
     }
-        $beacon = "$div<img src='".htmlspecialchars($logUrl)."' width='0' height='0' alt=''{$style} />{$divEnd}";
+        $beacon = "$div<img src='".htmlspecialchars($logUrl, ENT_QUOTES)."' width='0' height='0' alt=''{$style} />{$divEnd}";
         return $beacon;
 }
 
 /**
  * This function builds the HTML code to display an "image" ad (e.g. GIF/JPG/PNG)
@@ -247,11 +247,11 @@ function _adRenderImage(&$aBanner, $zoneId=0, $source='', $ct0='', $withText=fal
     // Create the anchor tag..
     $clickUrl = _adRenderBuildClickUrl($aBanner, $zoneId, $source, $ct0, $logClick);
     if (!empty($clickUrl)) {  // There is a link
         $status = _adRenderBuildStatusCode($aBanner);
         //$target = !empty($aBanner['target']) ? $aBanner['target'] : '_blank';
-        $clickTag = "<a href='$clickUrl' target='{target}'$status>";
+        $clickTag = "<a href='".htmlspecialchars($clickUrl, ENT_QUOTES)."' target='{target}'$status>";
         $clickTagEnd = '</a>';
     } else {
         $clickTag = '';
         $clickTagEnd = '';
     }
@@ -259,11 +259,11 @@ function _adRenderImage(&$aBanner, $zoneId=0, $source='', $ct0='', $withText=fal
     if (!empty($imageUrl)) {
         $imgStatus = empty($clickTag) && !empty($status) ? $status : '';
         $width = !empty($aBanner['width']) ? $aBanner['width'] : 0;
         $height = !empty($aBanner['height']) ? $aBanner['height'] : 0;
         $alt = !empty($aBanner['alt']) ? htmlspecialchars($aBanner['alt'], ENT_QUOTES) : '';
-        $imageTag = "$clickTag<img src='$imageUrl' width='$width' height='$height' alt='$alt' title='$alt' border='0'$imgStatus />$clickTagEnd";
+        $imageTag = "$clickTag<img src='".htmlspecialchars($imageUrl, ENT_QUOTES)."' width='$width' height='$height' alt='$alt' title='$alt' border='0'$imgStatus />$clickTagEnd";
     } else {
         $imageTag = '';
     }
     // Get the text below the banner
     $bannerText = $withText && !empty($aBanner['bannertext']) ? "<br />$clickTag" . htmlspecialchars($aBanner['bannertext'], ENT_QUOTES) . "$clickTagEnd" : '';
@@ -322,11 +322,11 @@ function _adRenderFlash(&$aBanner, $zoneId=0, $source='', $ct0='', $withText=fal
     $clickUrl = _adRenderBuildClickUrl($aBanner, $zoneId, $source, $ct0, $logClick);
     if (!empty($clickUrl)) {  // There is a link
         $status = _adRenderBuildStatusCode($aBanner);
         $target = !empty($aBanner['target']) ? $aBanner['target'] : '_blank';
         $swfParams = array('clickTARGET' => $target, 'clickTAG' => $clickUrl);
-        $clickTag = "<a href='$clickUrl' target='$target'$status>";
+        $clickTag = "<a href='".htmlspecialchars($clickUrl, ENT_QUOTES)."' target='$target'$status>";
         $clickTagEnd = '</a>';
     } else {
         $swfParams = array();
         $clickTag = '';
         $clickTagEnd = '';
diff --git a/lib/templates/admin/campaign-zone-zones.html b/lib/templates/admin/campaign-zone-zones.html
index 126f443da0..d1836118ce 100644
--- a/lib/templates/admin/campaign-zone-zones.html
+++ b/lib/templates/admin/campaign-zone-zones.html
@@ -61,11 +61,11 @@
             <input id="{$checkboxPrefix}w{$websiteid}"
                    name="w{$websiteid}" type="checkbox" class="checkbox parent" />{boldSearchPhrase text=$website.name search=$text}
         </label>
       </td>
       <td class="link">
-          <a title="{t str=EditWebsite} {$website.name}" class="website-icon" href="affiliate-edit.php?affiliateid={$websiteid}">&nbsp;</a>
+          <a title="{t str=EditWebsite} {$website.name|escape}" class="website-icon" href="affiliate-edit.php?affiliateid={$websiteid}">&nbsp;</a>
       </td>
       {if !empty($showStats)}
           <td></td>
           <td></td>
           <td></td>
@@ -80,11 +80,11 @@
                    name="z{$zoneid}" type="checkbox" class="checkbox" />
             {boldSearchPhrase text=$zone.name search=$text}
         </label>
         </td>
         <td class="link">
-            <a title="{t str=EditZone} {$website.name}" class="zone-icon" href="zone-edit.php?affiliateid={$websiteid}&zoneid={$zoneid}">&nbsp;</a>
+            <a title="{t str=EditZone} {$website.name|escape}" class="zone-icon" href="zone-edit.php?affiliateid={$websiteid}&zoneid={$zoneid}">&nbsp;</a>
         </td>
         {if !empty($showStats)}
             {assign var="ctr" value="`$zone.ctr*100`"}
             {assign var="cr" value="`$zone.cr*100`"}
             <td {if $zone.campaign_stats}class="estim"{/if}>{$ctr|string_format:"%.3f"}%</td>

Vulnerable code:         $beacon = "$div<img src='".htmlspecialchars($logUrl)."' width='0' height='0' alt=''{$style} />{$divEnd}";
        $clickTag = "<a href='$clickUrl' target='{target}'$status>";
        $imageTag = "$clickTag<img src='$imageUrl' width='$width' height='$height' alt='$alt' title='$alt' border='0'$imgStatus />$clickTagEnd";
        $clickTag = "<a href='$clickUrl' target='$target'$status>";
          <a title="{t str=EditWebsite} {$website.name}" class="website-icon" href="affiliate-edit.php?affiliateid={$websiteid}">&nbsp;</a>
            <a title="{t str=EditZone} {$website.name}" class="zone-icon" href="zone-edit.php?affiliateid={$websiteid}&zoneid={$zoneid}">&nbsp;</a>
Fixed code:         $beacon = "$div<img src='".htmlspecialchars($logUrl, ENT_QUOTES)."' width='0' height='0' alt=''{$style} />{$divEnd}";
        $clickTag = "<a href='".htmlspecialchars($clickUrl, ENT_QUOTES)."' target='{target}'$status>";
        $imageTag = "$clickTag<img src='".htmlspecialchars($imageUrl, ENT_QUOTES)."' width='$width' height='$height' alt='$alt' title='$alt' border='0'$imgStatus />$clickTagEnd";
        $clickTag = "<a href='".htmlspecialchars($clickUrl, ENT_QUOTES)."' target='$target'$status>";
          <a title="{t str=EditWebsite} {$website.name|escape}" class="website-icon" href="affiliate-edit.php?affiliateid={$websiteid}">&nbsp;</a>
            <a title="{t str=EditZone} {$website.name|escape}" class="zone-icon" href="zone-edit.php?affiliateid={$websiteid}&zoneid={$zoneid}">&nbsp;</a>