CVE-2015-3902: Cross-Site Request Forgery (CSRF) (CWE-352)
value: Multiple cross-site request forgery (CSRF) vulnerabilities in the setup process in phpMyAdmin 4.0.x before 4.0.10.10, 4.2.x before 4.2.13.3, 4.3.x before 4.3.13.1, and 4.4.x before 4.4.6.1 allow remote attackers to hijack the authentication of administrators for requests that modify the configuration file.
CWE description: The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request.
Published: 2015-05-26T15:59Z
Repository: https://github.com/phpmyadmin/phpmyadmin
Language: PHP
Files changed: ChangeLog, libraries/url_generating.lib.php, setup/frames/form.inc.php, setup/frames/index.inc.php, setup/frames/menu.inc.php, setup/frames/servers.inc.php, setup/index.php, setup/lib/form_processing.lib.php, setup/validate.php
Commit date: 2015-05-12 20:01:03 +0530
Commit message: bug #4899 [security] CSRF vulnerability in setup

Signed-off-by: Madhura Jayaratne <madhura.cj@gmail.com>

Diff: diff --git a/ChangeLog b/ChangeLog
index 845ff7302178..b07e196832dd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,11 @@
 phpMyAdmin - ChangeLog
 ======================
 
+4.4.6.1 (Not yet released)
+- bug #4899 [security] CSRF vulnerability in setup
+
 4.4.6.0 (2015-05-07)
 - bug #4890 webkitStorageInfo and webkitIndexedDB is deprecated
 - bug #4892 Undefined variable: unique_conditions
 - bug #4891 CSV Import ignores "Replace table data with file" checkbox
 
diff --git a/libraries/url_generating.lib.php b/libraries/url_generating.lib.php
index bc078ad9f12b..799489b22530 100644
--- a/libraries/url_generating.lib.php
+++ b/libraries/url_generating.lib.php
@@ -177,10 +177,11 @@ function PMA_URL_getCommon($params = array(), $encode = 'html', $divider = '?')
 
     // avoid overwriting when creating navi panel links to servers
     if (isset($GLOBALS['server'])
         && $GLOBALS['server'] != $GLOBALS['cfg']['ServerDefault']
         && ! isset($params['server'])
+        && ! defined('PMA_SETUP')
     ) {
         $params['server'] = $GLOBALS['server'];
     }
 
     if (empty($_COOKIE['pma_lang']) && ! empty($GLOBALS['lang'])) {
diff --git a/setup/frames/form.inc.php b/setup/frames/form.inc.php
index 2fb2cda0f447..4e25bfe1d2c3 100644
--- a/setup/frames/form.inc.php
+++ b/setup/frames/form.inc.php
@@ -17,12 +17,12 @@
 require_once './libraries/config/FormDisplay.class.php';
 require_once './setup/lib/form_processing.lib.php';
 
 require './libraries/config/setup.forms.php';
 
-$formset_id = filter_input(INPUT_GET, 'formset');
-$mode = filter_input(INPUT_GET, 'mode');
+$formset_id = isset($_GET['formset']) ? $_GET['formset'] : null;
+$mode = isset($_GET['mode']) ? $_GET['mode'] : null;
 if (! isset($forms[$formset_id])) {
     PMA_fatalError(__('Incorrect formset, check $formsets array in setup/frames/form.inc.php!'));
 }
 
 if (isset($GLOBALS['strConfigFormset_' . $formset_id])) {
diff --git a/setup/frames/index.inc.php b/setup/frames/index.inc.php
index c291c3c3275d..2c341ec2c99a 100644
--- a/setup/frames/index.inc.php
+++ b/setup/frames/index.inc.php
@@ -172,16 +172,16 @@
             . htmlspecialchars($cf->getValue("Servers/$id/auth_type"))
             .  '</td>';
         echo '<td>' . htmlspecialchars($cf->getServerDSN($id)) . '</td>';
         echo '<td style="white-space: nowrap">';
         echo '<small>';
-        echo '<a href="?page=servers' . $separator
-            . 'mode=edit' . $separator . 'id=' . $id . '">'
+        echo '<a href="' . PMA_URL_getCommon() . $separator . 'page=servers'
+            . $separator . 'mode=edit' . $separator . 'id=' . $id . '">'
             . __('Edit') . '</a>';
         echo ' | ';
-        echo '<a href="?page=servers' . $separator
-            . 'mode=remove' . $separator . 'id=' . $id . '">'
+        echo '<a href="' . PMA_URL_getCommon() . $separator . 'page=servers'
+            . $separator . 'mode=remove' . $separator . 'id=' . $id . '">'
             . __('Delete') . '</a>';
         echo '</small>';
         echo '</td>';
         echo '</tr>';
     }
@@ -306,9 +306,8 @@
 echo '</fieldset>';
 echo '<div id="footer">';
 echo '<a href="http://www.phpmyadmin.net/">' . __('phpMyAdmin homepage') . '</a>';
 echo '<a href="http://sourceforge.net/donate/index.php?group_id=23067">'
     .  __('Donate') . '</a>';
-echo '<a href="?version_check=1' . $separator
-    . 'token=' . $_SESSION[' PMA_token '] . '">'
+echo '<a href="' .  PMA_URL_getCommon() . $separator . 'version_check=1">'
     . __('Check for latest version') . '</a>';
 echo '</div>';
diff --git a/setup/frames/menu.inc.php b/setup/frames/menu.inc.php
index d82dce07f261..a78c84d689fe 100644
--- a/setup/frames/menu.inc.php
+++ b/setup/frames/menu.inc.php
@@ -8,15 +8,15 @@
 
 if (!defined('PHPMYADMIN')) {
     exit;
 }
 
-$formset_id = filter_input(INPUT_GET, 'formset');
+$formset_id = isset($_GET['formset']) ? $_GET['formset'] : null;
 
 $separator = PMA_URL_getArgSeparator('html');
 echo '<ul>';
-echo '<li><a href="index.php"'
+echo '<li><a href="index.php' . PMA_URL_getCommon() . '"'
     . ($formset_id === null ? ' class="active' : '')
     . '">' . __('Overview') . '</a></li>';
 
 $formsets = array(
     'Features'    => __('Features'),
@@ -26,11 +26,12 @@
     'Import'      => __('Import'),
     'Export'      => __('Export')
 );
 
 foreach ($formsets as $formset => $label) {
-    echo '<li><a href="?page=form' . $separator . 'formset=' . $formset . '" '
+    echo '<li><a href="' . PMA_URL_getCommon() . $separator . 'page=form'
+        . $separator . 'formset=' . $formset . '" '
         . ($formset_id === $formset ? ' class="active' : '')
         . '">' . $label . '</a></li>';
 }
 
 echo '</ul>';
diff --git a/setup/frames/servers.inc.php b/setup/frames/servers.inc.php
index 87c5cee1d7fe..859a784816f0 100644
--- a/setup/frames/servers.inc.php
+++ b/setup/frames/servers.inc.php
@@ -17,12 +17,12 @@
 require_once './libraries/config/FormDisplay.class.php';
 require_once './setup/lib/form_processing.lib.php';
 
 require './libraries/config/setup.forms.php';
 
-$mode = filter_input(INPUT_GET, 'mode');
-$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
+$mode = isset($_GET['mode']) ? $_GET['mode'] : null;
+$id = PMA_isValid($_GET['id'], 'numeric') ? $_GET['id'] : null;
 
 $cf = $GLOBALS['ConfigFile'];
 $server_exists = !empty($id) && $cf->get("Servers/$id") !== null;
 
 if ($mode == 'edit' && $server_exists) {
diff --git a/setup/index.php b/setup/index.php
index 53d333a63f78..5ef68c268ede 100644
--- a/setup/index.php
+++ b/setup/index.php
@@ -10,22 +10,22 @@
 /**
  * Core libraries.
  */
 require './lib/common.inc.php';
 
-$page = filter_input(INPUT_GET, 'page');
+$page = isset($_GET['page']) ? $_GET['page'] : null;
 $page = preg_replace('/[^a-z]/', '', $page);
 if ($page === '') {
     $page = 'index';
 }
 if (!file_exists("./setup/frames/$page.inc.php")) {
     // it will happen only when entering URL by hand, we don't care for these cases
     PMA_fatalError(__('Wrong GET file attribute value'));
 }
 
 // Handle done action info
-$action_done = filter_input(INPUT_GET, 'action_done');
+$action_done = isset($_GET['action_done']) ? $_GET['action_done'] : null;
 $action_done = preg_replace('/[^a-z_]/', '', $action_done);
 
 PMA_noCacheHeader();
 
 ?>
diff --git a/setup/lib/form_processing.lib.php b/setup/lib/form_processing.lib.php
index 5d762e76c5d9..db80e44ec5c4 100644
--- a/setup/lib/form_processing.lib.php
+++ b/setup/lib/form_processing.lib.php
@@ -13,11 +13,11 @@
  *
  * @return void
  */
 function PMA_Process_formset(FormDisplay $form_display)
 {
-    if (filter_input(INPUT_GET, 'mode') == 'revert') {
+    if (isset($_GET['mode']) && $_GET['mode'] == 'revert') {
         // revert erroneous fields to their default values
         $form_display->fixErrors();
         PMA_generateHeader303();
     }
 
@@ -33,32 +33,35 @@ function PMA_Process_formset(FormDisplay $form_display)
         return;
     }
 
     // form has errors, show warning
     $separator = PMA_URL_getArgSeparator('html');
-    $page = filter_input(INPUT_GET, 'page');
-    $formset = filter_input(INPUT_GET, 'formset');
+    $page = isset($_GET['page']) ? $_GET['page'] : null;
+    $formset = isset($_GET['formset']) ? $_GET['formset'] : null;
     $formset = $formset ? "{$separator}formset=$formset" : '';
-    $formId = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
+    $formId = PMA_isValid($_GET['id'], 'numeric') ? $_GET['id'] : null;
     if ($formId === null && $page == 'servers') {
         // we've just added a new server, get its id
         $formId = $form_display->getConfigFile()->getServerCount();
     }
     $formId = $formId ? "{$separator}id=$formId" : '';
     ?>
     <div class="error">
         <h4><?php echo __('Warning') ?></h4>
         <?php echo __('Submitted form contains errors') ?><br />
-        <a href="?page=<?php echo $page . $formset . $formId . $separator ?>mode=revert">
+        <a href="<?php echo PMA_URL_getCommon() . $separator ?>
+            page=<?php echo $page . $formset . $formId . $separator ?>mode=revert">
             <?php echo __('Try to revert erroneous fields to their default values')
             ?>
         </a>
     </div>
     <?php $form_display->displayErrors() ?>
-    <a class="btn" href="index.php"><?php echo __('Ignore errors') ?></a>
+    <a class="btn" href="index.php<?php echo PMA_URL_getCommon() ?>">
+        <?php echo __('Ignore errors') ?></a>
     &nbsp;
-    <a class="btn" href="?page=<?php echo $page . $formset . $formId
+    <a class="btn" href="<?php echo PMA_URL_getCommon() . $separator ?>
+        page=<?php echo $page . $formset . $formId
         . $separator ?>mode=edit"><?php echo __('Show form') ?></a>
     <?php
 }
 
 /**
diff --git a/setup/validate.php b/setup/validate.php
index fba2725dc36a..3c070f29abe3 100644
--- a/setup/validate.php
+++ b/setup/validate.php
@@ -14,12 +14,14 @@
 $validators = array();
 require './libraries/config/Validator.class.php';
 
 header('Content-type: application/json');
 
-$vids = explode(',', filter_input(INPUT_POST, 'id'));
-$values = json_decode(filter_input(INPUT_POST, 'values'));
+$ids = isset($_POST['id']) ? $_POST['id'] : null;
+$vids = explode(',', $ids);
+$vals = isset($_POST['values']) ? $_POST['values'] : null;
+$values = json_decode($vals);
 if (!($values instanceof stdClass)) {
     PMA_fatalError(__('Wrong data'));
 }
 $values = (array)$values;
 $result = PMA_Validator::validate($GLOBALS['ConfigFile'], $vids, $values, true);

Vulnerable code: $formset_id = filter_input(INPUT_GET, 'formset');
$mode = filter_input(INPUT_GET, 'mode');
        echo '<a href="?page=servers' . $separator
            . 'mode=edit' . $separator . 'id=' . $id . '">'
        echo '<a href="?page=servers' . $separator
            . 'mode=remove' . $separator . 'id=' . $id . '">'
echo '<a href="?version_check=1' . $separator
    . 'token=' . $_SESSION[' PMA_token '] . '">'
$formset_id = filter_input(INPUT_GET, 'formset');
echo '<li><a href="index.php"'
    echo '<li><a href="?page=form' . $separator . 'formset=' . $formset . '" '
$mode = filter_input(INPUT_GET, 'mode');
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
$page = filter_input(INPUT_GET, 'page');
$action_done = filter_input(INPUT_GET, 'action_done');
    if (filter_input(INPUT_GET, 'mode') == 'revert') {
    $page = filter_input(INPUT_GET, 'page');
    $formset = filter_input(INPUT_GET, 'formset');
    $formId = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
        <a href="?page=<?php echo $page . $formset . $formId . $separator ?>mode=revert">
    <a class="btn" href="index.php"><?php echo __('Ignore errors') ?></a>
    <a class="btn" href="?page=<?php echo $page . $formset . $formId
$vids = explode(',', filter_input(INPUT_POST, 'id'));
$values = json_decode(filter_input(INPUT_POST, 'values'));
Fixed code: 4.4.6.1 (Not yet released)
- bug #4899 [security] CSRF vulnerability in setup

        && ! defined('PMA_SETUP')
$formset_id = isset($_GET['formset']) ? $_GET['formset'] : null;
$mode = isset($_GET['mode']) ? $_GET['mode'] : null;
        echo '<a href="' . PMA_URL_getCommon() . $separator . 'page=servers'
            . $separator . 'mode=edit' . $separator . 'id=' . $id . '">'
        echo '<a href="' . PMA_URL_getCommon() . $separator . 'page=servers'
            . $separator . 'mode=remove' . $separator . 'id=' . $id . '">'
echo '<a href="' .  PMA_URL_getCommon() . $separator . 'version_check=1">'
$formset_id = isset($_GET['formset']) ? $_GET['formset'] : null;
echo '<li><a href="index.php' . PMA_URL_getCommon() . '"'
    echo '<li><a href="' . PMA_URL_getCommon() . $separator . 'page=form'
        . $separator . 'formset=' . $formset . '" '
$mode = isset($_GET['mode']) ? $_GET['mode'] : null;
$id = PMA_isValid($_GET['id'], 'numeric') ? $_GET['id'] : null;
$page = isset($_GET['page']) ? $_GET['page'] : null;
$action_done = isset($_GET['action_done']) ? $_GET['action_done'] : null;
    if (isset($_GET['mode']) && $_GET['mode'] == 'revert') {
    $page = isset($_GET['page']) ? $_GET['page'] : null;
    $formset = isset($_GET['formset']) ? $_GET['formset'] : null;
    $formId = PMA_isValid($_GET['id'], 'numeric') ? $_GET['id'] : null;
        <a href="<?php echo PMA_URL_getCommon() . $separator ?>
            page=<?php echo $page . $formset . $formId . $separator ?>mode=revert">
    <a class="btn" href="index.php<?php echo PMA_URL_getCommon() ?>">
        <?php echo __('Ignore errors') ?></a>
    <a class="btn" href="<?php echo PMA_URL_getCommon() . $separator ?>
        page=<?php echo $page . $formset . $formId
$ids = isset($_POST['id']) ? $_POST['id'] : null;
$vids = explode(',', $ids);
$vals = isset($_POST['values']) ? $_POST['values'] : null;
$values = json_decode($vals);