CVE-2015-10108 (published 2023-05-31T19:15Z)

A vulnerability was found in meitar Inline Google Spreadsheet Viewer Plugin up to 0.9.6 on WordPress and classified as problematic. Affected by this issue is the function displayShortcode of the file inline-gdocs-viewer.php. The manipulation leads to cross-site request forgery. The attack may be launched remotely. Upgrading to version 0.9.6.1 is able to address this issue. The patch is identified as 2a8057df8ca30adc859cecbe5cad21ac28c5b747. It is recommended to upgrade the affected component. VDB-230234 is the identifier assigned to this vulnerability.

CVSS v3 base score: 8.8, HIGH (CVSS:3.1/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/wp-plugins/inline-google-spreadsheet-viewer
commit_details: repo_url: https://github.com/wp-plugins/inline-google-spreadsheet-viewer
author: meitar
author_date: 2015-05-11 21:54:52+00:00
msg: Secure the CSV fetching code behind a WordPress nonce to avoid CSRFs.

git-svn-id: https://plugins.svn.wordpress.org/inline-google-spreadsheet-viewer/trunk@1158277 b8457f37-d9ea-0310-8a92-e5e31aec5664
repository: repo_url: https://github.com/wp-plugins/inline-google-spreadsheet-viewer
repo_name: wp-plugins/inline-google-spreadsheet-viewer
description: WordPress.org Plugin Mirror
repo_language: PHP
owner: wp-plugins
file_changes: filename: inline-gdocs-viewer.php
change_type: ModificationType.MODIFY
diff: @@ -27,6 +27,7 @@ class InlineGoogleSpreadsheetViewerPlugin {
         ));
 
         add_action('plugins_loaded', array($this, 'registerL10n'));
+        add_action('init', array($this, 'maybeFetchGvizDataSource'));
         add_action('admin_init', array($this, 'registerSettings'));
         add_action('admin_menu', array($this, 'registerAdminMenu'));
         add_action('admin_head', array($this, 'doAdminHeadActions'));
@@ -244,12 +245,10 @@ class InlineGoogleSpreadsheetViewerPlugin {
 
     private function getGVizDataSourceUrl ($key, $query, $format) {
         $format = ($format) ? $format : 'json';
-        $url = plugins_url('vistable-proxy.php', __FILE__);
-        $url .= '?url=' . rawurlencode($key);
-        $tq = $this->sanitizeQuery($query);
-        $url .= "&tq=$tq";
-        $url .= "&tqx=out:$format";
-        return $url;
+        $base = trailingslashit(get_site_url()) . '?';
+        $qs = 'url=';
+        $qs .= rawurlencode($key .  '?tq=' . $this->sanitizeQuery($query) . "&tqx=out:$format");
+        return $base . $qs;
     }
 
     private function sanitizeQuery ($query) {
@@ -295,7 +294,7 @@ class InlineGoogleSpreadsheetViewerPlugin {
         }
         $resp = (empty($http_args)) ? wp_remote_get($url) : wp_remote_request($url, $http_args);
         if (is_wp_error($resp)) { // bail on error
-            throw new Exception('[' . __('Error requesting data from Google:', 'inline-gdocs-viewer') . $resp->get_error_message() . ']');
+            throw new Exception('[' . __('Error requesting data:', 'inline-gdocs-viewer') . ' ' . $resp->get_error_message() . ']');
         }
         return $resp;
     }
@@ -425,6 +424,48 @@ class InlineGoogleSpreadsheetViewerPlugin {
         return $this->displayShortcode(array('key' => $url));
     }
 
+    public function maybeFetchGvizDataSource () {
+        if (
+            !isset($_GET[$this->prefix . 'get_datasource_nonce'])
+            ||
+            !$this->isValidNonce($_GET[$this->prefix . 'get_datasource_nonce'], $this->prefix . 'get_datasource_nonce')
+        ) { return; }
+        require_once dirname(__FILE__) . '/lib/vistable.php';
+        $url = rawurldecode($_GET['url']);
+        $http_response = $this->fetchData($url, false);
+
+        $p = parse_url($url);
+        $qs = array();
+        parse_str($p['query'], $qs);
+        $tqx  = (isset($qs['tqx']))  ? $qs['tqx'] : '';
+        $tq   = (isset($qs['tq']))   ? $qs['tq']  : '';
+        $tqrt = (isset($qs['tqrt'])) ? $qs['tqrt']: '';
+        $tz   = (isset($qs['tz']))   ? $qs['tz']  : 'PDT'; // TODO: will get_option('timezone_string') work?
+        $vt = new csv_vistable($tqx, $tq, $tqrt, $tz, get_locale(), array());
+        $vt->setup_table($http_response['body']);
+        print $vt->execute();
+        exit;
+    }
+
+    private function makeNonceUrl ($url) {
+        $options = get_option($this->prefix . 'settings');
+        $options[$this->prefix . 'get_datasource_nonce'] = wp_create_nonce($this->prefix . 'get_datasource_nonce');
+        update_option($this->prefix . 'settings', $options);
+        $p = parse_url($url);
+        return $p['scheme']
+            . '://' . $p['host'] . $p['path']
+            . '?' . $p['query'] . '&'
+            . $this->prefix . 'get_datasource_nonce=' . $options[$this->prefix . 'get_datasource_nonce'];
+    }
+
+    private function isValidNonce ($nonce, $nonce_name) {
+        $options = get_option($this->prefix . 'settings');
+        $is_valid = ($nonce === $options[$nonce_name]) ? true : false;
+        unset($options[$this->prefix . 'get_datasource_nonce']);
+        update_option($this->prefix . 'settings', $options);
+        return $is_valid;
+    }
+
     /**
      * WordPress Shortcode handler.
      */
@@ -567,7 +608,7 @@ class InlineGoogleSpreadsheetViewerPlugin {
             if (!empty($x['query'])) {
                 if (!empty($x['chart'])) { $fmt = 'json'; }
                 else { $fmt = 'csv'; }
-                $url = $this->getGVizDataSourceUrl($x['key'], $x['query'], $fmt);
+                $url = $this->makeNonceUrl($this->getGVizDataSourceUrl($x['key'], $x['query'], $fmt));
             }
         }
 

programming_language: PHP
filename: vistable-proxy.php
change_type: ModificationType.DELETE
diff: @@ -1,29 +0,0 @@
-<?php
-require_once dirname(__FILE__) . '/lib/vistable.php';
-
-$url = isset($_GET['url']) ? rawurldecode($_GET['url']) : '';
-$tqx = isset($_GET['tqx']) ? $_GET['tqx'] : '';
-$tq = isset($_GET['tq']) ? $_GET['tq'] : '';
-$tqrt = isset($_GET['tqrt']) ? $_GET['tqrt'] : '';
-$tz = isset($_GET['tz']) ? $_GET['tz'] : 'PDT';
-$locale = isset($_SERVER["HTTP_ACCEPT_LANGUAGE"]) ? $_SERVER["HTTP_ACCEPT_LANGUAGE"] : 'en_US';
-
-if (isset($_GET['locale'])) {
-    $locale = $_GET['locale'];
-}
-
-$extra = array();
-if (isset($_GET['debug']) && $_GET['debug']) {
-    header('Content-type: text/plain; charset="UTF-8"');
-    $extra['debug'] = 1;
-}
-
-$vt = new csv_vistable($tqx, $tq, $tqrt,$tz,$locale,$extra);
-
-$data = file_get_contents($url);
-
-$vt->setup_table($data);
-
-$result = $vt->execute();
-
-print $result;

programming_language: unknown