CVE-2017-15732: Cross-Site Request Forgery (CSRF) (CWE-352)
value: In phpMyFAQ before 2.9.9, there is Cross-Site Request Forgery (CSRF) in admin/news.php.
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.
CVSS v3 base score: 8.8
Published: 2017-10-22T18:29Z
Repository: https://github.com/thorsten/phpMyFAQ
Language: PHP
Files changed: phpmyfaq/admin/news.php
Commit date: 2017-10-03 12:30:39 +0200
Commit message: Added missing CSRF check

Diff: diff --git a/phpmyfaq/admin/news.php b/phpmyfaq/admin/news.php
index c204df0f0..1bf0657e7 100644
--- a/phpmyfaq/admin/news.php
+++ b/phpmyfaq/admin/news.php
@@ -27,107 +27,100 @@ if (!defined('IS_VALID_PHPMYFAQ')) {
     exit();
 }
 
 $news = new PMF_News($faqConfig);
 
+$csrfToken = PMF_Filter::filterInput(INPUT_POST, 'csrf', FILTER_SANITIZE_STRING);
+if (!isset($_SESSION['phpmyfaq_csrf_token']) || $_SESSION['phpmyfaq_csrf_token'] !== $csrfToken) {
+    $csrfCheck = false;
+} else {
+    $csrfCheck = true;
+}
+
 if ('addnews' == $action && $user->perm->checkRight($user->getUserId(), 'addnews')) {
     ?>
         <header class="row">
             <div class="col-lg-12">
-                <h2 class="page-header"><i aria-hidden="true" class="fa fa-pencil"></i> <?php echo $PMF_LANG['ad_news_add'];
-    ?></h2>
+                <h2 class="page-header"><i aria-hidden="true" class="fa fa-pencil"></i> <?php echo $PMF_LANG['ad_news_add'] ?></h2>
             </div>
         </header>
 
         <div class="row">
             <div class="col-lg-12">
                 <form class="form-horizontal" id="faqEditor" name="faqEditor" action="?action=savenews" method="post" accept-charset="utf-8">
 
                     <div class="form-group">
                         <label class="col-lg-2 control-label" for="newsheader">
-                            <?php echo $PMF_LANG['ad_news_header'];
-    ?>
+                            <?php echo $PMF_LANG['ad_news_header'] ?>
                         </label>
                         <div class="col-lg-4">
                             <input class="form-control" type="text" name="newsheader">
                         </div>
                     </div>
 
                     <div class="form-group">
-                        <label class="col-lg-2 control-label" for="news"><?php echo $PMF_LANG['ad_news_text'];
-    ?>:</label>
+                        <label class="col-lg-2 control-label" for="news"><?php echo $PMF_LANG['ad_news_text'] ?>:</label>
                         <div class="col-lg-4">
                             <noscript>Please enable JavaScript to use the WYSIWYG editor!</noscript>
                             <textarea name="news" rows="5" class="form-control"></textarea>
                         </div>
                     </div>
 
                     <div class="form-group">
-                        <label class="col-lg-2 control-label" for="authorName"><?php echo $PMF_LANG['ad_news_author_name'];
-    ?></label>
+                        <label class="col-lg-2 control-label" for="authorName"><?php echo $PMF_LANG['ad_news_author_name'] ?></label>
                         <div class="col-lg-4">
                             <input class="form-control" type="text" name="authorName" id="authorName"
-                                   value="<?php echo $user->getUserData('display_name');
-    ?>"/>
+                                   value="<?php echo $user->getUserData('display_name') ?>">
                         </div>
                     </div>
 
                     <div class="form-group">
-                        <label class="col-lg-2 control-label" for="authorEmail"><?php echo $PMF_LANG['ad_news_author_email'];
-    ?></label>
+                        <label class="col-lg-2 control-label" for="authorEmail"><?php echo $PMF_LANG['ad_news_author_email'] ?></label>
                         <div class="col-lg-4">
                             <input class="form-control" type="email" name="authorEmail" id="authorEmail"
-                                   value="<?php echo $user->getUserData('email');
-    ?>"/>
+                                   value="<?php echo $user->getUserData('email') ?>">
                         </div>
                     </div>
 
                     <div class="form-group">
                         <label class="col-lg-2 control-label" for="active">
-                            <?php echo $PMF_LANG['ad_news_set_active'];
-    ?>:
+                            <?php echo $PMF_LANG['ad_news_set_active'] ?>:
                         </label>
                         <div class="col-lg-4 checkbox">
                             <label>
                                 <input type="checkbox" name="active" id="active" value="y">
-                                <?php echo $PMF_LANG['ad_gen_yes'];
-    ?>
+                                <?php echo $PMF_LANG['ad_gen_yes'] ?>
                             </label>
                         </div>
                     </div>
 
                     <div class="form-group">
-                        <label class="col-lg-2 control-label" for="comment"><?php echo $PMF_LANG['ad_news_allowComments'];
-    ?></label>
+                        <label class="col-lg-2 control-label" for="comment"><?php echo $PMF_LANG['ad_news_allowComments'] ?></label>
                         <div class="col-lg-4 checkbox">
                             <label>
                                 <input type="checkbox" name="comment" id="comment" value="y">
-                                <?php echo $PMF_LANG['ad_gen_yes'];
-    ?>
+                                <?php echo $PMF_LANG['ad_gen_yes'] ?>
                             </label>
                         </div>
                     </div>
 
                     <div class="form-group">
-                        <label class="col-lg-2 control-label" for="link"><?php echo $PMF_LANG['ad_news_link_url'];
-    ?></label>
+                        <label class="col-lg-2 control-label" for="link"><?php echo $PMF_LANG['ad_news_link_url'] ?></label>
                         <div class="col-lg-4">
                             <input class="form-control" type="url" name="link" id="link" placeholder="http://www.example.com/">
                         </div>
                     </div>
 
                     <div class="form-group">
-                        <label class="col-lg-2 control-label" for="linkTitle"><?php echo $PMF_LANG['ad_news_link_title'];
-    ?></label>
+                        <label class="col-lg-2 control-label" for="linkTitle"><?php echo $PMF_LANG['ad_news_link_title'] ?></label>
                         <div class="col-lg-4">
                             <input type="text" name="linkTitle" id="linkTitle" class="form-control">
                         </div>
                     </div>
 
                     <div class="form-group">
-                        <label class="col-lg-2 control-label" ><?php echo $PMF_LANG['ad_news_link_target'];
-    ?></label>
+                        <label class="col-lg-2 control-label" ><?php echo $PMF_LANG['ad_news_link_target'] ?></label>
                         <div class="col-lg-4 radio">
                             <label>
                                 <input type="radio" name="target" value="blank">
                                 <?php echo $PMF_LANG['ad_news_link_window'] ?>
                                 <br>
@@ -138,20 +131,17 @@ if ('addnews' == $action && $user->perm->checkRight($user->getUserId(), 'addnews
                                 <?php echo $PMF_LANG['ad_news_link_parent'] ?>
                             </label>
                         </div>
                     </div>
                     <div class="form-group">
-                        <label class="col-lg-2 control-label" for="langTo"><?php echo $PMF_LANG['ad_entry_locale'];
-    ?>:</label>
+                        <label class="col-lg-2 control-label" for="langTo"><?php echo $PMF_LANG['ad_entry_locale'] ?>:</label>
                         <div class="col-lg-4">
-                            <?php echo PMF_Language::selectLanguages($LANGCODE, false, [], 'langTo');
-    ?>
+                            <?php echo PMF_Language::selectLanguages($LANGCODE, false, [], 'langTo') ?>
                         </div>
                     </div>
 
-                    <legend><?php echo $PMF_LANG['ad_news_expiration_window'];
-    ?></legend>
+                    <legend><?php echo $PMF_LANG['ad_news_expiration_window'] ?></legend>
                     <div class="form-group">
                         <label class="col-lg-2 control-label" for="dateStart"><?php echo $PMF_LANG['ad_news_from'];
     ?></label>
                         <div class="col-lg-2">
                             <input type="date" name="dateStart" id="dateStart" class="form-control date-pick">
@@ -592,20 +582,20 @@ if ('addnews' == $action && $user->perm->checkRight($user->getUserId(), 'addnews
 
         <div class="row">
             <div class="col-lg-12">
 <?php
     $precheck = PMF_Filter::filterInput(INPUT_POST, 'really', FILTER_SANITIZE_STRING, 'no');
-    $delete_id = PMF_Filter::filterInput(INPUT_GET, 'id', FILTER_VALIDATE_INT);
+    $deleteId = PMF_Filter::filterInput(INPUT_GET, 'id', FILTER_VALIDATE_INT);
 
     if ('no' == $precheck) {
         ?>
     <div class="form-group"><?php echo $PMF_LANG['ad_news_del'];
         ?></div>
     <div class="text-center">
     <form action="?action=deletenews" method="post" accept-charset="utf-8">
-    <input type="hidden" name="id" value="<?php echo $delete_id;
-        ?>">
+    <input type="hidden" name="id" value="<?php echo $deleteId ?>">
+    <input type="hidden" name="csrf" value="<?php echo $user->getCsrfTokenFromSession() ?>">
     <input type="hidden" name="really" value="yes">
         <button class="btn btn-warning" type="submit" name="submit">
             <?php echo $PMF_LANG['ad_news_yesdelete'];
         ?>
         </button>
@@ -624,13 +614,15 @@ if ('addnews' == $action && $user->perm->checkRight($user->getUserId(), 'addnews
     }
     </script>
 <?php
 
     } else {
-        $delete_id = PMF_Filter::filterInput(INPUT_POST, 'id', FILTER_VALIDATE_INT);
-        $news->deleteNews($delete_id);
-        printf('<p class="alert alert-success">%s</p>', $PMF_LANG['ad_news_delsuc']);
-        printf('<div class="form-group">&rarr; <a href="?action=news">%s</a></p>', $PMF_LANG['msgNews']);
+        if ($csrfCheck) {
+            $deleteId = PMF_Filter::filterInput(INPUT_POST, 'id', FILTER_VALIDATE_INT);
+            $news->deleteNews($deleteId);
+            printf('<p class="alert alert-success">%s</p>', $PMF_LANG['ad_news_delsuc']);
+            printf('<div class="form-group">&rarr; <a href="?action=news">%s</a></p>', $PMF_LANG['msgNews']);
+        }
     }
 } else {
     echo $PMF_LANG['err_NotAuth'];
 }

Vulnerable code:                 <h2 class="page-header"><i aria-hidden="true" class="fa fa-pencil"></i> <?php echo $PMF_LANG['ad_news_add'];
    ?></h2>
                            <?php echo $PMF_LANG['ad_news_header'];
    ?>
                        <label class="col-lg-2 control-label" for="news"><?php echo $PMF_LANG['ad_news_text'];
    ?>:</label>
                        <label class="col-lg-2 control-label" for="authorName"><?php echo $PMF_LANG['ad_news_author_name'];
    ?></label>
                                   value="<?php echo $user->getUserData('display_name');
    ?>"/>
                        <label class="col-lg-2 control-label" for="authorEmail"><?php echo $PMF_LANG['ad_news_author_email'];
    ?></label>
                                   value="<?php echo $user->getUserData('email');
    ?>"/>
                            <?php echo $PMF_LANG['ad_news_set_active'];
    ?>:
                                <?php echo $PMF_LANG['ad_gen_yes'];
    ?>
                        <label class="col-lg-2 control-label" for="comment"><?php echo $PMF_LANG['ad_news_allowComments'];
    ?></label>
                                <?php echo $PMF_LANG['ad_gen_yes'];
    ?>
                        <label class="col-lg-2 control-label" for="link"><?php echo $PMF_LANG['ad_news_link_url'];
    ?></label>
                        <label class="col-lg-2 control-label" for="linkTitle"><?php echo $PMF_LANG['ad_news_link_title'];
    ?></label>
                        <label class="col-lg-2 control-label" ><?php echo $PMF_LANG['ad_news_link_target'];
    ?></label>
                        <label class="col-lg-2 control-label" for="langTo"><?php echo $PMF_LANG['ad_entry_locale'];
    ?>:</label>
                            <?php echo PMF_Language::selectLanguages($LANGCODE, false, [], 'langTo');
    ?>
                    <legend><?php echo $PMF_LANG['ad_news_expiration_window'];
    ?></legend>
    $delete_id = PMF_Filter::filterInput(INPUT_GET, 'id', FILTER_VALIDATE_INT);
    <input type="hidden" name="id" value="<?php echo $delete_id;
        ?>">
        $delete_id = PMF_Filter::filterInput(INPUT_POST, 'id', FILTER_VALIDATE_INT);
        $news->deleteNews($delete_id);
        printf('<p class="alert alert-success">%s</p>', $PMF_LANG['ad_news_delsuc']);
        printf('<div class="form-group">&rarr; <a href="?action=news">%s</a></p>', $PMF_LANG['msgNews']);
Fixed code: $csrfToken = PMF_Filter::filterInput(INPUT_POST, 'csrf', FILTER_SANITIZE_STRING);
if (!isset($_SESSION['phpmyfaq_csrf_token']) || $_SESSION['phpmyfaq_csrf_token'] !== $csrfToken) {
    $csrfCheck = false;
} else {
    $csrfCheck = true;
}

                <h2 class="page-header"><i aria-hidden="true" class="fa fa-pencil"></i> <?php echo $PMF_LANG['ad_news_add'] ?></h2>
                            <?php echo $PMF_LANG['ad_news_header'] ?>
                        <label class="col-lg-2 control-label" for="news"><?php echo $PMF_LANG['ad_news_text'] ?>:</label>
                        <label class="col-lg-2 control-label" for="authorName"><?php echo $PMF_LANG['ad_news_author_name'] ?></label>
                                   value="<?php echo $user->getUserData('display_name') ?>">
                        <label class="col-lg-2 control-label" for="authorEmail"><?php echo $PMF_LANG['ad_news_author_email'] ?></label>
                                   value="<?php echo $user->getUserData('email') ?>">
                            <?php echo $PMF_LANG['ad_news_set_active'] ?>:
                                <?php echo $PMF_LANG['ad_gen_yes'] ?>
                        <label class="col-lg-2 control-label" for="comment"><?php echo $PMF_LANG['ad_news_allowComments'] ?></label>
                                <?php echo $PMF_LANG['ad_gen_yes'] ?>
                        <label class="col-lg-2 control-label" for="link"><?php echo $PMF_LANG['ad_news_link_url'] ?></label>
                        <label class="col-lg-2 control-label" for="linkTitle"><?php echo $PMF_LANG['ad_news_link_title'] ?></label>
                        <label class="col-lg-2 control-label" ><?php echo $PMF_LANG['ad_news_link_target'] ?></label>
                        <label class="col-lg-2 control-label" for="langTo"><?php echo $PMF_LANG['ad_entry_locale'] ?>:</label>
                            <?php echo PMF_Language::selectLanguages($LANGCODE, false, [], 'langTo') ?>
                    <legend><?php echo $PMF_LANG['ad_news_expiration_window'] ?></legend>
    $deleteId = PMF_Filter::filterInput(INPUT_GET, 'id', FILTER_VALIDATE_INT);
    <input type="hidden" name="id" value="<?php echo $deleteId ?>">
    <input type="hidden" name="csrf" value="<?php echo $user->getCsrfTokenFromSession() ?>">
        if ($csrfCheck) {
            $deleteId = PMF_Filter::filterInput(INPUT_POST, 'id', FILTER_VALIDATE_INT);
            $news->deleteNews($deleteId);
            printf('<p class="alert alert-success">%s</p>', $PMF_LANG['ad_news_delsuc']);
            printf('<div class="form-group">&rarr; <a href="?action=news">%s</a></p>', $PMF_LANG['msgNews']);
        }