Skip to content

FV Flowplayer Video Player <= 7.3.13.727 - Unauthenticated Stored XSS and SQL injection

Summary

Description Details
Name FV Flowplayer Video Player <= 7.3.13.727 - Unauthenticated Stored XSS
Summary wp_ajax_nopriv_fv_wp_flowplayer_email_signup used by unauthenticated user for sigups does not validate email ids allowing to execute evil javascript code while displaying eamil export page. SQL injection while checking if email already exists.
Affected application FV Flowplayer Video Player
Affected revision <= 7.3.13.727 , <= 7.3.14.727 SQL Injection
Vendor update available Yes
CVE
Ids CWE-79
CVSSv3.0 Base Score 8.1
CVSS vector AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N
Public Exploit available Yes
Exploit verified Yes
Authentication Required No

Vulnerable Code

<?php
## models/email-subscription.php
504     if(empty($data['email']) || filter_var(trim($data['email']), FILTER_VALIDATE_EMAIL)===false){
505       $result['status'] = 'ERROR';
506       $result['text'] = __('Malformed Email Address.', 'fv-wordpress-flowplayer');
507     };
## missing to exit 


512     if(intval($count) === 0){
513       $wpdb->insert($table_name, array(
514         'email' => $data['email'],
515         'data' => serialize($data),
516         'id_list'=>$list_id,
## data['email] not sanitized. wpdb->insert only escapes slashes, but not tags.

533       $wpdb->insert($table_name, array(
534         'email' => $data['email'],
535         'data' => serialize($data),
536         'id_list'=>$list_id,
## 

Email validation does not exit on failure, and goes on to insert into table. There is also a SQL injection vulnerability while searching if email already exists.

Exploit : External URL with payload contents as below.

http -v --form http://fv-wordpress-flowplayer-wp.vulnsite.wid/wp-admin/admin-ajax.php action=fv_wp_flowplayer_email_signup list=2  email="<svg/onload=alert(211)>@payload.com"

{
    "status": "ERROR",
    "text": "Malformed Email Address."
}

Safely view email list : On vulnerable versions, you can safely view email subscription list using wp cli or with mysql query.

wp db query  "select * from $( wp db prefix )fv_player_emails where email like '%<%' ; "

Exploit Methodology

The attacker will have to do the following to exploit this vulnerability:-

  • Upload payload into site by exploiting XSS vulnerability
  • Wait for admin user to visit the email subscription list( site -> admin -> Settings > FV Player > Tab Actions > Email Popups > View list )
  • Upon visiting subscription page, upload malware to site

Security Patch

diff --git a/wp-content/plugins/fv-wordpress-flowplayer/models/email-subscription.php b/wp-content/plugins/fv-wordpress-flowplayer/models/email-subscription.php
index cfe851b..348e317 100644
--- a/wp-content/plugins/fv-wordpress-flowplayer/models/email-subscription.php
+++ b/wp-content/plugins/fv-wordpress-flowplayer/models/email-subscription.php
@@ -504,19 +504,19 @@ class FV_Player_Email_Subscription {
     if(empty($data['email']) || filter_var(trim($data['email']), FILTER_VALIDATE_EMAIL)===false){
       $result['status'] = 'ERROR';
       $result['text'] = __('Malformed Email Address.', 'fv-wordpress-flowplayer');
+      die(json_encode($result));
     };
-
-    $count = $wpdb->get_var('SELECT COUNT(*) FROM ' . $wpdb->prefix . 'fv_player_emails WHERE email="' . addslashes($data['email']) . '" AND id_list = "'. addslashes($list_id) .'"' );
-
+    
+    $count = $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM ".$wpdb->prefix."fv_player_emails WHERE email = %s AND id_list = %s", strip_tags($data['email']), intval($list_id) ) );

     if(intval($count) === 0){
       $wpdb->insert($table_name, array(
-        'email' => $data['email'],
+        'email' => strip_tags($data['email']),
         'data' => serialize($data),
-        'id_list'=>$list_id,
-        'date'=>date("Y-m-d H:i:s"),
-        'first_name' => isset($data['first_name']) ? $data['first_name'] : '',
-        'last_name' => isset($data['last_name']) ? $data['last_name'] : '',
+        'id_list'=> intval($list_id),
+        'date' => date("Y-m-d H:i:s"),
+        'first_name' => isset($data['first_name']) ? strip_tags($data['first_name']) : '',
+        'last_name' => isset($data['last_name']) ? strip_tags($data['last_name']) : '',
         'integration' => $list['integration'],
         'integration_nice' => $integration_nice,
         'status' => $result['status'],
@@ -531,12 +531,12 @@ class FV_Player_Email_Subscription {

     }else{
       $wpdb->insert($table_name, array(
-        'email' => $data['email'],
+        'email' => strip_tags($data['email']),
         'data' => serialize($data),
-        'id_list'=>$list_id,
-        'date'=>date("Y-m-d H:i:s"),
-        'first_name' => isset($data['first_name']) ? $data['first_name'] : '',
-        'last_name' => isset($data['last_name']) ? $data['last_name'] : '',
+        'id_list' => intval($list_id),
+        'date' => date("Y-m-d H:i:s"),
+        'first_name' => isset($data['first_name']) ? strip_tags($data['first_name']) : '',
+        'last_name' => isset($data['last_name']) ? strip_tags($data['last_name']) : '',
         'integration' => $list['integration'],
         'integration_nice' => $integration_nice,
         'status' => $result['status'],
@@ -549,6 +549,8 @@ class FV_Player_Email_Subscription {
   }

   function csv_export(){
+    if( !current_user_can('manage_options') ) return;
+    
     $list_id = $_GET['fv-email-export'];
     $aLists = get_option('fv_player_email_lists');
     $list = $aLists[$list_id];
@@ -624,7 +626,7 @@ class FV_Player_Email_Subscription {
             $item = $tmp['title'];
           }
         }
-        echo '<td>' . $item . '</td>';
+        echo '<td>' . strip_tags($item) . '</td>';
       }
       echo '</tr>';
     }

References

WebARX