Vulnerability: In phpMyFAQ before 2.9.9, there is Cross-Site Request Forgery (CSRF) in admin/stat.main.php.
Vulnerability ID: CVE-2017-15734
CWE: CWE-352
Severity score: 6.4
Project: https://github.com/thorsten/phpMyFAQ
Published: 2017-10-22
File: phpmyfaq/admin/stat.main.php
Commit message: Added missing CSRF protection
Commit author: Thorsten Rinne

Vulnerable version (before fix):
                 <h2 class="page-header">                     <i aria-hidden="true" class="fa fa-tasks"></i> <?php echo $PMF_LANG['ad_stat_sess'] ?>                     <div class="pull-right">                         <a class="btn btn-danger" href="?action=clear-visits">                             <i aria-hidden="true" class="fa fa-trash"></i> <?php echo $PMF_LANG['ad_clear_all_visits'] ?>                         </a>                     </div>     $visits = new PMF_Visits($faqConfig);     $statdelete = PMF_Filter::filterInput(INPUT_POST, 'statdelete', FILTER_SANITIZE_STRING);     $month = PMF_Filter::filterInput(INPUT_POST, 'month', FILTER_SANITIZE_STRING);     $csrfToken = PMF_Filter::filterInput(INPUT_POST, 'csrf', FILTER_SANITIZE_STRING);      if (!isset($_SESSION['phpmyfaq_csrf_token']) || $_SESSION['phpmyfaq_csrf_token'] !== $csrfToken) {         $statdelete = null;     }      // Delete sessions and session files     if (!is_null($statdelete) && !is_null($month)) {         $dir = opendir(PMF_ROOT_DIR.'/data');     }      // Reset all visits and sessions     if ('clear-visits' === $action) {          // Clear visits         $visits->resetAll();

Fixed version (after fix):
                 <h2 class="page-header">                     <i aria-hidden="true" class="fa fa-tasks"></i> <?php echo $PMF_LANG['ad_stat_sess'] ?>                     <div class="pull-right">                         <a class="btn btn-danger"                            href="?action=clear-visits&csrf=<?php echo $user->getCsrfTokenFromSession() ?>">                             <i aria-hidden="true" class="fa fa-trash"></i> <?php echo $PMF_LANG['ad_clear_all_visits'] ?>                         </a>                     </div>     $visits = new PMF_Visits($faqConfig);     $statdelete = PMF_Filter::filterInput(INPUT_POST, 'statdelete', FILTER_SANITIZE_STRING);     $month = PMF_Filter::filterInput(INPUT_POST, 'month', FILTER_SANITIZE_STRING);     $csrfTokenFromPost = PMF_Filter::filterInput(INPUT_POST, 'csrf', FILTER_SANITIZE_STRING);     $csrfTokenFromGet = PMF_Filter::filterInput(INPUT_GET, 'csrf', FILTER_SANITIZE_STRING);      if (!isset($_SESSION['phpmyfaq_csrf_token']) || $_SESSION['phpmyfaq_csrf_token'] !== $csrfTokenFromPost) {         $statdelete = null;     }      if (!isset($_SESSION['phpmyfaq_csrf_token']) || $_SESSION['phpmyfaq_csrf_token'] !== $csrfTokenFromGet) {         $clearVisits = false;     } else {         $clearVisits = true;     }      // Delete sessions and session files     if (!is_null($statdelete) && !is_null($month)) {         $dir = opendir(PMF_ROOT_DIR.'/data');     }      // Reset all visits and sessions     if ('clear-visits' === $action && $clearVisits) {          // Clear visits         $visits->resetAll();

Patch:
patch: @@ -30,7 +30,8 @@
                 <h2 class="page-header">
                     <i aria-hidden="true" class="fa fa-tasks"></i> <?php echo $PMF_LANG['ad_stat_sess'] ?>
                     <div class="pull-right">
-                        <a class="btn btn-danger" href="?action=clear-visits">
+                        <a class="btn btn-danger"
+                           href="?action=clear-visits&csrf=<?php echo $user->getCsrfTokenFromSession() ?>">
                             <i aria-hidden="true" class="fa fa-trash"></i> <?php echo $PMF_LANG['ad_clear_all_visits'] ?>
                         </a>
                     </div>
@@ -47,12 +48,19 @@
     $visits = new PMF_Visits($faqConfig);
     $statdelete = PMF_Filter::filterInput(INPUT_POST, 'statdelete', FILTER_SANITIZE_STRING);
     $month = PMF_Filter::filterInput(INPUT_POST, 'month', FILTER_SANITIZE_STRING);
-    $csrfToken = PMF_Filter::filterInput(INPUT_POST, 'csrf', FILTER_SANITIZE_STRING);
+    $csrfTokenFromPost = PMF_Filter::filterInput(INPUT_POST, 'csrf', FILTER_SANITIZE_STRING);
+    $csrfTokenFromGet = PMF_Filter::filterInput(INPUT_GET, 'csrf', FILTER_SANITIZE_STRING);
 
-    if (!isset($_SESSION['phpmyfaq_csrf_token']) || $_SESSION['phpmyfaq_csrf_token'] !== $csrfToken) {
+    if (!isset($_SESSION['phpmyfaq_csrf_token']) || $_SESSION['phpmyfaq_csrf_token'] !== $csrfTokenFromPost) {
         $statdelete = null;
     }
 
+    if (!isset($_SESSION['phpmyfaq_csrf_token']) || $_SESSION['phpmyfaq_csrf_token'] !== $csrfTokenFromGet) {
+        $clearVisits = false;
+    } else {
+        $clearVisits = true;
+    }
+
     // Delete sessions and session files
     if (!is_null($statdelete) && !is_null($month)) {
         $dir = opendir(PMF_ROOT_DIR.'/data');
@@ -80,7 +88,7 @@
     }
 
     // Reset all visits and sessions
-    if ('clear-visits' === $action) {
+    if ('clear-visits' === $action && $clearVisits) {
 
         // Clear visits
         $visits->resetAll();
path: phpmyfaq/admin/stat.main.php