{
	"id": "8a8603e1-3ef7-407f-8155-6c4e5c05ace2",
	"created_at": "2026-04-06T00:20:09.695303Z",
	"updated_at": "2026-04-10T03:24:24.049777Z",
	"deleted_at": null,
	"sha1_hash": "2e277475ae8d0c252ba8dc53d7c1e1506807ba7f",
	"title": "Analysis of a trojanized jQuery script: GootLoader unleashed",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 5790115,
	"plain_text": "Analysis of a trojanized jQuery script: GootLoader unleashed\r\nBy Sasja Reynaert\r\nPublished: 2022-07-20 · Archived: 2026-04-05 18:51:32 UTC\r\nUpdate 24/10/202:\r\nWe have noticed 2 changes since we published this report 3 months ago.\r\n1. The code has been adapted to use registry key\r\n“HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Personalization” instead of\r\n“HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Phone” (sample SHA256\r\ned2f654b5c5e8c05c27457876f3855e51d89c5f946c8aefecca7f110a6276a6e)\r\n2. When the payload is Cobalt Strike, the beacon configuration now contains hostnames for the C2, like\r\nr1dark[.]ssndob[.]cn[.]com and r2dark[.]ssndob[.]cn[.]com (all prior CS samples we analyzed use IPv4\r\naddresses).\r\nIn this blog post, we will perform a deep analysis into GootLoader, malware which is known to deliver several\r\ntypes of payloads, such as Kronos trojan, REvil, IcedID, GootKit payloads and in this case Cobalt Strike.\r\nIn our analysis we’ll be using the initial malware sample itself together with some malware artifacts from the\r\nsystem it was executed on. The malicious JavaScript code is hiding within a jQuery JavaScript Library and\r\ncontains about 287kb of data and consists of almost 11.000 lines of code. We’ll do a step-by-step analysis of the\r\nmalicious JavaScript file.\r\nTLDR techniques we used to analyze this GootLoader script:\r\n1. Stage 1: A legitimate jQuery JavaScript script is used to hide a trojan downloader:\r\nSeveral new functions were added to the original jQuery script. Analyzing these functions would show a\r\nblob of obfuscated data and functions to deobfuscate this blob.\r\n2. The algorithm used for deobfuscating this blob (trojan downloader):\r\n1. For each character in the obfuscated data, assess whether it is at an even or uneven position (index\r\nstarting at 0)\r\n1. If uneven, put it in front of an accumulator string\r\n1. If even, put it at the back of the accumulator string\r\n1. The result is more JavaScript code\r\n3. Attempt to download the (obfuscated) payload from one of three URLs listed in the resulting JavaScript\r\ncode.\r\n1. This failed due to the payload not being served anymore and we resorted to make an educated guess\r\nto search for an obfuscated (as defined in the previous output) “createobject” string on VirusTotal\r\nwith the “content” filter, which resulted in a few hits.\r\n4. Stage 2: Decode the obfuscated payload\r\n1. Take 2 digits\r\nhttps://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/\r\nPage 1 of 15\n\n1. Convert these 2 decimal digits to an integer\r\n1. Add 30\r\n1. Convert to ASCII\r\n1. Repeat till the end\r\n1. The result is a combination of JavaScript and PowerShell\r\n5. Extract the JavaScript, PowerShell loader, PowerShell persistence and analyze it to extract the obfuscated\r\n.NET loader embedded in the payload\r\n6. Stage 3: Analyze the .NET loader to deobfuscate the Cobalt Strike DLL\r\n7. Stage 4: Extract the config from the Cobalt Strike DLL\r\nStage 1 – sample_supplier_quality_agreement 33187.js\r\nFilename: sample_supplier_quality_agreement 33187.js\r\nMD5: dbe5d97fcc40e4117a73ae11d7f783bf\r\nSHA256: 6a772bd3b54198973ad79bb364d90159c6f361852febe95e7cd45b53a51c00cb\r\nFile Size: 287 KB\r\nTo find the trojan downloader inside this JavaScript file, the following grep command was executed:\r\ngrep -P \"^[a-zA-Z0-9]+\\(\"\r\nFig 1. The function “hundred71(3565)” looks out of place here\r\nThis grep command will find entry points that are calling a JavaScript function outside any function definition,\r\nthus without indentation (leading whitespace). This is a convention that many developers follow, but it is not a\r\nguarantee to quickly find the entry point. In this case, the function call hundred17(3565) looks out of place in a\r\nmature JavaScript library like jQuery.\r\nWhen tracing the different calls, there’s a lot of obfuscated code, the function “color1” is observed Another way to\r\nfigure out what was changed in the script could be to compare it to the legitimate version[1] of the script and\r\n“diff” them to see the difference. The legitimate script was pulled from the jQuery website itself, based on the\r\nversion displayed in the beginning of the malicious script.\r\nFig 2. The version of the jQuery JavaScript Library displayed here was used to fetch the original\r\nhttps://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/\r\nPage 2 of 15\n\nBefore starting a full diff on the entire jQuery file, we first extracted the functions names with the following grep\r\ncommand:\r\ngrep 'function [0-9a-zA-Z]'\r\nThis was done for both the legitimate jQuery file and the malicious one and allows us to quickly see which\r\nadditional functions were added by the malware creator. Comparing these two files immediately show some\r\ninteresting function names and parameters:\r\nFig 3. Many functions were added by the malware author as seen in this screenshot\r\nA diff on both files without only focusing on the function names gave us all the added code by the malware author.\r\nColor1 is one of the added functions containing most of the data, seemingly obfuscated, which could indicated this\r\nis the most relevant function.\r\nFig 4. Out of all the added functions, “color1()” contains the most amount of data\r\nThe has6 variable is of interest in this function, as it combines all the previously defined variables into 1:\r\nhttps://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/\r\nPage 3 of 15\n\nFurther tracing of the functions eventually leads to the main functions that are responsible for deobfuscating this\r\ndata: “modern00” and “gun6”\r\nFig 5. Function modern00, responsible for part of the deobfuscation algorithm\r\nFig 6. Function gun6, responsible for the modulo part of the deobfuscation algorithm\r\nThe deobfuscation algorithm is straightforward:\r\nFor each character in the obfuscated string (starting with the first character), add this character to an accumulator\r\nstring (initially empty). If the character is at an uneven position (index starting from 0), put it in front of the\r\naccumulator, otherwise put it at the back. When all characters have been processed, the accumulator will contain\r\nthe deobfuscated string.\r\nThe script used to implement the algorithm would look similar to the following written in Python:\r\nFig 7. Proof of concept Python script to display how the algorithm functions\r\nFig 8. Running the deobfuscation script displays readable code\r\nhttps://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/\r\nPage 4 of 15\n\nCreateObject, observed in the deobfuscated script, is used to create a script execution object (WScript.Shell) that\r\nis then passed the script to execute (first script). This script (highlightd in white) is also obfuscated with JavaScript\r\nobfuscation and the same script obfuscation that was observed in the first script.\r\nDeobfuscating that script yields a second JavaScript script. Following, is the second script, with deobfuscated\r\nstrings and code, and “pretty-printed”:\r\nFig 9. Pretty printed deobfuscated code\r\nThis script is a downloader script, attempting to initiate a download from 3 domains.\r\nwww[.]labbunnies[.]eu\r\nwww[.]lenovob2bportal[.]com\r\nwww[.]lakelandartassociation[.]org\r\nThe HTTPS requests have a random component and can convey a small piece of information: if the request ends\r\nwith “4173581”, then the request originates from a Windows machine that is a domain member (the script\r\ndetermines this by checking for the presence of environment variable %USERDNSDOMAIN%).\r\nThe following is an example of a URL:\r\nhxxps://www[.]labbunnies[.]eu/test[.]php?cmqqvfpugxfsfhz=71941221366466524173581\r\nIf the download fails (i.e., HTTP status code different from 200), the script sleeps for 12 seconds (12345\r\nmilliseconds to be precise) before trying the next domain. When the download succeeds, the next stage is decoded\r\nand executed as (another) JavaScript script. Different methods were attempted to download the payload (with\r\nvarying URLs), but all methods were unsuccessful. Most of the time a TCP/TLS connection couldn’t be\r\nestablished to the server. The times an HTTP reply was received, the body was empty (content-length 0). Although\r\nwe couldn’t download the payload from the malicious servers, we were able to retrieve it from VirusTotal.\r\nStage 2 – Payload\r\nWe were able to find a payload that we believe, with high confidence, to be the original stage 2. With high\r\nconfidence, it was determined that this is indeed the payload that was served to the infected machine, more\r\ninformation on how this was determined can be found in the following sections. The payload, originally uploaded\r\nhttps://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/\r\nPage 5 of 15\n\nfrom Germany, can be found here:\r\nhttps://www.virustotal.com/gui/file/f8857afd249818613161b3642f22c77712cc29f30a6993ab68351af05ae14c0f\r\nMD5: ae8e4c816e004263d4b1211297f8ba67\r\nSHA-256: f8857afd249818613161b3642f22c77712cc29f30a6993ab68351af05ae14c0f\r\nFile Size: 1012.97 KB\r\nThe payload consists of digits. To decode it, take 2 digits, add 30, convert to an ASCII character, and repeat this\r\ntill the end of the payload. This deobfuscation algorithm was deduced from the previous script, in the last step:\r\nFig 10. Stage 2 acquired from VirusTotal\r\nFig 11. Deobfuscation algorithm for stage 2\r\nAs an example, we’ll decode the first characters of the strings in detail: 88678402\r\n1. 88 –\u003e 88+30 = 118\r\nhttps://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/\r\nPage 6 of 15\n\nFig 12. ASCII value 118 equals the letter v\r\n2. 67 –\u003e 67 + 30 = 97\r\nFig 13. ASCII value 97 equals the letter a\r\n3. 84 –\u003e 84 + 30 = 114\r\nhttps://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/\r\nPage 7 of 15\n\nFig 14. ASCII value 114 equals the letter r\r\n4. 02 –\u003e 02+30 = 32\r\nFig 15. ASCII value 32 equals the symbol “space”\r\nThis results in: “var “, which indicates the declaration of a variable in JavaScript. This means we have yet another\r\nJavaScript script to analyze.\r\nTo decode the entire string a bit faster we can use a small Python script, which will automate the process for us:\r\nhttps://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/\r\nPage 8 of 15\n\nFig 16. Proof of concept Python script to display how the algorithm functions\r\nFirst half of the decoded string:\r\nFig 17. Output of the deobfuscation script, showing the first part\r\nSecond half of the decoded string:\r\nFig 18. Output of the deobfuscation script, showing the second part\r\nThe same can be done with the following CyberChef recipe, it will take some time, due to the amount of data, but\r\nwe saw it as a small challenge to use CyberChef to do the same.\r\nhttps://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/\r\nPage 9 of 15\n\n#recipe=Regular_expression('User%20defined','..',true,true,false,false,false,false,'List%20matches')Find_/_Repl\r\nFig 19. The CyberChef recipe in action\r\nThe decoded payload results in another JavaScript script.\r\nMD5: a8b63471215d375081ea37053b52dfc4\r\nSHA256: 12c0067a15a0e73950f68666dafddf8a555480c5a51fd50c6c3947f924ec2fb4\r\nFile size: 507 KB\r\nThe JavaScript script contains code to insert an encoded PE file (unmanaged code) and create a key with as value\r\nas encoded assembly (“HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Phone”) and then launches 2\r\nPowerShell scripts. These 2 PowerShell scripts are fileless, and thus have no filename. For referencing in this\r\ndocument, the PowerShell scripts are named as follows:\r\n1. powershell_loader: this PowerShell script is a loader to execute the PE file injected into the registry\r\n2. powershell_persistence: this PowerShell script creates a scheduled task to execute the loader PowerShell\r\nscript (powershell_loader) at boot time.\r\nhttps://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/\r\nPage 10 of 15\n\nFig 20. Deobfuscated \u0026 pretty-printed JavaScript script found in the decoded payload\r\nA custom script was utilized to decode this payload as a whole and extract all separate elements from it (based on\r\nthe reverse engineering of the script itself). The following is the output of the custom script:\r\nFig 21. Output of the custom script parsing all the components from the deobfuscated\r\nAll the artifacts extracted with this script match exactly with the artifacts recovered from the infected machine.\r\nThese can be verified with the fileless artifacts extracted from Defender logs, with matching cryptographic hash:\r\nStage 2 SHA256 Script: 12c0067a15a0e73950f68666dafddf8a555480c5a51fd50c6c3947f924ec2fb4\r\nStage 2 SHA256 Persistence PowerShell script (powershell_persistence):\r\n48e94b62cce8a8ce631c831c279dc57ecc53c8436b00e70495d8cc69b6d9d097\r\nStage 2 SHA256 PowerShell script (powershell_loader) contained in Persistence PowerShell script:\r\nc8a3ce2362e93c7c7dc13597eb44402a5d9f5757ce36ddabac8a2f38af9b3f4c\r\nStage 3 SHA256 Assembly: f1b33735dfd1007ce9174fdb0ba17bd4a36eee45fadcda49c71d7e86e3d4a434\r\nhttps://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/\r\nPage 11 of 15\n\nStage 4 SHA256 DLL: 63bf85c27e048cf7f243177531b9f4b1a3cb679a41a6cc8964d6d195d869093e\r\nBased on this information, it can be concluded, with high confidence, that the payload found on VirusTotal is\r\nidentical to the one downloaded by the infected machine: all hashes match with the artifacts from the infected\r\nmachine.\r\nIn addition to the evidence these matching hashes bring, the stage 2 payload file also ends with the following\r\nstring (this is not part of the encoded script): @83290986999722234173581@. This is the random part of the URL\r\nused to request this payload. Notice that it ends with 4173581, the unique number for domain joined machines\r\nfound in the trojanized jQuery script.\r\nPayload retrieval from VirusTotal\r\nAlthough VirusTotal has reports for several URLs used by this malicious script, none of the reports contained a\r\nlink to the actual downloaded content. However, using the following query:\r\ncontent:”378471678671496876716986″, the download content (payload) was found on VirusTotal; This string of\r\ndigits corresponds to the encoding of string “CreateObject”. (see Fig. 20)\r\nIn order to attempt the retrieval of the downloaded content, an educated guess was made that the downloaded\r\npayload would contain calls to function CreateObject, because such functions calls are also present in the\r\ntrojanized jQuery script. There are countless files on VirusTotal that contain the string “CreateObject”, but in this\r\nparticular case, it is encoded with an encoding specific to GootLoader. Each letter of the string “CreateObject” is\r\nencoded to its numerical representation (ASCII code), and subtracted with 30. This returns the string\r\n“378471678671496876716986”.\r\nStage 3 – .NET Loader\r\nMD5 Assembly: d401dc350aff1e3fd4cc483238208b43\r\nSHA256 Assembly: f1b33735dfd1007ce9174fdb0ba17bd4a36eee45fadcda49c71d7e86e3d4a434\r\nFile Size: 13.50 KB\r\nThis .NET loader is fileless and thus has no filename.\r\nThe PowerShell loader script (powershell_loader)\r\n1. extracts the .NET Loader from the registry\r\n2. decodes it\r\n3. dynamically loads \u0026 executes it (i.e., it is not written to disk).\r\nThe .NET Loader is encoded in hexadecimal and stored inside the registry. It is slightly obfuscated: character #\r\nhas to be replaced with 1000.\r\nThe .NET loader:\r\n1. extracts the DLL (stage 4) from the registry\r\n2. decodes it\r\nhttps://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/\r\nPage 12 of 15\n\n3. dynamically loads \u0026 executes it ( i.e., it is not written to disk).\r\nThe DLL is encoded in hexadecimal, but with an alternative character set. This is translated to regular\r\nhexadecimal via the following table:\r\nFig 22. “Test” function that decodes the DLL by using the replace\r\nThis Test function decodes the DLL and executes it in memory. Note that without the .NET loader, statistical\r\nanalysis could reveal the DLL as well. A blog post[2], written by our colleague Didier Stevens on how to decode a\r\npayload by performing statistical analysis can offer some insights on how this could be done.\r\nStage 4 – Cobalt Strike DLL\r\nMD5 DLL: 92a271eb76a0db06c94688940bc4442b\r\nSHA256 DLL: 63bf85c27e048cf7f243177531b9f4b1a3cb679a41a6cc8964d6d195d869093e\r\nThis is a typical Cobalt Strike beacon and has the following configuration (extracted with 1768.py)\r\nhttps://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/\r\nPage 13 of 15\n\nFig 23. 1768.py by DidierStevens used to detect and parse the Cobalt Strike beacon\r\nNow that Cobalt Strike is loaded as final part of the infection chain, the attacker has control over the infected\r\nmachine and can start his reconnaissance from this machine or make use of the post-exploitation functionality in\r\nCobalt Strike, e.g. download/upload files, log keystrokes, take screenshots, …\r\nConclusion\r\nThe analysis of the trojanized jQuery JavaScript confirms the initial analysis of the artifacts collected from the\r\ninfected machine and confirms that the trojanized jQuery contains malicious obfuscated code to download a\r\npayload from the Internet. This payload is designed to filelessly, and with boot-persistence, instantiate a Cobalt\r\nStrike beacon.\r\nAbout the authors\r\nDidier\r\nStevens\r\nDidier Stevens is a malware expert working for NVISO. Didier is a SANS\r\nInternet Storm Center senior handler and Microsoft MVP, and has developed\r\nnumerous popular tools to assist with malware analysis. You can find Didier\r\non Twitter and LinkedIn.\r\nSasja\r\nReynaert\r\nSasja Reynaert is a forensic analyst working for NVISO. Sasja is a GIAC\r\nCertified Incident Handler, Forensics Examiner \u0026 Analyst (GCIH, GCFE,\r\nGCFA). You can find Sasja on LinkedIn.\r\nYou can follow NVISO Labs on Twitter to stay up to date on all our future research and publications.\r\n[1]:https://code.jquery.com/jquery-3.6.0.js\r\n[2]:https://blog.didierstevens.com/2022/06/20/another-exercise-in-encoding-reversing/\r\nhttps://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/\r\nPage 14 of 15\n\nSource: https://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/\r\nhttps://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/\r\nPage 15 of 15",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://blog.nviso.eu/2022/07/20/analysis-of-a-trojanized-jquery-script-gootloader-unleashed/"
	],
	"report_names": [
		"analysis-of-a-trojanized-jquery-script-gootloader-unleashed"
	],
	"threat_actors": [
		{
			"id": "610a7295-3139-4f34-8cec-b3da40add480",
			"created_at": "2023-01-06T13:46:38.608142Z",
			"updated_at": "2026-04-10T02:00:03.03764Z",
			"deleted_at": null,
			"main_name": "Cobalt",
			"aliases": [
				"Cobalt Group",
				"Cobalt Gang",
				"GOLD KINGSWOOD",
				"COBALT SPIDER",
				"G0080",
				"Mule Libra"
			],
			"source_name": "MISPGALAXY:Cobalt",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775434809,
	"ts_updated_at": 1775791464,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/2e277475ae8d0c252ba8dc53d7c1e1506807ba7f.pdf",
		"text": "https://archive.orkl.eu/2e277475ae8d0c252ba8dc53d7c1e1506807ba7f.txt",
		"img": "https://archive.orkl.eu/2e277475ae8d0c252ba8dc53d7c1e1506807ba7f.jpg"
	}
}