Vulnerability: Revive Adserver before 3.2.3 suffers from Cross-Site Request Forgery (CSRF). The password recovery form in Revive Adserver is vulnerable to CSRF attacks. This vulnerability could be exploited to send a large number of password recovery emails to the registered users, especially in conjunction with a bug that caused recovery emails to be sent to all the users at once. Both issues have been fixed.
Vulnerability ID: CVE-2016-9127
CWE: CWE-352
Severity score: 6.4
Project: https://github.com/revive-adserver/revive-adserver
Published: 2017-03-28
File: lib/OA/Admin/PasswordRecovery.php
Commit message: Fix h1 report 99452

Cross-Site Request Forgery (CSRF)
---------------------------------

An undisclosed user has reported via HackerOne that the password recovery form
in Revive Adserver was vulnerable to CSRF attacks. Such vulnerability could be
exploited to send a large number of password recovery emails to the
registered users, especially in conjunction with a bug that caused recovery
emails to be sent to all the users at once. Both issues have been fixed.

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

CWE: CWE-352
CVSSv2: 5 (AV:N/AC:L/Au:N/C:N/I:N/A:P)
Commit author: Matteo Beccati

Vulnerable version (before fix):
 function handleGet($vars)      */     function handlePost($vars)     {         $this->pageHeader();         if (empty($vars['id'])) {             if (empty($vars['email'])) { function displayRecoveryRequestForm($errormessage = '')          echo "<form method='post' action='password-recovery.php'>\n";          echo "<div class='install'>".$GLOBALS['strPwdRecEnterEmail']."</div>";         echo "<table cellpadding='0' cellspacing='0' border='0'>";         echo "<tr><td colspan='2'><img src='" . OX::assetPath() . "/images/break-el.gif' width='400' height='1' vspace='8'></td></tr>"; function displayRecoveryResetForm($id, $errormessage = '')          echo "<form method='post' action='password-recovery.php'>\n";         echo "<input type='hidden' name='id' value=\"".htmlspecialchars($id)."\" />";          echo "<div class='install'>".$GLOBALS['strPwdRecEnterPassword']."</div>";         echo "<table cellpadding='0' cellspacing='0' border='0'>";

Fixed version (after fix):
 function handleGet($vars)      */     function handlePost($vars)     {         OA_Permission::checkSessionToken();          $this->pageHeader();         if (empty($vars['id'])) {             if (empty($vars['email'])) { function displayRecoveryRequestForm($errormessage = '')          echo "<form method='post' action='password-recovery.php'>\n";          echo "<input type='hidden' name='token' value='".phpAds_SessionGetToken()."'/>\n";          echo "<div class='install'>".$GLOBALS['strPwdRecEnterEmail']."</div>";         echo "<table cellpadding='0' cellspacing='0' border='0'>";         echo "<tr><td colspan='2'><img src='" . OX::assetPath() . "/images/break-el.gif' width='400' height='1' vspace='8'></td></tr>"; function displayRecoveryResetForm($id, $errormessage = '')          echo "<form method='post' action='password-recovery.php'>\n";         echo "<input type='hidden' name='id' value=\"".htmlspecialchars($id)."\" />";         echo "<input type='hidden' name='token' value='".phpAds_SessionGetToken()."'/>\n";          echo "<div class='install'>".$GLOBALS['strPwdRecEnterPassword']."</div>";         echo "<table cellpadding='0' cellspacing='0' border='0'>";

Patch:
patch: @@ -99,6 +99,8 @@ function handleGet($vars)
      */
     function handlePost($vars)
     {
+        OA_Permission::checkSessionToken();
+
         $this->pageHeader();
         if (empty($vars['id'])) {
             if (empty($vars['email'])) {
@@ -152,6 +154,8 @@ function displayRecoveryRequestForm($errormessage = '')
 
         echo "<form method='post' action='password-recovery.php'>\n";
 
+        echo "<input type='hidden' name='token' value='".phpAds_SessionGetToken()."'/>\n";
+
         echo "<div class='install'>".$GLOBALS['strPwdRecEnterEmail']."</div>";
         echo "<table cellpadding='0' cellspacing='0' border='0'>";
         echo "<tr><td colspan='2'><img src='" . OX::assetPath() . "/images/break-el.gif' width='400' height='1' vspace='8'></td></tr>";
@@ -177,6 +181,7 @@ function displayRecoveryResetForm($id, $errormessage = '')
 
         echo "<form method='post' action='password-recovery.php'>\n";
         echo "<input type='hidden' name='id' value=\"".htmlspecialchars($id)."\" />";
+        echo "<input type='hidden' name='token' value='".phpAds_SessionGetToken()."'/>\n";
 
         echo "<div class='install'>".$GLOBALS['strPwdRecEnterPassword']."</div>";
         echo "<table cellpadding='0' cellspacing='0' border='0'>";
path: lib/OA/Admin/PasswordRecovery.php