CVE-2017-15733 (published 2017-10-22T18:29Z)

In phpMyFAQ before 2.9.9, there is Cross-Site Request Forgery (CSRF) in admin/ajax.attachment.php and admin/att.main.php.

Severity: MEDIUM
CVSS v2 base score: 6.8 (AV:N/AC:M/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 8.8, HIGH (CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-352
cwe_name: Cross-Site Request Forgery (CSRF)
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.
extended_description: When a web server is designed to receive a request from a client without any mechanism for verifying that it was intentionally sent, then it might be possible for an attacker to trick a client into making an unintentional request to the web server which will be treated as an authentic request. This can be done via a URL, image load, XMLHttpRequest, etc. and can result in exposure of data or unintended code execution.
         

Fix information:
repo_url: https://github.com/thorsten/phpMyFAQ
commit_details: repo_url: https://github.com/thorsten/phpMyFAQ
author: Thorsten Rinne
author_date: 2017-10-08 11:00:38+02:00
msg: Added missing CSRF protection
repository: repo_url: https://github.com/thorsten/phpMyFAQ
repo_name: thorsten/phpMyFAQ
description: phpMyFAQ - Open Source FAQ web application for PHP 8.1+ and MySQL, PostgreSQL and other databases
repo_language: PHP
owner: thorsten
file_changes: filename: ajax.attachment.php
change_type: ModificationType.MODIFY
diff: @@ -10,11 +10,9 @@
  * obtain one at http://mozilla.org/MPL/2.0/.
  *
  * @category  phpMyFAQ
- *
  * @author    Anatoliy Belsky <anatoliy.belsky@mayflower.de>
  * @copyright 2010-2017 phpMyFAQ Team
  * @license   http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
- *
  * @link      http://www.phpmyfaq.de
  * @since     2010-12-20
  */
@@ -29,16 +27,23 @@ if (!defined('IS_VALID_PHPMYFAQ')) {
 
 $ajaxAction = PMF_Filter::filterInput(INPUT_GET, 'ajaxaction', FILTER_SANITIZE_STRING);
 $attId = PMF_Filter::filterInput(INPUT_GET, 'attId', FILTER_VALIDATE_INT);
+$csrfToken = PMF_Filter::filterInput(INPUT_GET, 'csrf', FILTER_SANITIZE_STRING);
 
 $att = PMF_Attachment_Factory::create($attId);
 
 if ($att) {
     switch ($ajaxAction) {
         case 'delete':
+
+            if (!isset($_SESSION['phpmyfaq_csrf_token']) || $_SESSION['phpmyfaq_csrf_token'] !== $csrfToken) {
+                echo $PMF_LANG['err_NotAuth'];
+                exit(1);
+            }
+
             if ($att->delete()) {
-                print $PMF_LANG['msgAttachmentsDeleted'];
+                echo $PMF_LANG['msgAttachmentsDeleted'];
             } else {
-                print $PMF_LANG['ad_att_delfail'];
+                echo $PMF_LANG['ad_att_delfail'];
             }
             break;
     }

programming_language: PHP
filename: att.main.php
change_type: ModificationType.MODIFY
diff: @@ -70,7 +70,7 @@ $pagination = new PMF_Pagination(
                             <td><?php echo $item->filesize ?></td>
                             <td><?php echo $item->mime_type ?></td>
                             <td>
-                                <a href="javascript:deleteAttachment(<?php echo $item->id ?>); void(0);"
+                                <a href="javascript:deleteAttachment(<?php echo $item->id ?>, '<?php echo $user->getCsrfTokenFromSession() ?>'); void(0);"
                                    class="btn btn-danger" title="<?php echo $PMF_LANG['ad_gen_delete'] ?>">
                                     <i aria-hidden="true" class="fa fa-trash-o"></i>
                                 </a>
@@ -92,15 +92,16 @@ $pagination = new PMF_Pagination(
          * Ajax call for deleting attachments
          *
          * @param att_id Attachment id
+         * @apram csrf CSRF token
          */
-        function deleteAttachment(att_id)
+        function deleteAttachment(att_id, csrf)
         {
             if (confirm('<?php echo $PMF_LANG['msgAttachmentsWannaDelete'] ?>')) {
                 $('#saving_data_indicator').html('<i aria-hidden="true" class="fa fa-spinner fa-spin"></i> Deleting ...');
                 $.ajax({
                     type:    "GET",
                     url:     "index.php?action=ajax&ajax=att&ajaxaction=delete",
-                    data:    {attId: att_id},
+                    data:    { attId: att_id, csrf: csrf},
                     success: function(msg) {
                         $('.att_' + att_id).fadeOut('slow');
                         $('#saving_data_indicator').html('<p class="alert alert-success">' + msg + '</p>');

programming_language: PHP