How to Cleanup Massive JavaScript Malware NDSW/NDSX

The ndsw / ndsx malware causes massive JavaScript malware infection extending to thousands of JavaScript files. This one can be painful to clean owing to the sheer intimidating number of infected files.

Let’s break this task into small steps and take it one step at a time.

  1. Disable your WordPress site temporarily.
  2. Choose a Cleanup Methodology Based on Access.
  3. Reinstall WordPress Core Files.
  4. Do a multifile batch search & replace in infected files.

If you want to learn more about NDSW / NDSW malware, Sucuri already has published their research. The current article will only focus on the clean-up steps.

1. Disabling Your WordPress Website Temporarily

You don’t want visitors or search engines visiting your website while you are going to be doing a massive file-editing operation. The challenge is you can’t even rely on a maintenance plugin because that would be infected too.

For Apache the simplest way to disable the website is to add the following at the top of your .htaccess file:

<FilesMatch "*">
    # Apache 2.2
    <IfModule !mod_authz_core.c>
        Order Deny,Allow
        Deny from all
    </IfModule>
    # Apache 2.4
    <IfModule mod_authz_core.c>
        Require all denied
    </IfModule>
</FilesMatch>

For Nginx or other web-servers, please refer to the respective instructions.

2. Pre-Cleanup Preparation

The most important thing to do before you actually clean-up the JavaScript files is to first get rid of the primary infection vector which in this case usually is a PHP-Backdoor. That’s because you don’t want your files to get reinfected after you’ve done the cleanup. So scan your site thoroughly and ensure that there are no infections other than the ndws / ndsx.

3. Choosing Cleanup Methodology

Your cleanup method will largely depend on the kind of access and technical comfort you have. In this specific case there are basically two strategies:

3.1 Cleanup over SSH

Nothing matches the effectiveness of access to WP CLI. If you have access to ssh, this method is quicker. and will help you clean thousands of files at a lightening speed. Isn’t this awesome? You do need to be comfortable using SSH and the power that comes with it.

3.2 Downloading all files locally, Cleaning-up & Re-uploading

This method will take some time and patience. The idea is to download all the files locally to your system and then do a batch search-and-replace operation on all JavaScript files. You can use any search-and-replace utility that allows to run batch operations on files and allows usage of regular-expressions. This article walks you through this by employing VSCode.

4. Reinstalling Core WordPress Files

If you are going to do the the cleanup over ssh, here’s a quick way to reinstall WordPress core files. Once you are done, just jump to Step #5.

If you have manually download, executed search-and-replace and reupload the files, here are the steps to follow:

  1. Find out your WordPress version.
  2. Download the same WordPress version from WordPress.Org.
  3. Extract the downloaded archive.
  4. Upload wp-admin and wp-includes folders to your website overwriting the older ones.

5. Cleanup over SSH: Using sed to do a batch search-and-replace on all JavaScript files

If you don’t have ssh access, jump to Step #6.

Here is the command you’d need to customise for your specific infection type.

find . -type f -name '*.js' -exec sed -i 's/;if(ndsw===undefined).*//g' {} \;

Let’s break this down.

  1. find .: Finds file in the current directory. If you are not already in the root of your WordPress installation, then you’ll need to pass the path to it.
  2. -type f: Makes the find command to only search for files (instead of directories etc.). Don’t’ worry, this is fully recursive.
  3. -name '*.js': Makes the find command only search for JavaScript files.
  4. -exec: Executes a command.
  5. sed -i: Make the sed command do an in-place operation on the file.
  6. 's/;if(ndsw===undefined).*//g': The s stands for string replacement (including regular expression patterns). The part between the first set of / slashes is the pattern to search. The part between the second pair of / slashes is the replacement (which in this case is empty). The g at the end makes sed replace all occurances instead of just the first one.
  7. {} \;: Passes each file separately to the sed command. A variation of this {} + would pass all files to the sed command at once. Read more about the find exec bahaviour here.

6. Using VSCode to do a batch search-and-replace on all JavaScript files

Start by downloading all the files locally to your desktop. If you are on Windows OS, you may probably get warnings about files already existing because Windows filenames are not case-sensitive. You’ll need to make the local directory case-sensitive before you initiate the download. If you are on macOS or Linux you don’t have to worry about it.

Once all the files are downloaded, you’ll need to execute a batch search-and-replace on all files. This day our editor-utility of choice is Microsoft VSCode which is available for almost all common platforms.

Our regular-expression search and replace operation is going to be based on this:

How To Do A Multiline Regex Search In VSCode

Here is the search expression:

;if\(\w+===undefined\)[\s\S\n]*

And this is what it will look like in VSCode:

Once the search-and-replace operation is complete, just reupload the files over-writing the previous ones.

7. Post Clean-Up

  1. Re-enable your website: Just undo the actions in Step #1.
  2. Purge website cache.
  3. Shuffle WordPress salts: This will log out everyone from your website.
  4. Monitor website for reinfection. As a SOP we monitor the website and keep a close eye on any cases of reinfection before we close the case. If there’s a website reinfection, chances are that there still is a security vulnerability present on your website or hosting environment that is allowing the website to get re-infected.

Clean-Up Summary

The NDSW / NDSX JavaScript Malware is a pain to clean, not because it is complicated but because it’s infects a huge number of JavaScript files. The idea is to execute a smart operation which allows you to use regular-expressions to do a batch search-and-replace across a huge number of files. That’s the complicated part. The other crucial part is to ensure that no other backdoors and vulnerabilities exist before you clean-up the JavaScript infections.