Step-by-Step Guide to Cleaning Up Massive JavaScript Malware Redirects NDSW / NDSX / NDSJ

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.

The following command you’d need to customise for your specific infection type.

Backup before trying these commands!!!

For safety the following commands have been prefixed with a # symbol. If you know what you are doing, remove the #.

The following code works for all variable variants in the format ;if (typeof variable === "undefined"):

find . -type f -name '*.js' -exec sed -i -r '/;if\s*\(\s*(typeof\s+[a-zA-Z_$][a-zA-Z0-9_$]*\s*)?===\s*["'\''']undefined["'\''']\s*\)/,$d' {} \;

Explanation of Commands for Cleanup:

Option 1. Remove all lines from the matched pattern to the end of the file: This command deletes all lines starting from the match ;if (typeof variable === "undefined") until the end of the file. Useful if the malware spans multiple lines or if subsequent code is unnecessary.

find . -type f -name '*.js' -exec sed -i -r '/;if\s*\(\s*(typeof\s+[a-zA-Z_$][a-zA-Z0-9_$]*\s*)?===\s*["'\''']undefined["'\''']\s*\)/,$d' {} \;

Option 2. Remove only the infected part of the line: This command deletes only the specific matched part ;if (typeof variable === "undefined") on each line, preserving any remaining code on the line. Less destructive, but could potentially break syntax if it removes critical code within a line.

find . -type f -name '*.js' -exec sed -i -r 's/;if\s*\(\s*(typeof\s+[a-zA-Z_$][a-zA-Z0-9_$]*\s*)?===\s*["'\''']undefined["'\''']\s*\).*//' {} \;

Option 3. Simplified match for a single alphanumeric or underscore variable: This command is more restrictive, targeting cases where the variable name is a simple alphanumeric or underscore (\w+). It removes all lines from the match to the end of the file and may miss certain patterns.

find . -type f -name '*.js' -exec sed -i -r '/;if\s*\(\s*typeof\s+\w+\s*===\s*["'\''']undefined["'\''']\s*\)/,$d' {} \;

Let’s break down each command component:

  1. find .: Finds files in the current directory. Use an absolute path if you’re not in the root of your project.
  2. -type f: Ensures find only searches for files.
  3. -name '*.js': Limits the search to JavaScript files.
  4. -exec: Executes a command on each file found.
  5. sed -i: Allows sed to make in-place modifications to files.
  6. The ,: Defines a range in sed, starting from the matched line to the end of the file (denoted by $).
  7. $d: The sed command to delete lines within the specified range.
  8. '/;if\s*\(\s*(typeof\s+[a-zA-Z_$][a-zA-Z0-9_$]*\s*)?===\s*["'\''']undefined["'\''']\s*\)/,$d': This regular expression:
    • Matches ;if followed by optional whitespace, then an opening parenthesis.
    • Optionally matches typeof followed by a variable name that can include letters, numbers, underscores, and dollar signs.
    • Matches === followed by `”undefined”` (either in single or double quotes) and then a closing parenthesis.
  9. {} \;: Passes each file separately to the sed command.

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.

See Also:

This article is written by Evelyn Allison. Evelyn has over two decades of experience with the big-tech corporate giants. Starting in 2002 with consumer IT remote support, he transitioned into IT enterprise support and systems provisioning for Windows and Linux servers. Her prowess spans her expertise in network security, security audit and scripting-based-automation. Actively involved in web security since 2017, Evelyn has worked with various technologies to secure the web, leveraging tech like Nginx, modsecurity, reverse-proxies, developing web-application-firewalls, on-the-fly asset optimization using Google’s PageSpeed Module and more. Her expertise is reflected in the top-tier plugins and comprehensive consulting-services she offers in the domain of web-security.